diff --git a/.gitignore b/.gitignore index e43b0f988..10cc0ea8b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,10 @@ +.gradle +local.properties +.idea +build/ .DS_Store +*.iml +*.apk +*.aar +*.zip +google-services.json diff --git a/CCL/build.gradle b/CCL/build.gradle deleted file mode 100644 index d25fde4ed..000000000 --- a/CCL/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion 23 - buildToolsVersion rootProject.ext.tools - publishNonDefault true - - defaultConfig { - minSdkVersion 9 - targetSdkVersion 23 - versionCode 10 - versionName "1.0" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } -} - - -dependencies { - compile rootProject.ext.supportV4 - compile rootProject.ext.appCompat - compile rootProject.ext.mediaRouter - - compile rootProject.ext.playServicesBase - compile rootProject.ext.playServicesBasement - compile rootProject.ext.playServicesCast -} diff --git a/CCL/src/main/AndroidManifest.xml b/CCL/src/main/AndroidManifest.xml deleted file mode 100644 index d717cc38e..000000000 --- a/CCL/src/main/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/BaseCastManager.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/BaseCastManager.java deleted file mode 100644 index 788725c38..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/BaseCastManager.java +++ /dev/null @@ -1,1236 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGD; -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.gms.cast.ApplicationMetadata; -import com.google.android.gms.cast.Cast; -import com.google.android.gms.cast.Cast.ApplicationConnectionResult; -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.cast.CastMediaControlIntent; -import com.google.android.gms.cast.CastStatusCodes; -import com.google.android.gms.cast.LaunchOptions; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.api.GoogleApiClient; -import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; -import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; -import com.google.android.gms.common.api.ResultCallback; -import com.google.android.gms.common.api.Status; -import com.google.android.libraries.cast.companionlibrary.R; -import com.google.android.libraries.cast.companionlibrary.cast.callbacks.BaseCastConsumer; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.OnFailedListener; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.reconnection.ReconnectionService; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; -import com.google.android.libraries.cast.companionlibrary.utils.PreferenceAccessor; -import com.google.android.libraries.cast.companionlibrary.utils.Utils; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.media.RemoteControlClient; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; -import android.support.annotation.IntDef; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.app.MediaRouteActionProvider; -import android.support.v7.app.MediaRouteButton; -import android.support.v7.app.MediaRouteDialogFactory; -import android.support.v7.media.MediaRouteSelector; -import android.support.v7.media.MediaRouter; -import android.support.v7.media.MediaRouter.RouteInfo; -import android.view.Menu; -import android.view.MenuItem; - -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -/** - * An abstract class that manages connectivity to a cast device. Subclasses are expected to extend - * the functionality of this class based on their purpose. - */ -public abstract class BaseCastManager - implements ConnectionCallbacks, OnConnectionFailedListener, OnFailedListener { - - private static final String TAG = LogUtils.makeLogTag(BaseCastManager.class); - - public static final int RECONNECTION_STATUS_STARTED = 1; - public static final int RECONNECTION_STATUS_IN_PROGRESS = 2; - public static final int RECONNECTION_STATUS_FINALIZED = 3; - public static final int RECONNECTION_STATUS_INACTIVE = 4; - - public static final int FEATURE_DEBUGGING = 1; - public static final int FEATURE_LOCKSCREEN = 1 << 1; - public static final int FEATURE_NOTIFICATION = 1 << 2; - public static final int FEATURE_WIFI_RECONNECT = 1 << 3; - public static final int FEATURE_CAPTIONS_PREFERENCE = 1 << 4; - public static final int FEATURE_AUTO_RECONNECT = 1 << 5; - - public static final String PREFS_KEY_SESSION_ID = "session-id"; - public static final String PREFS_KEY_SSID = "ssid"; - public static final String PREFS_KEY_MEDIA_END = "media-end"; - public static final String PREFS_KEY_APPLICATION_ID = "application-id"; - public static final String PREFS_KEY_CAST_ACTIVITY_NAME = "cast-activity-name"; - public static final String PREFS_KEY_CAST_CUSTOM_DATA_NAMESPACE = "cast-custom-data-namespace"; - public static final String PREFS_KEY_ROUTE_ID = "route-id"; - - public static final int CLEAR_ALL = 0; - public static final int CLEAR_ROUTE = 1; - public static final int CLEAR_WIFI = 1 << 1; - public static final int CLEAR_SESSION = 1 << 2; - public static final int CLEAR_MEDIA_END = 1 << 3; - - public static final int DISCONNECT_REASON_OTHER = 0; - public static final int DISCONNECT_REASON_CONNECTIVITY = 1; - public static final int DISCONNECT_REASON_APP_NOT_RUNNING = 2; - public static final int DISCONNECT_REASON_EXPLICIT = 3; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({DISCONNECT_REASON_OTHER, DISCONNECT_REASON_CONNECTIVITY, - DISCONNECT_REASON_APP_NOT_RUNNING, DISCONNECT_REASON_EXPLICIT}) - public @interface DISCONNECT_REASON {} - - public static final int NO_APPLICATION_ERROR = 0; - - public static final int NO_STATUS_CODE = -1; - private static final int SESSION_RECOVERY_TIMEOUT_S = 10; - private static final int WHAT_UI_VISIBLE = 0; - private static final int WHAT_UI_HIDDEN = 1; - private static final int UI_VISIBILITY_DELAY_MS = 300; - - private static String sCclVersion; - - protected Context mContext; - protected MediaRouter mMediaRouter; - protected MediaRouteSelector mMediaRouteSelector; - protected CastMediaRouterCallback mMediaRouterCallback; - protected CastDevice mSelectedCastDevice; - protected String mDeviceName; - protected PreferenceAccessor mPreferenceAccessor; - - private final Set mBaseCastConsumers = new CopyOnWriteArraySet<>(); - private boolean mDestroyOnDisconnect = false; - protected String mApplicationId; - protected int mReconnectionStatus = RECONNECTION_STATUS_INACTIVE; - protected int mVisibilityCounter; - protected boolean mUiVisible; - protected GoogleApiClient mApiClient; - protected AsyncTask mReconnectionTask; - protected int mCapabilities; - protected boolean mConnectionSuspended; - protected String mSessionId; - private Handler mUiVisibilityHandler; - private RouteInfo mRouteInfo; - protected int mApplicationErrorCode = NO_APPLICATION_ERROR; - protected LaunchOptions mLaunchOptions; - - protected BaseCastManager() { - } - - /** - * Since application lifecycle callbacks are managed by subclasses, this abstract method needs - * to be implemented by each subclass independently. - * - * @param device The Cast receiver device returned from the MediaRouteProvider. Should not be - * {@code null}. - */ - protected abstract Cast.CastOptions.Builder getCastOptionBuilder(CastDevice device); - - /** - * Subclasses can decide how the Cast Controller Dialog should be built. If this returns - * null, the default dialog will be shown. - */ - protected abstract MediaRouteDialogFactory getMediaRouteDialogFactory(); - - /** - * Subclasses should implement this to react appropriately to the successful launch of their - * application. This is called when the application is successfully launched. - */ - protected abstract void onApplicationConnected(ApplicationMetadata applicationMetadata, - String applicationStatus, String sessionId, boolean wasLaunched); - - /** - * Called when the launch of application has failed. Subclasses need to handle this by doing - * appropriate clean up. - */ - protected abstract void onApplicationConnectionFailed(int statusCode); - - /** - * Called when the attempt to stop application has failed. - */ - protected abstract void onApplicationStopFailed(int statusCode); - - /** - * Called when a Cast device is unselected (i.e. disconnected). Most of the logic is handled by - * the {@link BaseCastManager} but each subclass may have some additional logic that can be - * done, e.g. detaching data or media channels that they may have set up. - */ - protected void onDeviceUnselected() { - // no-op implementation - } - - protected BaseCastManager(Context context, String applicationId) { - sCclVersion = context.getString(R.string.ccl_version); - LOGD(TAG, "BaseCastManager is instantiated\nVersion: " + sCclVersion - + "\nApplication ID: " + applicationId); - mContext = context.getApplicationContext(); - mPreferenceAccessor = new PreferenceAccessor(mContext); - mUiVisibilityHandler = new Handler(new UpdateUiVisibilityHandlerCallback()); - mApplicationId = applicationId; - mLaunchOptions = new LaunchOptions.Builder().setRelaunchIfRunning(false).build(); - mPreferenceAccessor.saveStringToPreference(PREFS_KEY_APPLICATION_ID, applicationId); - - mMediaRouter = MediaRouter.getInstance(mContext); - mMediaRouteSelector = new MediaRouteSelector.Builder().addControlCategory( - CastMediaControlIntent.categoryForCast(mApplicationId)).build(); - - mMediaRouterCallback = new CastMediaRouterCallback(this); - mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, - MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); - } - - /** - * Called when a {@link CastDevice} is extracted from the {@link RouteInfo}. This is where all - * the fun starts! - */ - public final void onDeviceSelected(CastDevice device) { - if (device == null) { - disconnectDevice(mDestroyOnDisconnect, true, false); - } else { - setDevice(device); - } - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onDeviceSelected(device); - } - } - - /** - * This is called from - * {@link com.google.android.libraries.cast.companionlibrary.cast.CastMediaRouterCallback} to - * signal the change in presence of cast devices on network. - * - * @param castDevicePresent Indicates where a cast device is present, true, or not, - * false. - */ - public final void onCastAvailabilityChanged(boolean castDevicePresent) { - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onCastAvailabilityChanged(castDevicePresent); - } - } - - /** - * Disconnects from the connected device. - * - * @param stopAppOnExit If {@code true}, the application running on the cast device will be - * stopped when disconnected. - * @param clearPersistedConnectionData If {@code true}, the persisted connection information - * will be cleared as part of this call. - * @param setDefaultRoute If {@code true}, after disconnection, the selected route will be set - * to the Default Route. - */ - public final void disconnectDevice(boolean stopAppOnExit, boolean clearPersistedConnectionData, - boolean setDefaultRoute) { - LOGD(TAG, "disconnectDevice(" + clearPersistedConnectionData + "," + setDefaultRoute + ")"); - if (mSelectedCastDevice == null) { - return; - } - mSelectedCastDevice = null; - mDeviceName = null; - - String message = "disconnectDevice() Disconnect Reason: "; - int reason; - if (mConnectionSuspended) { - message += "Connectivity lost"; - reason = DISCONNECT_REASON_CONNECTIVITY; - } else { - switch (mApplicationErrorCode) { - case CastStatusCodes.APPLICATION_NOT_RUNNING: - message += "App was taken over or not available anymore"; - reason = DISCONNECT_REASON_APP_NOT_RUNNING; - break; - case NO_APPLICATION_ERROR: - message += "Intentional disconnect"; - reason = DISCONNECT_REASON_EXPLICIT; - break; - default: - message += "Other"; - reason = DISCONNECT_REASON_OTHER; - } - } - LOGD(TAG, message); - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onDisconnectionReason(reason); - } - - LOGD(TAG, "mConnectionSuspended: " + mConnectionSuspended); - if (!mConnectionSuspended && clearPersistedConnectionData) { - clearPersistedConnectionInfo(CLEAR_ALL); - stopReconnectionService(); - } - try { - if ((isConnected() || isConnecting()) && stopAppOnExit) { - LOGD(TAG, "Calling stopApplication"); - stopApplication(); - } - } catch (NoConnectionException | TransientNetworkDisconnectionException e) { - LOGE(TAG, "Failed to stop the application after disconnecting route", e); - } - onDeviceUnselected(); - if (mApiClient != null) { - // the following check is currently required, without including a check for - // isConnecting() due to a bug in the current play services library and will be removed - // when that bug is addressed; calling disconnect() while we are in "connecting" state - // will throw an exception - if (mApiClient.isConnected()) { - LOGD(TAG, "Trying to disconnect"); - mApiClient.disconnect(); - } - if ((mMediaRouter != null) && setDefaultRoute) { - LOGD(TAG, "disconnectDevice(): Setting route to default"); - mMediaRouter.selectRoute(mMediaRouter.getDefaultRoute()); - } - mApiClient = null; - } - mSessionId = null; - onDisconnected(stopAppOnExit, clearPersistedConnectionData, setDefaultRoute); - } - - /** - * Returns {@code true} if and only if the selected cast device is on the local network. - * - * @throws CastException if no cast device has been selected. - */ - public final boolean isDeviceOnLocalNetwork() throws CastException { - if (mSelectedCastDevice == null) { - throw new CastException("No cast device has yet been selected"); - } - return mSelectedCastDevice.isOnLocalNetwork(); - } - - private void setDevice(CastDevice device) { - mSelectedCastDevice = device; - mDeviceName = mSelectedCastDevice.getFriendlyName(); - - if (mApiClient == null) { - LOGD(TAG, "acquiring a connection to Google Play services for " + mSelectedCastDevice); - Cast.CastOptions.Builder apiOptionsBuilder = getCastOptionBuilder(mSelectedCastDevice); - mApiClient = new GoogleApiClient.Builder(mContext) - .addApi(Cast.API, apiOptionsBuilder.build()) - .addConnectionCallbacks(this) - .addOnConnectionFailedListener(this) - .build(); - mApiClient.connect(); - } else if (!mApiClient.isConnected() && !mApiClient.isConnecting()) { - mApiClient.connect(); - } - } - - /** - * Called as soon as a non-default {@link RouteInfo} is discovered. The main usage for this is - * to provide a hint to clients that the cast button is going to become visible/available soon. - * A client, for example, can use this to show a quick help screen to educate the user on the - * cast concept and the usage of the cast button. - */ - public final void onCastDeviceDetected(RouteInfo info) { - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onCastDeviceDetected(info); - } - } - - /** - * Adds and wires up the Media Router cast button. It returns a reference to the Media Router - * menu item if the caller needs such reference. It is assumed that the enclosing - * {@link android.app.Activity} inherits (directly or indirectly) from - * {@link android.support.v7.app.AppCompatActivity}. - * - * @param menu Menu reference - * @param menuResourceId The resource id of the cast button in the xml menu descriptor file - */ - public final MenuItem addMediaRouterButton(Menu menu, int menuResourceId) { - MenuItem mediaRouteMenuItem = menu.findItem(menuResourceId); - MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) - MenuItemCompat.getActionProvider(mediaRouteMenuItem); - mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector); - if (getMediaRouteDialogFactory() != null) { - mediaRouteActionProvider.setDialogFactory(getMediaRouteDialogFactory()); - } - return mediaRouteMenuItem; - } - - /** - * Adds and wires up the {@link android.support.v7.app.MediaRouteButton} instance that is passed - * as an argument. This requires that - * - */ - public final void addMediaRouterButton(MediaRouteButton button) { - button.setRouteSelector(mMediaRouteSelector); - if (getMediaRouteDialogFactory() != null) { - button.setDialogFactory(getMediaRouteDialogFactory()); - } - } - - /** - * Calling this method signals the library that an activity page is made visible. In common - * cases, this should be called in the "onResume()" method of each activity of the application. - * The library keeps a counter and when at least one page of the application becomes visible, - * the {@link #onUiVisibilityChanged(boolean)} method is called. - */ - public final synchronized void incrementUiCounter() { - mVisibilityCounter++; - if (!mUiVisible) { - mUiVisible = true; - mUiVisibilityHandler.removeMessages(WHAT_UI_HIDDEN); - mUiVisibilityHandler.sendEmptyMessageDelayed(WHAT_UI_VISIBLE, UI_VISIBILITY_DELAY_MS); - } - if (mVisibilityCounter == 0) { - LOGD(TAG, "UI is no longer visible"); - } else { - LOGD(TAG, "UI is visible"); - } - } - - /** - * Calling this method signals the library that an activity page is made invisible. In common - * cases, this should be called in the "onPause()" method of each activity of the application. - * The library keeps a counter and when all pages of the application become invisible, the - * {@link #onUiVisibilityChanged(boolean)} method is called. - */ - public final synchronized void decrementUiCounter() { - if (--mVisibilityCounter == 0) { - LOGD(TAG, "UI is no longer visible"); - if (mUiVisible) { - mUiVisible = false; - mUiVisibilityHandler.removeMessages(WHAT_UI_VISIBLE); - mUiVisibilityHandler.sendEmptyMessageDelayed(WHAT_UI_HIDDEN, - UI_VISIBILITY_DELAY_MS); - } - } else { - LOGD(TAG, "UI is visible"); - } - } - - /** - * This is called when UI visibility of the client has changed - * - * @param visible The updated visibility status - */ - protected void onUiVisibilityChanged(boolean visible) { - if (visible) { - if (mMediaRouter != null && mMediaRouterCallback != null) { - LOGD(TAG, "onUiVisibilityChanged() addCallback called"); - startCastDiscovery(); - if (isFeatureEnabled(FEATURE_AUTO_RECONNECT)) { - reconnectSessionIfPossible(); - } - } - } else { - if (mMediaRouter != null) { - LOGD(TAG, "onUiVisibilityChanged() removeCallback called"); - stopCastDiscovery(); - } - } - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onUiVisibilityChanged(visible); - } - } - - /** - * Starts the discovery of cast devices by registering a {@link android.support.v7.media - * .MediaRouter.Callback} - */ - public final void startCastDiscovery() { - mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, - MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); - } - - /** - * Stops the process of cast discovery by removing the registered - * {@link android.support.v7.media.MediaRouter.Callback} - */ - public final void stopCastDiscovery() { - mMediaRouter.removeCallback(mMediaRouterCallback); - } - - /** - * A utility method to validate that the appropriate version of the Google Play Services is - * available on the device. If not, it will open a dialog to address the issue. The dialog - * displays a localized message about the error and upon user confirmation (by tapping on - * dialog) will direct them to the Play Store if Google Play services is out of date or missing, - * or to system settings if Google Play services is disabled on the device. - */ - public static boolean checkGooglePlayServices(final Activity activity) { - return Utils.checkGooglePlayServices(activity); - } - - /** - * can be used to find out if the application is connected to the service or not. - * - * @return true if connected, false otherwise. - */ - public final boolean isConnected() { - return (mApiClient != null) && mApiClient.isConnected(); - } - - /** - * Returns true only if application is connecting to the Cast service. - */ - public final boolean isConnecting() { - return (mApiClient != null) && mApiClient.isConnecting(); - } - - /** - * Disconnects from the cast device and stops the application on the cast device. - */ - public final void disconnect() { - if (isConnected() || isConnecting()) { - disconnectDevice(mDestroyOnDisconnect, true, true); - } - } - - /** - * Returns the assigned human-readable name of the device, or null if no device is - * connected. - */ - public final String getDeviceName() { - return mDeviceName; - } - - /** - * Sets a flag to control whether disconnection form a cast device should result in stopping - * the running application or not. If true is passed, then application will be - * stopped. Default behavior is not to stop the app. - */ - public final void setStopOnDisconnect(boolean stopOnExit) { - mDestroyOnDisconnect = stopOnExit; - } - - /** - * Returns the {@link MediaRouteSelector} object. - */ - public final MediaRouteSelector getMediaRouteSelector() { - return mMediaRouteSelector; - } - - /** - * Returns the {@link android.support.v7.media.MediaRouter.RouteInfo} corresponding to the - * selected route. - */ - public final RouteInfo getRouteInfo() { - return mRouteInfo; - } - - /** - * Sets the {@link android.support.v7.media.MediaRouter.RouteInfo} corresponding to the - * selected route. - */ - public final void setRouteInfo(RouteInfo routeInfo) { - mRouteInfo = routeInfo; - } - - /** - * Turns on configurable features in the library. All the supported features are turned off by - * default and clients, prior to using them, need to turn them on; it is best to do this - * immediately after initialization of the library. Bitwise OR combination of features should be - * passed in if multiple features are needed - *

- * Current set of configurable features are: - *

- */ - public final void enableFeatures(int capabilities) { - mCapabilities = capabilities; - onFeaturesUpdated(mCapabilities); - } - - /* - * Returns true if and only if the feature is turned on - */ - public final boolean isFeatureEnabled(int feature) { - return (feature & mCapabilities) == feature; - } - - /** - * Allow subclasses to be notified of changes to capabilities if they want to. - */ - protected void onFeaturesUpdated(int capabilities) { - } - - /** - * Sets the device (system) volume. - * - * @param volume Should be a value between 0 and 1, inclusive. - * @throws CastException - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public final void setDeviceVolume(double volume) throws CastException, - TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - try { - Cast.CastApi.setVolume(mApiClient, volume); - } catch (IOException e) { - throw new CastException("Failed to set volume", e); - } catch (IllegalStateException e) { - throw new NoConnectionException("setDeviceVolume()", e); - } - } - - /** - * Gets the remote's system volume, a number between 0 and 1, inclusive. - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public final double getDeviceVolume() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - try { - return Cast.CastApi.getVolume(mApiClient); - } catch (IllegalStateException e) { - throw new NoConnectionException("getDeviceVolume()", e); - } - } - - /** - * Increments (or decrements) the device volume by the given amount. - * - * @throws CastException - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public final void adjustDeviceVolume(double delta) throws CastException, - TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - double vol = getDeviceVolume(); - if (vol >= 0) { - setDeviceVolume(vol + delta); - } - } - - /** - * Returns true if remote device is muted. It internally determines if this should - * be done for stream or device volume. - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public final boolean isDeviceMute() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - try { - return Cast.CastApi.isMute(mApiClient); - } catch (IllegalStateException e) { - throw new NoConnectionException("isDeviceMute()", e); - } - } - - /** - * Mutes or un-mutes the device volume. - * - * @throws CastException - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public final void setDeviceMute(boolean mute) throws CastException, - TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - try { - Cast.CastApi.setMute(mApiClient, mute); - } catch (IOException e) { - throw new CastException("setDeviceMute", e); - } catch (IllegalStateException e) { - throw new NoConnectionException("setDeviceMute()", e); - } - } - - /** - * Returns the current reconnection status - */ - public final int getReconnectionStatus() { - return mReconnectionStatus; - } - - /** - * Sets the reconnection status - */ - public final void setReconnectionStatus(int status) { - if (mReconnectionStatus != status) { - mReconnectionStatus = status; - onReconnectionStatusChanged(mReconnectionStatus); - } - } - - private void onReconnectionStatusChanged(int status) { - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onReconnectionStatusChanged(status); - } - } - - /** - * Returns true if there is enough persisted information to attempt a session - * recovery. For this to return true, there needs to be a persisted session ID and - * a route ID from the last successful launch. - */ - protected final boolean canConsiderSessionRecovery() { - return canConsiderSessionRecovery(null); - } - - /** - * Returns true if there is enough persisted information to attempt a session - * recovery. For this to return true, there needs to be persisted session ID and - * route ID from the last successful launch. In addition, if ssidName is non-null, - * then an additional check is also performed to make sure the persisted wifi name is the same - * as the ssidName - */ - public final boolean canConsiderSessionRecovery(String ssidName) { - String sessionId = mPreferenceAccessor.getStringFromPreference(PREFS_KEY_SESSION_ID); - String routeId = mPreferenceAccessor.getStringFromPreference(PREFS_KEY_ROUTE_ID); - String ssid = mPreferenceAccessor.getStringFromPreference(PREFS_KEY_SSID); - if (sessionId == null || routeId == null) { - return false; - } - if (ssidName != null && (ssid == null || (!ssid.equals(ssidName)))) { - return false; - } - LOGD(TAG, "Found session info in the preferences, so proceed with an " - + "attempt to reconnect if possible"); - return true; - } - - private void reconnectSessionIfPossibleInternal(RouteInfo theRoute) { - if (isConnected()) { - return; - } - String sessionId = mPreferenceAccessor.getStringFromPreference(PREFS_KEY_SESSION_ID); - String routeId = mPreferenceAccessor.getStringFromPreference(PREFS_KEY_ROUTE_ID); - LOGD(TAG, "reconnectSessionIfPossible() Retrieved from preferences: " + "sessionId=" - + sessionId + ", routeId=" + routeId); - if (sessionId == null || routeId == null) { - return; - } - setReconnectionStatus(RECONNECTION_STATUS_IN_PROGRESS); - CastDevice device = CastDevice.getFromBundle(theRoute.getExtras()); - - if (device != null) { - LOGD(TAG, "trying to acquire Cast Client for " + device); - onDeviceSelected(device); - } - } - - /* - * Cancels the task responsible for recovery of prior sessions, is used internally. - */ - public final void cancelReconnectionTask() { - LOGD(TAG, "cancelling reconnection task"); - if (mReconnectionTask != null && !mReconnectionTask.isCancelled()) { - mReconnectionTask.cancel(true); - } - } - - /** - * This method tries to automatically re-establish re-establish connection to a session if - * - * Under these conditions, a best-effort attempt will be made to continue with the same - * session. This attempt will go on for {@code SESSION_RECOVERY_TIMEOUT} seconds. - */ - public final void reconnectSessionIfPossible() { - reconnectSessionIfPossible(SESSION_RECOVERY_TIMEOUT_S); - } - - /** - * This method tries to automatically re-establish connection to a session if - * - * Under these conditions, a best-effort attempt will be made to continue with the same - * session. This attempt will go on for timeoutInSeconds seconds. - */ - public final void reconnectSessionIfPossible(final int timeoutInSeconds) { - reconnectSessionIfPossible(timeoutInSeconds, null); - } - - /** - * This method tries to automatically re-establish connection to a session if - * - * Under these conditions, a best-effort attempt will be made to continue with the same - * session. - * This attempt will go on for timeoutInSeconds seconds. - * - * @param timeoutInSeconds the length of time, in seconds, to attempt reconnection before giving - * up - * @param ssidName The name of Wifi SSID - */ - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - public void reconnectSessionIfPossible(final int timeoutInSeconds, String ssidName) { - LOGD(TAG, String.format("reconnectSessionIfPossible(%d, %s)", timeoutInSeconds, ssidName)); - if (isConnected()) { - return; - } - String routeId = mPreferenceAccessor.getStringFromPreference(PREFS_KEY_ROUTE_ID); - if (canConsiderSessionRecovery(ssidName)) { - List routes = mMediaRouter.getRoutes(); - RouteInfo theRoute = null; - if (routes != null) { - for (RouteInfo route : routes) { - if (route.getId().equals(routeId)) { - theRoute = route; - break; - } - } - } - if (theRoute != null) { - // route has already been discovered, so lets just get the device - reconnectSessionIfPossibleInternal(theRoute); - } else { - // we set a flag so if the route is discovered within a short period, we let - // onRouteAdded callback of CastMediaRouterCallback take care of that - setReconnectionStatus(RECONNECTION_STATUS_STARTED); - } - - // cancel any prior reconnection task - if (mReconnectionTask != null && !mReconnectionTask.isCancelled()) { - mReconnectionTask.cancel(true); - } - - // we may need to reconnect to an existing session - mReconnectionTask = new AsyncTask() { - - @Override - protected Boolean doInBackground(Void... params) { - for (int i = 0; i < timeoutInSeconds; i++) { - LOGD(TAG, "Reconnection: Attempt " + (i + 1)); - if (isCancelled()) { - return true; - } - try { - if (isConnected()) { - cancel(true); - } - Thread.sleep(1000); - } catch (InterruptedException e) { - // ignore - } - } - return false; - } - - @Override - protected void onPostExecute(Boolean result) { - if (result == null || !result) { - LOGD(TAG, "Couldn't reconnect, dropping connection"); - setReconnectionStatus(RECONNECTION_STATUS_INACTIVE); - onDeviceSelected(null); - } - } - - }; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - mReconnectionTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } else { - mReconnectionTask.execute(); - } - } - } - - /** - * This is called by the library when a connection is re-established after a transient - * disconnect. Note: this is not called by SDK. - */ - public void onConnectivityRecovered() { - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onConnectivityRecovered(); - } - } - - /* - * (non-Javadoc) - * @see com.google.android.gms.GoogleApiClient.ConnectionCallbacks#onConnected - * (android.os.Bundle) - */ - @Override - public final void onConnected(Bundle hint) { - LOGD(TAG, "onConnected() reached with prior suspension: " + mConnectionSuspended); - if (mConnectionSuspended) { - mConnectionSuspended = false; - if (hint != null && hint.getBoolean(Cast.EXTRA_APP_NO_LONGER_RUNNING)) { - // the same app is not running any more - LOGD(TAG, "onConnected(): App no longer running, so disconnecting"); - disconnect(); - } else { - onConnectivityRecovered(); - } - return; - } - if (!isConnected()) { - if (mReconnectionStatus == RECONNECTION_STATUS_IN_PROGRESS) { - setReconnectionStatus(RECONNECTION_STATUS_INACTIVE); - } - return; - } - try { - if (isFeatureEnabled(FEATURE_WIFI_RECONNECT)) { - String ssid = Utils.getWifiSsid(mContext); - mPreferenceAccessor.saveStringToPreference(PREFS_KEY_SSID, ssid); - } - Cast.CastApi.requestStatus(mApiClient); - launchApp(); - - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onConnected(); - } - - } catch (IOException | IllegalStateException e) { - LOGE(TAG, "requestStatus()", e); - } - - } - - /* - * Note: this is not called by the SDK anymore but this library calls this in the appropriate - * time. - */ - protected void onDisconnected(boolean stopAppOnExit, boolean clearPersistedConnectionData, - boolean setDefaultRoute) { - LOGD(TAG, "onDisconnected() reached"); - mDeviceName = null; - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onDisconnected(); - } - } - - /* - * (non-Javadoc) - * @see com.google.android.gms.GoogleApiClient.OnConnectionFailedListener# - * onConnectionFailed(com.google.android.gms.common.ConnectionResult) - */ - @Override - public void onConnectionFailed(ConnectionResult result) { - LOGD(TAG, "onConnectionFailed() reached, error code: " + result.getErrorCode() - + ", reason: " + result.toString()); - disconnectDevice(mDestroyOnDisconnect, false /* clearPersistentConnectionData */, - false /* setDefaultRoute */); - mConnectionSuspended = false; - if (mMediaRouter != null) { - mMediaRouter.selectRoute(mMediaRouter.getDefaultRoute()); - } - - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onConnectionFailed(result); - } - - if (result != null) { - PendingIntent pendingIntent = result.getResolution(); - if (pendingIntent != null) { - try { - pendingIntent.send(); - } catch (PendingIntent.CanceledException e) { - LOGE(TAG, "Failed to show recovery from the recoverable error", e); - } - } - } - } - - @Override - public void onConnectionSuspended(int cause) { - mConnectionSuspended = true; - LOGD(TAG, "onConnectionSuspended() was called with cause: " + cause); - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onConnectionSuspended(cause); - } - } - - /** - * Sets the launch options. - * - * @param relaunchIfRunning Launches the app even if the same application is running on the - * receiver - * @param locale The {@link Locale} - */ - public void setLaunchOptions(boolean relaunchIfRunning, Locale locale) { - mLaunchOptions = new LaunchOptions.Builder().setLocale(locale) - .setRelaunchIfRunning(relaunchIfRunning).build(); - } - - /* - * Launches application. For this to succeed, a connection should be already established by the - * CastClient. - */ - private void launchApp() throws TransientNetworkDisconnectionException, NoConnectionException { - LOGD(TAG, "launchApp() is called"); - if (!isConnected()) { - if (mReconnectionStatus == RECONNECTION_STATUS_IN_PROGRESS) { - setReconnectionStatus(RECONNECTION_STATUS_INACTIVE); - return; - } - checkConnectivity(); - } - - if (mReconnectionStatus == RECONNECTION_STATUS_IN_PROGRESS) { - LOGD(TAG, "Attempting to join a previously interrupted session..."); - String sessionId = mPreferenceAccessor.getStringFromPreference(PREFS_KEY_SESSION_ID); - LOGD(TAG, "joinApplication() -> start"); - Cast.CastApi.joinApplication(mApiClient, mApplicationId, sessionId).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(ApplicationConnectionResult result) { - if (result.getStatus().isSuccess()) { - LOGD(TAG, "joinApplication() -> success"); - onApplicationConnected(result.getApplicationMetadata(), - result.getApplicationStatus(), result.getSessionId(), - result.getWasLaunched()); - } else { - LOGD(TAG, "joinApplication() -> failure"); - clearPersistedConnectionInfo(CLEAR_SESSION | CLEAR_MEDIA_END); - cancelReconnectionTask(); - onApplicationConnectionFailed(result.getStatus().getStatusCode()); - } - } - } - ); - } else { - LOGD(TAG, "Launching app"); - Cast.CastApi.launchApplication(mApiClient, mApplicationId, mLaunchOptions) - .setResultCallback( - new ResultCallback() { - - @Override - public void onResult(ApplicationConnectionResult result) { - if (result.getStatus().isSuccess()) { - LOGD(TAG, "launchApplication() -> success result"); - onApplicationConnected(result.getApplicationMetadata(), - result.getApplicationStatus(), - result.getSessionId(), - result.getWasLaunched()); - } else { - LOGD(TAG, "launchApplication() -> failure result"); - onApplicationConnectionFailed( - result.getStatus().getStatusCode()); - } - } - } - ); - } - } - - /** - * Stops the application on the receiver device. - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public final void stopApplication() - throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - Cast.CastApi.stopApplication(mApiClient, mSessionId).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(Status result) { - if (!result.isSuccess()) { - LOGD(TAG, "stopApplication -> onResult: stopping " - + "application failed"); - onApplicationStopFailed(result.getStatusCode()); - } else { - LOGD(TAG, "stopApplication -> onResult Stopped application " - + "successfully"); - } - } - }); - } - - /** - * Registers a {@link BaseCastConsumer} interface with this class. Registered listeners will be - * notified of changes to a variety of lifecycle callbacks that the interface provides. - * - * @see {@code BaseCastConsumerImpl} - */ - public final void addBaseCastConsumer(BaseCastConsumer listener) { - if (listener != null) { - if (mBaseCastConsumers.add(listener)) { - LOGD(TAG, "Successfully added the new BaseCastConsumer listener " + listener); - } - } - } - - /** - * Unregisters a {@link BaseCastConsumer}. - */ - public final void removeBaseCastConsumer(BaseCastConsumer listener) { - if (listener != null) { - if (mBaseCastConsumers.remove(listener)) { - LOGD(TAG, "Successfully removed the existing BaseCastConsumer listener " - + listener); - } - } - } - - /** - * A simple method that throws an exception if there is no connectivity to the cast device. - * - * @throws TransientNetworkDisconnectionException If framework is still trying to recover - * @throws NoConnectionException If no connectivity to the device exists - */ - public final void checkConnectivity() throws TransientNetworkDisconnectionException, - NoConnectionException { - if (!isConnected()) { - if (mConnectionSuspended) { - throw new TransientNetworkDisconnectionException(); - } else { - throw new NoConnectionException(); - } - } - } - - @Override - public void onFailed(int resourceId, int statusCode) { - LOGD(TAG, "onFailed() was called with statusCode: " + statusCode); - for (BaseCastConsumer consumer : mBaseCastConsumers) { - consumer.onFailed(resourceId, statusCode); - } - } - - /** - * Returns the version of this library. - */ - public static final String getCclVersion() { - return sCclVersion; - } - - public PreferenceAccessor getPreferenceAccessor() { - return mPreferenceAccessor; - } - - /** - * Clears the persisted connection information. Bitwise OR combination of the following options - * should be passed as the argument: - *
    - *
  • CLEAR_SESSION
  • - *
  • CLEAR_ROUTE
  • - *
  • CLEAR_WIFI
  • - *
  • CLEAR_MEDIA_END
  • - *
  • CLEAR_ALL
  • - *
- * Clients can form an or - */ - public final void clearPersistedConnectionInfo(int what) { - LOGD(TAG, "clearPersistedConnectionInfo(): Clearing persisted data for " + what); - if (isFlagSet(what, CLEAR_SESSION)) { - mPreferenceAccessor.saveStringToPreference(PREFS_KEY_SESSION_ID, null); - } - if (isFlagSet(what, CLEAR_ROUTE)) { - mPreferenceAccessor.saveStringToPreference(PREFS_KEY_ROUTE_ID, null); - } - if (isFlagSet(what, CLEAR_WIFI)) { - mPreferenceAccessor.saveStringToPreference(PREFS_KEY_SSID, null); - } - if (isFlagSet(what, CLEAR_MEDIA_END)) { - mPreferenceAccessor.saveLongToPreference(PREFS_KEY_MEDIA_END, null); - } - } - - private static boolean isFlagSet(int mask, int flag) { - return (mask == CLEAR_ALL) || ((mask & flag) == flag); - } - - protected void startReconnectionService(long mediaDurationLeft) { - if (!isFeatureEnabled(FEATURE_WIFI_RECONNECT)) { - return; - } - LOGD(TAG, "startReconnectionService() for media length lef = " + mediaDurationLeft); - long endTime = SystemClock.elapsedRealtime() + mediaDurationLeft; - mPreferenceAccessor.saveLongToPreference(PREFS_KEY_MEDIA_END, endTime); - Context applicationContext = mContext.getApplicationContext(); - Intent service = new Intent(applicationContext, ReconnectionService.class); - service.setPackage(applicationContext.getPackageName()); - applicationContext.startService(service); - } - - protected void stopReconnectionService() { - if (!isFeatureEnabled(FEATURE_WIFI_RECONNECT)) { - return; - } - LOGD(TAG, "stopReconnectionService()"); - Context applicationContext = mContext.getApplicationContext(); - Intent service = new Intent(applicationContext, ReconnectionService.class); - service.setPackage(applicationContext.getPackageName()); - applicationContext.stopService(service); - } - - /** - * A Handler.Callback to receive individual messages when UI goes hidden or becomes visible. - */ - private class UpdateUiVisibilityHandlerCallback implements Handler.Callback { - - @Override - public boolean handleMessage(Message msg) { - onUiVisibilityChanged(msg.what == WHAT_UI_VISIBLE); - return true; - } - } - - /** - * Returns {@code true} if and only if there is at least one route matching the - * {@link #getMediaRouteSelector()}. - */ - public boolean isAnyRouteAvailable() { - return mMediaRouterCallback.isRouteAvailable(); - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/CastMediaRouterCallback.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/CastMediaRouterCallback.java deleted file mode 100644 index e85270821..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/CastMediaRouterCallback.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGD; - -import com.google.android.gms.cast.CastDevice; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; - -import android.support.v7.media.MediaRouter; -import android.support.v7.media.MediaRouter.RouteInfo; - -/** - * Provides a handy implementation of {@link MediaRouter.Callback}. When a {@link RouteInfo} is - * selected by user from the list of available routes, this class will call the - * {@link BaseCastManager#setDevice(CastDevice))} of the listener that was passed to it in - * the constructor. In addition, as soon as a non-default route is discovered, the - * {@link BaseCastManager#onCastDeviceDetected(RouteInfo))} is called. - *

- * There is also some logic in this class to help with the process of previous session recovery. - */ -public class CastMediaRouterCallback extends MediaRouter.Callback { - private static final String TAG = LogUtils.makeLogTag(CastMediaRouterCallback.class); - private final BaseCastManager mCastManager; - private boolean mRouteAvailable = false; - - public CastMediaRouterCallback(BaseCastManager castManager) { - mCastManager = castManager; - } - - @Override - public void onRouteSelected(MediaRouter router, RouteInfo info) { - LOGD(TAG, "onRouteSelected: info=" + info); - if (mCastManager.getReconnectionStatus() - == BaseCastManager.RECONNECTION_STATUS_FINALIZED) { - mCastManager.setReconnectionStatus(BaseCastManager.RECONNECTION_STATUS_INACTIVE); - mCastManager.cancelReconnectionTask(); - return; - } - mCastManager.getPreferenceAccessor().saveStringToPreference( - BaseCastManager.PREFS_KEY_ROUTE_ID, info.getId()); - CastDevice device = CastDevice.getFromBundle(info.getExtras()); - mCastManager.onDeviceSelected(device); - LOGD(TAG, "onRouteSelected: mSelectedDevice=" + device.getFriendlyName()); - } - - @Override - public void onRouteUnselected(MediaRouter router, RouteInfo route) { - LOGD(TAG, "onRouteUnselected: route=" + route); - mCastManager.onDeviceSelected(null); - } - - @Override - public void onRouteAdded(MediaRouter router, RouteInfo route) { - if (!router.getDefaultRoute().equals(route)) { - notifyRouteAvailabilityChangedIfNeeded(router); - mCastManager.onCastDeviceDetected(route); - } - if (mCastManager.getReconnectionStatus() - == BaseCastManager.RECONNECTION_STATUS_STARTED) { - String routeId = mCastManager.getPreferenceAccessor().getStringFromPreference( - BaseCastManager.PREFS_KEY_ROUTE_ID); - if (route.getId().equals(routeId)) { - // we found the route, so lets go with that - LOGD(TAG, "onRouteAdded: Attempting to recover a session with info=" + route); - mCastManager.setReconnectionStatus(BaseCastManager.RECONNECTION_STATUS_IN_PROGRESS); - - CastDevice device = CastDevice.getFromBundle(route.getExtras()); - LOGD(TAG, "onRouteAdded: Attempting to recover a session with device: " - + device.getFriendlyName()); - mCastManager.onDeviceSelected(device); - } - } - } - - @Override - public void onRouteRemoved(MediaRouter router, RouteInfo route) { - notifyRouteAvailabilityChangedIfNeeded(router); - } - - @Override - public void onRouteChanged(MediaRouter router, RouteInfo route) { - notifyRouteAvailabilityChangedIfNeeded(router); - } - - private void notifyRouteAvailabilityChangedIfNeeded(MediaRouter router) { - boolean routeAvailable = isRouteAvailable(router); - if (routeAvailable != mRouteAvailable) { - // availability of routes have changed - mRouteAvailable = routeAvailable; - mCastManager.onCastAvailabilityChanged(mRouteAvailable); - } - } - - private boolean isRouteAvailable(MediaRouter router) { - return router.isRouteAvailable(mCastManager.getMediaRouteSelector(), - MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE - | MediaRouter.AVAILABILITY_FLAG_REQUIRE_MATCH); - } - - /** - * Returns {@code true} if and only if there is at least one route matching the - * {@link BaseCastManager#getMediaRouteSelector()}. - */ - public boolean isRouteAvailable() { - return mRouteAvailable; - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/DataCastManager.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/DataCastManager.java deleted file mode 100644 index d38cac394..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/DataCastManager.java +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGD; -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.gms.cast.ApplicationMetadata; -import com.google.android.gms.cast.Cast; -import com.google.android.gms.cast.Cast.CastOptions.Builder; -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.cast.CastStatusCodes; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesUtil; -import com.google.android.gms.common.api.ResultCallback; -import com.google.android.gms.common.api.Status; -import com.google.android.libraries.cast.companionlibrary.cast.callbacks.DataCastConsumer; -import com.google.android.libraries.cast.companionlibrary.cast.callbacks.DataCastConsumerImpl; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; - -import android.content.Context; -import android.support.v7.app.MediaRouteDialogFactory; -import android.support.v7.media.MediaRouter.RouteInfo; -import android.text.TextUtils; - -import java.io.IOException; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -/** - * A concrete subclass of {@link BaseCastManager} that is suitable for data-centric applications - * that use multiple namespaces. - *

- * This is a singleton that needs to be "initialized" (by calling initialize()) prior - * to usage. Subsequent to initialization, an easier way to get access to the singleton class is to - * call a variant of getInstance(). After initialization, callers can enable any - * available feature (all features are off by default). To do so, call enableFeature() - * and pass an OR-ed expression built from one ore more of the following constants: - *

- *

    - *
  • FEATURE_DEBUGGING: to enable Google Play Services level logging
  • - *
- * Beyond managing the connectivity to a cast device, this class provides easy-to-use methods to - * send and receive messages using one or more namespaces. These namespaces can be configured during - * the initialization as part of the call to initialize() or can be added later on. - * Clients can subclass this class to extend the features and functionality beyond what this class - * provides. This class manages various states of the remote cast device. Client applications, - * however, can complement the default behavior of this class by hooking into various callbacks that - * it provides (see - * {@link com.google.android.libraries.cast.companionlibrary.cast.callbacks.DataCastConsumer}). - * Since the number of these callbacks is usually much larger than what a single application might - * be interested in, there is a no-op implementation of this interface (see - * {@link DataCastConsumerImpl}) that applications can subclass to override only those methods that - * they are interested in. Since this library depends on the cast functionalities provided by the - * Google Play services, the library checks to ensure that the right version of that service is - * installed. It also provides a simple static method {@code checkGooglePlayServices()} that clients - * can call at an early stage of their applications to provide a dialog for users if they need to - * update/activate their Google Play Services library. To learn more about this library, please read - * the documentation that is distributed as part of this library. - */ -public class DataCastManager extends BaseCastManager implements Cast.MessageReceivedCallback { - - private static final String TAG = LogUtils.makeLogTag(DataCastManager.class); - private static DataCastManager sInstance; - private final Set mNamespaceList = new HashSet<>(); - private final Set mDataConsumers = new CopyOnWriteArraySet<>(); - - private DataCastManager() { - } - - /** - * Initializes the DataCastManager for clients. Before clients can use DataCastManager, they - * need to initialize it by calling this static method. Then clients can obtain an instance of - * this singleton class by calling {@link DataCastManager#getInstance()}. Failing to initialize - * this class before requesting an instance will result in a {@link CastException} exception. - * - * @param context - * @param applicationId the application ID for your application - * @param namespaces Namespaces to be set up for this class. - */ - public static synchronized DataCastManager initialize(Context context, - String applicationId, String... namespaces) { - if (sInstance == null) { - LOGD(TAG, "New instance of DataCastManager is created"); - if (ConnectionResult.SUCCESS != GooglePlayServicesUtil - .isGooglePlayServicesAvailable(context)) { - String msg = "Couldn't find the appropriate version of Google Play Services"; - LOGE(TAG, msg); - throw new RuntimeException(msg); - } - sInstance = new DataCastManager(context, applicationId, namespaces); - } - return sInstance; - } - - protected DataCastManager(Context context, String applicationId, String... namespaces) { - super(context, applicationId); - if (namespaces != null) { - for (String namespace : namespaces) { - if (!TextUtils.isEmpty(namespace)) { - mNamespaceList.add(namespace); - } else { - LOGD(TAG, "A null or empty namespace was ignored."); - } - } - } - } - - /** - * Returns a (singleton) instance of this class. Clients should call this method in order to - * get a hold of this singleton instance. If it is not initialized yet, a - * {@link CastException} will be thrown. - */ - public static DataCastManager getInstance() { - if (sInstance == null) { - String msg = "No DataCastManager instance was found, did you forget to initialize it?"; - LOGE(TAG, msg); - throw new IllegalStateException(msg); - } - return sInstance; - } - - /** - * Adds a channel with the given {@code namespace} and registers {@link DataCastManager} as - * the callback receiver. If the namespace is already registered, this returns - * false, otherwise returns true. - * - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from a - * possibly transient loss of network - */ - public boolean addNamespace(String namespace) throws - TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (TextUtils.isEmpty(namespace)) { - throw new IllegalArgumentException("namespace cannot be empty"); - } - if (mNamespaceList.contains(namespace)) { - LOGD(TAG, "Ignoring to add a namespace that is already added."); - return false; - } - try { - Cast.CastApi.setMessageReceivedCallbacks(mApiClient, namespace, this); - mNamespaceList.add(namespace); - return true; - } catch (IOException | IllegalStateException e) { - LOGE(TAG, String.format("addNamespace(%s)", namespace), e); - } - return false; - } - - /** - * Unregisters a namespace. If namespace is not already registered, it returns - * false, otherwise a successful removal returns true. - * - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from a - * possibly transient loss of network - */ - public boolean removeNamespace(String namespace) throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - if (TextUtils.isEmpty(namespace)) { - throw new IllegalArgumentException("namespace cannot be empty"); - } - if (!mNamespaceList.contains(namespace)) { - LOGD(TAG, "Ignoring to remove a namespace that is not registered."); - return false; - } - try { - Cast.CastApi.removeMessageReceivedCallbacks(mApiClient, namespace); - mNamespaceList.remove(namespace); - return true; - } catch (IOException | IllegalStateException e) { - LOGE(TAG, String.format("removeNamespace(%s)", namespace), e); - } - return false; - - } - - /** - * Sends the message on the data channel for the namespace. If fails, - * it will call onMessageSendFailed - * - * @throws IllegalArgumentException If the the message is null, empty, or too long; or if the - * namespace is null or too long. - * @throws IllegalStateException If there is no active service connection. - * @throws IOException - */ - public void sendDataMessage(String message, String namespace) - throws IllegalArgumentException, IllegalStateException, IOException { - checkConnectivity(); - if (TextUtils.isEmpty(namespace)) { - throw new IllegalArgumentException("namespace cannot be empty"); - } - Cast.CastApi.sendMessage(mApiClient, namespace, message). - setResultCallback(new ResultCallback() { - - @Override - public void onResult(Status result) { - if (!result.isSuccess()) { - DataCastManager.this.onMessageSendFailed(result); - } - } - }); - } - - @Override - protected void onDeviceUnselected() { - detachDataChannels(); - } - - @Override - protected Builder getCastOptionBuilder(CastDevice device) { - - Builder builder = Cast.CastOptions.builder( - mSelectedCastDevice, new CastListener()); - if (isFeatureEnabled(FEATURE_DEBUGGING)) { - builder.setVerboseLoggingEnabled(true); - } - return builder; - } - - class CastListener extends Cast.Listener { - - /* - * (non-Javadoc) - * @see com.google.android.gms.cast.Cast.Listener#onApplicationDisconnected (int) - */ - @Override - public void onApplicationDisconnected(int statusCode) { - DataCastManager.this.onApplicationDisconnected(statusCode); - } - - /* - * (non-Javadoc) - * @see com.google.android.gms.cast.Cast.Listener#onApplicationStatusChanged () - */ - @Override - public void onApplicationStatusChanged() { - DataCastManager.this.onApplicationStatusChanged(); - } - } - - @Override - protected MediaRouteDialogFactory getMediaRouteDialogFactory() { - return null; - } - - @Override - public void onApplicationConnected(ApplicationMetadata appMetadata, String applicationStatus, - String sessionId, boolean wasLaunched) { - LOGD(TAG, "onApplicationConnected() reached with sessionId: " + sessionId); - - // saving session for future retrieval; we only save the last session info - mPreferenceAccessor.saveStringToPreference(PREFS_KEY_SESSION_ID, sessionId); - if (mReconnectionStatus == RECONNECTION_STATUS_IN_PROGRESS) { - // we have tried to reconnect and successfully launched the app, so - // it is time to select the route and make the cast icon happy :-) - List routes = mMediaRouter.getRoutes(); - if (routes != null) { - String routeId = mPreferenceAccessor.getStringFromPreference(PREFS_KEY_ROUTE_ID); - boolean found = false; - for (RouteInfo routeInfo : routes) { - if (routeId.equals(routeInfo.getId())) { - // found the right route - LOGD(TAG, "Found the correct route during reconnection attempt"); - found = true; - mReconnectionStatus = RECONNECTION_STATUS_FINALIZED; - mMediaRouter.selectRoute(routeInfo); - break; - } - } - if (!found) { - // we were hoping to have the route that we wanted, but we - // didn't so we deselect the device - onDeviceSelected(null); - mReconnectionStatus = RECONNECTION_STATUS_INACTIVE; - return; - } - } - } - // registering namespaces, if any - try { - attachDataChannels(); - mSessionId = sessionId; - for (DataCastConsumer consumer : mDataConsumers) { - consumer.onApplicationConnected(appMetadata, applicationStatus, sessionId, - wasLaunched); - } - } catch (IllegalStateException | IOException e) { - LOGE(TAG, "Failed to attach namespaces", e); - } - - } - - /* - * Adds namespaces for data channel(s) - * - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from a - * possibly transient loss of network - * @throws IOException If an I/O error occurs while performing the request. - * @throws IllegalStateException Thrown when the controller is not connected to a CastDevice. - * @throws IllegalArgumentException If namespace is null. - */ - private void attachDataChannels() throws IllegalStateException, IOException { - checkConnectivity(); - for (String namespace : mNamespaceList) { - Cast.CastApi.setMessageReceivedCallbacks(mApiClient, namespace, this); - } - } - - /* - * Remove namespaces - * - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from a - * possibly transient loss of network - */ - private void detachDataChannels() { - if (mApiClient == null) { - return; - } - for (String namespace : mNamespaceList) { - try { - Cast.CastApi.removeMessageReceivedCallbacks(mApiClient, namespace); - } catch (IOException | IllegalArgumentException e) { - LOGE(TAG, "detachDataChannels() Failed to remove namespace: " + namespace, e); - } - } - } - - @Override - public void onApplicationConnectionFailed(int errorCode) { - if (mReconnectionStatus == RECONNECTION_STATUS_IN_PROGRESS) { - if (errorCode == CastStatusCodes.APPLICATION_NOT_RUNNING) { - // while trying to re-establish session, we found out that the app is not running - // so we need to disconnect - mReconnectionStatus = RECONNECTION_STATUS_INACTIVE; - onDeviceSelected(null); - } - } else { - for (DataCastConsumer consumer : mDataConsumers) { - consumer.onApplicationConnectionFailed(errorCode); - } - onDeviceSelected(null); - if (mMediaRouter != null) { - LOGD(TAG, "onApplicationConnectionFailed(): Setting route to default"); - mMediaRouter.selectRoute(mMediaRouter.getDefaultRoute()); - } - } - } - - public void onApplicationDisconnected(int errorCode) { - for (DataCastConsumer consumer : mDataConsumers) { - consumer.onApplicationDisconnected(errorCode); - } - if (mMediaRouter != null) { - mMediaRouter.selectRoute(mMediaRouter.getDefaultRoute()); - } - onDeviceSelected(null); - - } - - public void onApplicationStatusChanged() { - String appStatus; - if (!isConnected()) { - return; - } - try { - appStatus = Cast.CastApi.getApplicationStatus(mApiClient); - LOGD(TAG, "onApplicationStatusChanged() reached: " + appStatus); - for (DataCastConsumer consumer : mDataConsumers) { - consumer.onApplicationStatusChanged(appStatus); - } - } catch (IllegalStateException e) { - LOGE(TAG, "onApplicationStatusChanged(): Failed", e); - } - - } - - @Override - public void onApplicationStopFailed(int errorCode) { - for (DataCastConsumer consumer : mDataConsumers) { - consumer.onApplicationStopFailed(errorCode); - } - } - - @Override - public void onConnectivityRecovered() { - try { - attachDataChannels(); - } catch (IOException | IllegalStateException e) { - LOGE(TAG, "onConnectivityRecovered(): Failed to reattach data channels", e); - } - super.onConnectivityRecovered(); - } - - @Override - public void onMessageReceived(CastDevice castDevice, String namespace, String message) { - for (DataCastConsumer consumer : mDataConsumers) { - consumer.onMessageReceived(castDevice, namespace, message); - } - } - - public void onMessageSendFailed(Status result) { - for (DataCastConsumer consumer : mDataConsumers) { - consumer.onMessageSendFailed(result); - } - } - - /** - * Registers an - * {@link com.google.android.libraries.cast.companionlibrary.cast.callbacks.DataCastConsumer} - * interface with this class. Registered listeners will be notified of changes to a variety of - * lifecycle and status changes through the callbacks that the interface provides. - */ - public void addDataCastConsumer(DataCastConsumer listener) { - if (listener != null) { - addBaseCastConsumer(listener); - boolean result; - result = mDataConsumers.add(listener); - if (result) { - LOGD(TAG, "Successfully added the new DataCastConsumer listener " + listener); - } else { - LOGD(TAG, "Adding Listener " + listener + " was already registered, " - + "skipping this step"); - } - } - } - - /** - * Unregisters an {@link com.google.android.libraries.cast.companionlibrary.cast.callbacks.DataCastConsumer}. - */ - public void removeDataCastConsumer(DataCastConsumer listener) { - if (listener != null) { - removeBaseCastConsumer(listener); - mDataConsumers.remove(listener); - } - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/MediaQueue.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/MediaQueue.java deleted file mode 100644 index 6b376f97b..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/MediaQueue.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast; - -import com.google.android.gms.cast.MediaQueueItem; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * A simple class to model a queue for bookkeeping purposes. - */ -public class MediaQueue { - - private List mQueueItems = new CopyOnWriteArrayList<>(); - public static final int INVALID_POSITION = -1; - private MediaQueueItem mCurrentItem; - private boolean mShuffle; - private int mRepeatMode; - - public MediaQueue() {} - - public MediaQueue(List queueItems, - MediaQueueItem currentItem, boolean shuffle, int repeatMode) { - mQueueItems = queueItems; - mCurrentItem = currentItem; - mShuffle = shuffle; - mRepeatMode = repeatMode; - } - - public final List getQueueItems() { - return mQueueItems; - } - - public final void setQueueItems(List queue) { - if (queue == null) { - mQueueItems = null; - } else { - mQueueItems = new CopyOnWriteArrayList<>(queue); - } - } - - public final MediaQueueItem getCurrentItem() { - return mCurrentItem; - } - - public final void setCurrentItem(MediaQueueItem currentItem) { - mCurrentItem = currentItem; - } - - public final boolean isShuffle() { - return mShuffle; - } - - public final void setShuffle(boolean shuffle) { - mShuffle = shuffle; - } - - public final int getRepeatMode() { - return mRepeatMode; - } - - public final void setRepeatMode(int repeatMode) { - mRepeatMode = repeatMode; - } - - /** - * Returns the size of queue, or 0 if it is {@code null} - */ - public final int getCount() { - return mQueueItems == null || mQueueItems.isEmpty() ? 0 : mQueueItems.size(); - } - - /** - * Returns {@code true} if and only if the queue is empty or {@code null} - */ - public final boolean isEmpty() { - return mQueueItems == null || mQueueItems.isEmpty(); - } - - /** - * Returns the position of the current item in the queue. If the queue is {@code null}, it - * will return {@link #INVALID_POSITION}. If the queue is empty, it returns 0. - */ - public final int getCurrentItemPosition() { - if (mQueueItems == null) { - return INVALID_POSITION; - } - - if (mQueueItems.isEmpty()) { - return 0; - } - - return mQueueItems.indexOf(mCurrentItem); - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/VideoCastManager.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/VideoCastManager.java deleted file mode 100644 index 50ec932f7..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/VideoCastManager.java +++ /dev/null @@ -1,2977 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGD; -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.gms.cast.ApplicationMetadata; -import com.google.android.gms.cast.Cast; -import com.google.android.gms.cast.Cast.CastOptions.Builder; -import com.google.android.gms.cast.Cast.MessageReceivedCallback; -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.cast.CastStatusCodes; -import com.google.android.gms.cast.MediaInfo; -import com.google.android.gms.cast.MediaMetadata; -import com.google.android.gms.cast.MediaQueueItem; -import com.google.android.gms.cast.MediaStatus; -import com.google.android.gms.cast.MediaTrack; -import com.google.android.gms.cast.RemoteMediaPlayer; -import com.google.android.gms.cast.RemoteMediaPlayer.MediaChannelResult; -import com.google.android.gms.cast.TextTrackStyle; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesUtil; -import com.google.android.gms.common.api.ResultCallback; -import com.google.android.gms.common.api.Status; -import com.google.android.gms.common.images.WebImage; -import com.google.android.libraries.cast.companionlibrary.R; -import com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumer; -import com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumerImpl; -import com.google.android.libraries.cast.companionlibrary.cast.dialog.video.VideoMediaRouteDialogFactory; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.OnFailedListener; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.player.MediaAuthService; -import com.google.android.libraries.cast.companionlibrary.cast.player.VideoCastController; -import com.google.android.libraries.cast.companionlibrary.cast.player.VideoCastControllerActivity; -import com.google.android.libraries.cast.companionlibrary.cast.tracks.OnTracksSelectedListener; -import com.google.android.libraries.cast.companionlibrary.cast.tracks.TracksPreferenceManager; -import com.google.android.libraries.cast.companionlibrary.notification.VideoCastNotificationService; -import com.google.android.libraries.cast.companionlibrary.remotecontrol.VideoIntentReceiver; -import com.google.android.libraries.cast.companionlibrary.utils.FetchBitmapTask; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; -import com.google.android.libraries.cast.companionlibrary.utils.Utils; -import com.google.android.libraries.cast.companionlibrary.widgets.IMiniController; -import com.google.android.libraries.cast.companionlibrary.widgets.MiniController; -import com.google.android.libraries.cast.companionlibrary.widgets.MiniController.OnMiniControllerChangedListener; - -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources.NotFoundException; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.AudioManager; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.preference.PreferenceScreen; -import android.support.v4.media.MediaMetadataCompat; -import android.support.v4.media.session.MediaSessionCompat; -import android.support.v4.media.session.PlaybackStateCompat; -import android.support.v7.app.MediaRouteDialogFactory; -import android.support.v7.media.MediaRouter.RouteInfo; -import android.text.TextUtils; -import android.view.KeyEvent; -import android.view.View; -import android.view.accessibility.CaptioningManager; - -import org.json.JSONObject; - -import java.io.IOException; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.TimeUnit; - -/** - * An abstract subclass of {@link BaseCastManager} that is suitable for casting video contents (it - * also provides a single custom data channel/namespace if an out-of-band communication is - * needed). - *

- * Clients need to initialize this class by calling - * {@link #initialize(android.content.Context, String, Class, String)} and implement - * the abstracts methods defined here. To access the (singleton) instance of this class, clients - * need to call {@link #getInstance()}. After acquiring an instance, callers can enable a - * number of features (all features are turned off by default). To do so, call - * {@link #enableFeatures(int)} and pass an OR-ed expression built from one or more of the - * following constants: - *

- *

    - *
  • FEATURE_DEBUGGING: to enable Google Play Services level logging
  • - *
  • FEATURE_NOTIFICATION: to enable system notifications
  • - *
  • FEATURE_LOCKSCREEN: to enable lock-screen controls on supported versions
  • - *
  • FEATURE_WIFI_RECONNECT: to enable reconnection logic
  • - *
  • FEATURE_CAPTIONS_PREFERENCE: to enable Closed Caption Preference handling logic
  • - *
- * Callers can add {@link MiniController} components to their application pages by adding the - * corresponding widget to their layout xml and then calling addMiniController(). This - * class manages various states of the remote cast device. Client applications, however, can - * complement the default behavior of this class by hooking into various callbacks that it provides - * (see - * {@link com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumer}). - * Since the number of these callbacks is usually much larger than what a single application might - * be interested in, there is a no-op implementation of this interface (see - * {@link VideoCastConsumerImpl}) that applications can subclass to override only those methods that - * they are interested in. Since this library depends on the cast functionalities provided by the - * Google Play services, the library checks to ensure that the right version of that service is - * installed. It also provides a simple static method {@code checkGooglePlayServices()} that clients - * can call at an early stage of their applications to provide a dialog for users if they need to - * update/activate their Google Play Services library. To learn more about this library, please read - * the documentation that is distributed as part of this library. - */ -public class VideoCastManager extends BaseCastManager - implements OnMiniControllerChangedListener, OnFailedListener { - - private static final String TAG = LogUtils.makeLogTag(VideoCastManager.class); - - public static final String EXTRA_HAS_AUTH = "hasAuth"; - public static final String EXTRA_MEDIA = "media"; - public static final String EXTRA_START_POINT = "startPoint"; - public static final String EXTRA_SHOULD_START = "shouldStart"; - public static final String EXTRA_CUSTOM_DATA = "customData"; - public static final double DEFAULT_VOLUME_STEP = 0.05; - private static final long PROGRESS_UPDATE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(1); - private double mVolumeStep = DEFAULT_VOLUME_STEP; - public static final long DEFAULT_LIVE_STREAM_DURATION_MS = TimeUnit.HOURS.toMillis(2); // 2hrs - public static final String PREFS_KEY_START_ACTIVITY = "ccl-start-cast-activity"; - public static final String PREFS_KEY_NEXT_PREV_POLICY = "ccl-next-prev-policy"; - public static final String PREFS_KEY_IMMERSIVE_MODE = "ccl-cast-contoller-immersive"; - private TracksPreferenceManager mTrackManager; - private ComponentName mMediaEventReceiver; - private MediaQueue mMediaQueue; - private MediaStatus mMediaStatus; - private Timer mProgressTimer; - private UpdateProgressTask mProgressTask; - private FetchBitmapTask mLockScreenFetchTask; - private FetchBitmapTask mMediaSessionIconFetchTask; - - /** - * Volume can be controlled at two different layers, one is at the "stream" level and one at - * the "device" level. VolumeType encapsulates these two types. - * - * @see {@link #setVolumeType} - */ - public static enum VolumeType { - STREAM, - DEVICE - } - - private static VideoCastManager sInstance; - private Class mTargetActivity; - private final Set mMiniControllers = Collections - .synchronizedSet(new HashSet()); - private AudioManager mAudioManager; - private RemoteMediaPlayer mRemoteMediaPlayer; - private MediaSessionCompat mMediaSessionCompat; - private VolumeType mVolumeType = VolumeType.DEVICE; - private int mState = MediaStatus.PLAYER_STATE_IDLE; - private int mIdleReason; - private String mDataNamespace; - private Cast.MessageReceivedCallback mDataChannel; - private final Set mVideoConsumers = new CopyOnWriteArraySet<>(); - private final Set mTracksSelectedListeners = - new CopyOnWriteArraySet<>(); - private MediaAuthService mAuthService; - private long mLiveStreamDuration = DEFAULT_LIVE_STREAM_DURATION_MS; - private MediaQueueItem mPreLoadingItem; - - public static final int QUEUE_OPERATION_LOAD = 1; - public static final int QUEUE_OPERATION_INSERT_ITEMS = 2; - public static final int QUEUE_OPERATION_UPDATE_ITEMS = 3; - public static final int QUEUE_OPERATION_JUMP = 4; - public static final int QUEUE_OPERATION_REMOVE_ITEM = 5; - public static final int QUEUE_OPERATION_REMOVE_ITEMS = 6; - public static final int QUEUE_OPERATION_REORDER = 7; - public static final int QUEUE_OPERATION_MOVE = 8; - public static final int QUEUE_OPERATION_APPEND = 9; - public static final int QUEUE_OPERATION_NEXT = 10; - public static final int QUEUE_OPERATION_PREV = 11; - public static final int QUEUE_OPERATION_SET_REPEAT = 12; - - /** - * Returns the namespace for an additional data namespace that this library can manage for an - * application to have an out-of-band communication channel with the receiver. Note that this - * only prepares the sender and your own receiver needs to be able to receive and manage the - * channel as well. The default implementation is not to set up any additional channel. - * - * @return The namespace that the library can manage for the application. If {@code null}, no - * namespace will be set up. - */ - protected String getDataNamespace() { - return null; - } - - private VideoCastManager() { - } - - protected VideoCastManager(Context context, String applicationId, Class targetActivity, - String dataNamespace) { - super(context, applicationId); - LOGD(TAG, "VideoCastManager is instantiated"); - mDataNamespace = dataNamespace; - if (targetActivity == null) { - targetActivity = VideoCastControllerActivity.class; - } - mTargetActivity = targetActivity; - mPreferenceAccessor.saveStringToPreference(PREFS_KEY_CAST_ACTIVITY_NAME, - mTargetActivity.getName()); - if (!TextUtils.isEmpty(mDataNamespace)) { - mPreferenceAccessor.saveStringToPreference(PREFS_KEY_CAST_CUSTOM_DATA_NAMESPACE, - dataNamespace); - } - - mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - } - - public static synchronized VideoCastManager initialize(Context context, - String applicationId, Class targetActivity, String dataNamespace) { - if (sInstance == null) { - LOGD(TAG, "New instance of VideoCastManager is created"); - if (ConnectionResult.SUCCESS != GooglePlayServicesUtil - .isGooglePlayServicesAvailable(context)) { - String msg = "Couldn't find the appropriate version of Google Play Services"; - LOGE(TAG, msg); - } - sInstance = new VideoCastManager(context, applicationId, targetActivity, dataNamespace); - sInstance.restartProgressTimer(); - } - return sInstance; - } - - - /** - * Returns a (singleton) instance of this class. Clients should call this method in order to - * get a hold of this singleton instance, only after it is initialized. If it is not initialized - * yet, an {@link IllegalStateException} will be thrown. - * - */ - public static VideoCastManager getInstance() { - if (sInstance == null) { - String msg = "No VideoCastManager instance was found, did you forget to initialize it?"; - LOGE(TAG, msg); - throw new IllegalStateException(msg); - } - return sInstance; - } - - @Override - protected void onFeaturesUpdated(int capabilities) { - if (isFeatureEnabled(FEATURE_CAPTIONS_PREFERENCE)) { - mTrackManager = new TracksPreferenceManager(mContext.getApplicationContext()); - registerCaptionListener(mContext.getApplicationContext()); - } - } - - /** - * Updates the information and state of a MiniController. - * - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - private void updateMiniController(IMiniController controller) - throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - checkRemoteMediaPlayerAvailable(); - if (mRemoteMediaPlayer.getStreamDuration() > 0 || isRemoteStreamLive()) { - MediaInfo mediaInfo = getRemoteMediaInformation(); - MediaMetadata mm = mediaInfo.getMetadata(); - controller.setStreamType(mediaInfo.getStreamType()); - controller.setPlaybackStatus(mState, mIdleReason); - controller.setSubtitle(mContext.getResources().getString(R.string.ccl_casting_to_device, - mDeviceName)); - controller.setTitle(mm.getString(MediaMetadata.KEY_TITLE)); - controller.setIcon(Utils.getImageUri(mediaInfo, 0)); - } - } - - /* - * Updates the information and state of all MiniControllers - */ - private void updateMiniControllers() { - synchronized (mMiniControllers) { - for (final IMiniController controller : mMiniControllers) { - try { - updateMiniController(controller); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "updateMiniControllers() Failed to update mini controller", e); - } - } - } - } - - /* - * (non-Javadoc) - * @see com.google.android.libraries.cast.companionlibrary.widgets.MiniController. - * OnMiniControllerChangedListener#onPlayPauseClicked(android.view.View) - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws CastException - */ - @Override - public void onPlayPauseClicked(View v) throws CastException, - TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (mState == MediaStatus.PLAYER_STATE_PLAYING) { - pause(); - } else { - boolean isLive = isRemoteStreamLive(); - if ((mState == MediaStatus.PLAYER_STATE_PAUSED && !isLive) - || (mState == MediaStatus.PLAYER_STATE_IDLE && isLive)) { - play(); - } - } - } - - /* - * (non-Javadoc) - * @see com.google.android.libraries.cast.companionlibrary.widgets.MiniController. - * OnMiniControllerChangedListener #onTargetActivityInvoked(android.content.Context) - */ - @Override - public void onTargetActivityInvoked(Context context) throws - TransientNetworkDisconnectionException, NoConnectionException { - Intent intent = new Intent(context, mTargetActivity); - intent.putExtra(EXTRA_MEDIA, Utils.mediaInfoToBundle(getRemoteMediaInformation())); - context.startActivity(intent); - } - - @Override - public void onUpcomingPlayClicked(View view, MediaQueueItem upcomingItem) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onUpcomingPlayClicked(view, upcomingItem); - } - } - - @Override - public void onUpcomingStopClicked(View view, MediaQueueItem upcomingItem) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onUpcomingStopClicked(view, upcomingItem); - } - } - - /** - * Updates the visibility of the mini controllers. In most cases, clients do not need to use - * this as the {@link VideoCastManager} handles the visibility. - * - * @param visible If {@link true}, mini controllers wil be visible; hidden otherwise. - */ - public void updateMiniControllersVisibility(boolean visible) { - LOGD(TAG, "updateMiniControllersVisibility() reached with visibility: " + visible); - synchronized (mMiniControllers) { - for (IMiniController controller : mMiniControllers) { - controller.setVisibility(visible ? View.VISIBLE : View.GONE); - } - } - } - - public void updateMiniControllersVisibilityForUpcoming(MediaQueueItem item) { - synchronized (mMiniControllers) { - for (IMiniController controller : mMiniControllers) { - controller.setUpcomingItem(item); - controller.setUpcomingVisibility(item != null); - } - } - } - - /** - * Sets an internal flag that is used to disambiguate the two cases that the - * {@code VideoCastControllerActivity} is started programmatically or through the system (say, - * after configuration change or from recent history). - */ - private void setFlagForStartCastControllerActivity() { - mPreferenceAccessor.saveBooleanToPreference(PREFS_KEY_START_ACTIVITY, true); - } - - /** - * Launches the VideoCastControllerActivity that provides a default Cast Player page. - * - * @param context The context to use for starting the activity - * @param mediaWrapper a bundle wrapper for the media that is or will be casted - * @param position Starting point, in milliseconds, of the media playback - * @param shouldStart indicates if the remote playback should start after launching the new - * page - * @param customData Optional {@link JSONObject} - */ - public void startVideoCastControllerActivity(Context context, Bundle mediaWrapper, int position, - boolean shouldStart, JSONObject customData) { - Intent intent = new Intent(context, VideoCastControllerActivity.class); - intent.putExtra(EXTRA_MEDIA, mediaWrapper); - intent.putExtra(EXTRA_START_POINT, position); - intent.putExtra(EXTRA_SHOULD_START, shouldStart); - if (customData != null) { - intent.putExtra(EXTRA_CUSTOM_DATA, customData.toString()); - } - setFlagForStartCastControllerActivity(); - context.startActivity(intent); - } - - /** - * Launches the {@link VideoCastControllerActivity} that provides a default Cast Player page. - * - * @param context The context to use for starting the activity - * @param mediaWrapper A bundle wrapper for the media that is or will be casted - * @param position Starting point, in milliseconds, of the media playback - * @param shouldStart Indicates if the remote playback should start after launching the new - * page - */ - public void startVideoCastControllerActivity(Context context, Bundle mediaWrapper, int position, - boolean shouldStart) { - startVideoCastControllerActivity(context, mediaWrapper, position, shouldStart, null); - } - - /** - * Launches the {@link VideoCastControllerActivity} that provides a default Cast Player page. - * This variation should be used when an - * {@link com.google.android.libraries.cast.companionlibrary.cast.player.MediaAuthService} - * needs to be used. - */ - public void startVideoCastControllerActivity(Context context, MediaAuthService authService) { - if (authService != null) { - mAuthService = authService; - Intent intent = new Intent(context, VideoCastControllerActivity.class); - intent.putExtra(EXTRA_HAS_AUTH, true); - setFlagForStartCastControllerActivity(); - context.startActivity(intent); - } - } - - /** - * Launches the {@link VideoCastControllerActivity} that provides a default Cast Player page. - * - * @param context The context to use for starting the activity - * @param mediaInfo The media that is or will be casted - * @param position Starting point, in milliseconds, of the media playback - * @param shouldStart Indicates if the remote playback should start after launching the new page - */ - public void startVideoCastControllerActivity(Context context, - MediaInfo mediaInfo, int position, boolean shouldStart) { - startVideoCastControllerActivity(context, Utils.mediaInfoToBundle(mediaInfo), position, - shouldStart); - } - - /** - * Returns the instance of - * {@link com.google.android.libraries.cast.companionlibrary.cast.player.MediaAuthService}, - * or null if there is no such instance. - */ - public MediaAuthService getMediaAuthService() { - return mAuthService; - } - - /** - * Sets the - * {@link com.google.android.libraries.cast.companionlibrary.cast.player.MediaAuthService}. - */ - public void setMediaAuthService(MediaAuthService authService) { - mAuthService = authService; - } - - /** - * Removes the pointer to the - * {@link com.google.android.libraries.cast.companionlibrary.cast.player.MediaAuthService} to - * avoid any leak. - */ - public void removeMediaAuthService() { - mAuthService = null; - } - - /** - * Returns the active {@link RemoteMediaPlayer} instance. Since there are a number of media - * control APIs that this library do not provide a wrapper for, client applications can call - * those methods directly after obtaining an instance of the active {@link RemoteMediaPlayer}. - */ - public final RemoteMediaPlayer getRemoteMediaPlayer() { - return mRemoteMediaPlayer; - } - - /** - * Determines if the media that is loaded remotely is a live stream or not. - * - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public final boolean isRemoteStreamLive() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - MediaInfo info = getRemoteMediaInformation(); - return (info != null) && (info.getStreamType() == MediaInfo.STREAM_TYPE_LIVE); - } - - /** - * A helper method to determine if, given a player state and an idle reason (if the state is - * idle) will warrant having a UI for remote presentation of the remote content. - * - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public boolean shouldRemoteUiBeVisible(int state, int idleReason) - throws TransientNetworkDisconnectionException, NoConnectionException { - switch (state) { - case MediaStatus.PLAYER_STATE_PLAYING: - case MediaStatus.PLAYER_STATE_PAUSED: - case MediaStatus.PLAYER_STATE_BUFFERING: - return true; - case MediaStatus.PLAYER_STATE_IDLE: - return isRemoteStreamLive() && (idleReason == MediaStatus.IDLE_REASON_CANCELED); - default: - } - return false; - } - - /* - * A simple check to make sure mRemoteMediaPlayer is not null - */ - private void checkRemoteMediaPlayerAvailable() throws NoConnectionException { - if (mRemoteMediaPlayer == null) { - throw new NoConnectionException(); - } - } - - /** - * Sets the type of volume. Most applications should use {@code VolumeType.DEVICE} (which is - * the default value) but in rare cases, an application can set the type to {@code - * VolumeType.STREAM} - */ - public final void setVolumeType(VolumeType volumeType) { - mVolumeType = volumeType; - } - - /** - * Returns the url for the movie that is currently playing on the remote device. If there is no - * connection, this will return null. - * - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from - * a possibly transient loss of network - */ - public String getRemoteMediaUrl() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - if (mRemoteMediaPlayer != null && mRemoteMediaPlayer.getMediaInfo() != null) { - MediaInfo info = mRemoteMediaPlayer.getMediaInfo(); - mRemoteMediaPlayer.getMediaStatus().getPlayerState(); - return info.getContentId(); - } - throw new NoConnectionException(); - } - - /** - * Indicates if the remote movie is currently playing (or buffering). - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public boolean isRemoteMediaPlaying() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - return mState == MediaStatus.PLAYER_STATE_BUFFERING - || mState == MediaStatus.PLAYER_STATE_PLAYING; - } - - /** - * Returns true if the remote connected device is playing a movie. - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public boolean isRemoteMediaPaused() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - return mState == MediaStatus.PLAYER_STATE_PAUSED; - } - - /** - * Returns true only if there is a media on the remote being played, paused or - * buffered. - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public boolean isRemoteMediaLoaded() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - return isRemoteMediaPaused() || isRemoteMediaPlaying(); - } - - /** - * Returns the {@link MediaInfo} for the current media - * - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from - * a possibly transient loss of network - */ - public MediaInfo getRemoteMediaInformation() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - checkRemoteMediaPlayerAvailable(); - return mRemoteMediaPlayer.getMediaInfo(); - } - - /** - * Gets the remote's system volume. It internally detects what type of volume is used. - * - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from - * a possibly transient loss of network - */ - public double getVolume() throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (mVolumeType == VolumeType.STREAM) { - checkRemoteMediaPlayerAvailable(); - return mRemoteMediaPlayer.getMediaStatus().getStreamVolume(); - } - return getDeviceVolume(); - } - - /** - * Sets the volume. It internally determines if this should be done for stream or - * device volume. - * - * @param volume Should be a value between 0 and 1, inclusive. - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - * @throws CastException If setting system volume fails - * - * @see {link #setVolumeType()} - */ - public void setVolume(double volume) throws CastException, - TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (volume > 1.0) { - volume = 1.0; - } else if (volume < 0) { - volume = 0.0; - } - if (mVolumeType == VolumeType.STREAM) { - checkRemoteMediaPlayerAvailable(); - mRemoteMediaPlayer.setStreamVolume(mApiClient, volume).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - if (!result.getStatus().isSuccess()) { - onFailed(R.string.ccl_failed_setting_volume, - result.getStatus().getStatusCode()); - } - } - } - ); - } else { - setDeviceVolume(volume); - } - } - - /** - * Increments (or decrements) the volume by the given amount. It internally determines if this - * should be done for stream or device volume. - * - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from - * a possibly transient loss of network - * @throws CastException - */ - public void adjustVolume(double delta) throws CastException, - TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - double vol = getVolume() + delta; - if (vol > 1) { - vol = 1; - } else if (vol < 0) { - vol = 0; - } - setVolume(vol); - } - - /** - * Increments or decrements volume by delta if {@code delta < 0} or - * {@code delta > 0}, respectively. Note that the volume range is between 0 and {@code - * RouteInfo.getVolumeMax()}. - */ - public void updateVolume(int delta) { - RouteInfo info = mMediaRouter.getSelectedRoute(); - info.requestUpdateVolume(delta); - } - - /** - * Returns true if remote device is muted. It internally determines if this should - * be done for stream or device volume. - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public boolean isMute() throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (mVolumeType == VolumeType.STREAM) { - checkRemoteMediaPlayerAvailable(); - return mRemoteMediaPlayer.getMediaStatus().isMute(); - } else { - return isDeviceMute(); - } - } - - /** - * Mutes or un-mutes the volume. It internally determines if this should be done for - * stream or device volume. - * - * @throws CastException - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void setMute(boolean mute) throws CastException, TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - if (mVolumeType == VolumeType.STREAM) { - checkRemoteMediaPlayerAvailable(); - mRemoteMediaPlayer.setStreamMute(mApiClient, mute); - } else { - setDeviceMute(mute); - } - } - - /** - * Returns the duration of the media that is loaded, in milliseconds. - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public long getMediaDuration() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - checkRemoteMediaPlayerAvailable(); - return mRemoteMediaPlayer.getStreamDuration(); - } - - /** - * Returns the time left (in milliseconds) of the current media. If there is no - * {@code RemoteMediaPlayer}, it returns -1. - * - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public long getMediaTimeRemaining() - throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - return -1; - } - return isRemoteStreamLive() ? mLiveStreamDuration : mRemoteMediaPlayer.getStreamDuration() - - mRemoteMediaPlayer.getApproximateStreamPosition(); - } - - /** - * Returns the current (approximate) position of the current media, in milliseconds. - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public long getCurrentMediaPosition() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - checkRemoteMediaPlayerAvailable(); - return mRemoteMediaPlayer.getApproximateStreamPosition(); - } - - /* - * Starts a service that can last beyond the lifetime of the application to provide - * notifications. The service brings itself down when needed. The service will be started only - * if the notification feature has been enabled during the initialization. - * @see {@link BaseCastManager#enableFeatures()} - */ - private boolean startNotificationService() { - if (!isFeatureEnabled(FEATURE_NOTIFICATION)) { - return true; - } - LOGD(TAG, "startNotificationService()"); - Intent service = new Intent(mContext, VideoCastNotificationService.class); - service.setPackage(mContext.getPackageName()); - service.setAction(VideoCastNotificationService.ACTION_VISIBILITY); - service.putExtra(VideoCastNotificationService.NOTIFICATION_VISIBILITY, !mUiVisible); - return mContext.startService(service) != null; - } - - private void stopNotificationService() { - if (!isFeatureEnabled(FEATURE_NOTIFICATION)) { - return; - } - if (mContext != null) { - mContext.stopService(new Intent(mContext, VideoCastNotificationService.class)); - } - } - - private void onApplicationDisconnected(int errorCode) { - LOGD(TAG, "onApplicationDisconnected() reached with error code: " + errorCode); - mApplicationErrorCode = errorCode; - updateMediaSession(false); - if (mMediaSessionCompat != null && isFeatureEnabled(FEATURE_LOCKSCREEN)) { - mMediaRouter.setMediaSessionCompat(null); - } - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onApplicationDisconnected(errorCode); - } - if (mMediaRouter != null) { - LOGD(TAG, "onApplicationDisconnected(): Cached RouteInfo: " + getRouteInfo()); - LOGD(TAG, "onApplicationDisconnected(): Selected RouteInfo: " - + mMediaRouter.getSelectedRoute()); - if (getRouteInfo() == null || mMediaRouter.getSelectedRoute().equals(getRouteInfo())) { - LOGD(TAG, "onApplicationDisconnected(): Setting route to default"); - mMediaRouter.selectRoute(mMediaRouter.getDefaultRoute()); - } - } - onDeviceSelected(null); - updateMiniControllersVisibility(false); - stopNotificationService(); - } - - private void onApplicationStatusChanged() { - if (!isConnected()) { - return; - } - try { - String appStatus = Cast.CastApi.getApplicationStatus(mApiClient); - LOGD(TAG, "onApplicationStatusChanged() reached: " + appStatus); - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onApplicationStatusChanged(appStatus); - } - } catch (IllegalStateException e) { - LOGE(TAG, "onApplicationStatusChanged()", e); - } - } - - private void onVolumeChanged() { - LOGD(TAG, "onVolumeChanged() reached"); - double volume; - try { - volume = getVolume(); - boolean isMute = isMute(); - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onVolumeChanged(volume, isMute); - } - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to get volume", e); - } - - } - - @Override - protected void onApplicationConnected(ApplicationMetadata appMetadata, - String applicationStatus, String sessionId, boolean wasLaunched) { - LOGD(TAG, "onApplicationConnected() reached with sessionId: " + sessionId - + ", and mReconnectionStatus=" + mReconnectionStatus); - mApplicationErrorCode = NO_APPLICATION_ERROR; - if (mReconnectionStatus == RECONNECTION_STATUS_IN_PROGRESS) { - // we have tried to reconnect and successfully launched the app, so - // it is time to select the route and make the cast icon happy :-) - List routes = mMediaRouter.getRoutes(); - if (routes != null) { - String routeId = mPreferenceAccessor.getStringFromPreference(PREFS_KEY_ROUTE_ID); - for (RouteInfo routeInfo : routes) { - if (routeId.equals(routeInfo.getId())) { - // found the right route - LOGD(TAG, "Found the correct route during reconnection attempt"); - mReconnectionStatus = RECONNECTION_STATUS_FINALIZED; - mMediaRouter.selectRoute(routeInfo); - break; - } - } - } - } - startNotificationService(); - try { - attachDataChannel(); - attachMediaChannel(); - mSessionId = sessionId; - // saving device for future retrieval; we only save the last session info - mPreferenceAccessor.saveStringToPreference(PREFS_KEY_SESSION_ID, mSessionId); - mRemoteMediaPlayer.requestStatus(mApiClient). - setResultCallback(new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - if (!result.getStatus().isSuccess()) { - onFailed(R.string.ccl_failed_status_request, - result.getStatus().getStatusCode()); - } - - } - }); - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onApplicationConnected(appMetadata, mSessionId, wasLaunched); - } - } catch (TransientNetworkDisconnectionException e) { - LOGE(TAG, "Failed to attach media/data channel due to network issues", e); - onFailed(R.string.ccl_failed_no_connection_trans, NO_STATUS_CODE); - } catch (NoConnectionException e) { - LOGE(TAG, "Failed to attach media/data channel due to network issues", e); - onFailed(R.string.ccl_failed_no_connection, NO_STATUS_CODE); - } - - } - - /* - * (non-Javadoc) - * @see com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager - * #onConnectivityRecovered() - */ - @Override - public void onConnectivityRecovered() { - reattachMediaChannel(); - reattachDataChannel(); - super.onConnectivityRecovered(); - } - - /* - * (non-Javadoc) - * @see com.google.android.gms.cast.CastClient.Listener#onApplicationStopFailed (int) - */ - @Override - public void onApplicationStopFailed(int errorCode) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onApplicationStopFailed(errorCode); - } - } - - @Override - public void onApplicationConnectionFailed(int errorCode) { - LOGD(TAG, "onApplicationConnectionFailed() reached with errorCode: " + errorCode); - mApplicationErrorCode = errorCode; - if (mReconnectionStatus == RECONNECTION_STATUS_IN_PROGRESS) { - if (errorCode == CastStatusCodes.APPLICATION_NOT_RUNNING) { - // while trying to re-establish session, we found out that the app is not running - // so we need to disconnect - mReconnectionStatus = RECONNECTION_STATUS_INACTIVE; - onDeviceSelected(null); - } - } else { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onApplicationConnectionFailed(errorCode); - } - onDeviceSelected(null); - if (mMediaRouter != null) { - LOGD(TAG, "onApplicationConnectionFailed(): Setting route to default"); - mMediaRouter.selectRoute(mMediaRouter.getDefaultRoute()); - } - } - } - - /** - * Loads a media. For this to succeed, you need to have successfully launched the application. - * - * @param media The media to be loaded - * @param autoPlay If true, playback starts after load - * @param position Where to start the playback (only used if autoPlay is true. - * Units is milliseconds. - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void loadMedia(MediaInfo media, boolean autoPlay, int position) - throws TransientNetworkDisconnectionException, NoConnectionException { - loadMedia(media, autoPlay, position, null); - } - - /** - * Loads a media. For this to succeed, you need to have successfully launched the application. - * - * @param media The media to be loaded - * @param autoPlay If true, playback starts after load - * @param position Where to start the playback (only used if autoPlay is true). - * Units is milliseconds. - * @param customData Optional {@link JSONObject} data to be passed to the cast device - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void loadMedia(MediaInfo media, boolean autoPlay, int position, JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - loadMedia(media, null, autoPlay, position, customData); - } - - /** - * Loads a media. For this to succeed, you need to have successfully launched the application. - * - * @param media The media to be loaded - * @param activeTracks An array containing the list of track IDs to be set active for this - * media upon a successful load - * @param autoPlay If true, playback starts after load - * @param position Where to start the playback (only used if autoPlay is true). - * Units is milliseconds. - * @param customData Optional {@link JSONObject} data to be passed to the cast device - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void loadMedia(MediaInfo media, final long[] activeTracks, boolean autoPlay, - int position, JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - LOGD(TAG, "loadMedia"); - checkConnectivity(); - if (media == null) { - return; - } - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to load a video with no active media session"); - throw new NoConnectionException(); - } - - mRemoteMediaPlayer.load(mApiClient, media, autoPlay, position, activeTracks, customData) - .setResultCallback(new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaLoadResult(result.getStatus().getStatusCode()); - } - } - }); - } - /** - * Loads and optionally starts playback of a new queue of media items. - * - * @param items Array of items to load, in the order that they should be played. Must not be - * {@code null} or empty. - * @param startIndex The array index of the item in the {@code items} array that should be - * played first (i.e., it will become the currentItem).If {@code repeatMode} - * is {@link MediaStatus#REPEAT_MODE_REPEAT_OFF} playback will end when the - * last item in the array is played. - *

- * This may be useful for continuation scenarios where the user was already - * using the sender application and in the middle decides to cast. This lets - * the sender application avoid mapping between the local and remote queue - * positions and/or avoid issuing an extra request to update the queue. - *

- * This value must be less than the length of {@code items}. - * @param repeatMode The repeat playback mode for the queue. One of - * {@link MediaStatus#REPEAT_MODE_REPEAT_OFF}, - * {@link MediaStatus#REPEAT_MODE_REPEAT_ALL}, - * {@link MediaStatus#REPEAT_MODE_REPEAT_SINGLE} and - * {@link MediaStatus#REPEAT_MODE_REPEAT_ALL_AND_SHUFFLE}. - * @param customData Custom application-specific data to pass along with the request, may be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueLoad(final MediaQueueItem[] items, final int startIndex, final int repeatMode, - final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - LOGD(TAG, "queueLoad"); - checkConnectivity(); - if (items == null || items.length == 0) { - return; - } - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to queue one or more videos with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer - .queueLoad(mApiClient, items, startIndex, repeatMode, customData) - .setResultCallback(new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_LOAD, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Inserts a list of new media items into the queue. - * - * @param itemsToInsert List of items to insert into the queue, in the order that they should be - * played. The itemId field of the items should be unassigned or the - * request will fail with an INVALID_PARAMS error. Must not be {@code null} - * or empty. - * @param insertBeforeItemId ID of the item that will be located immediately after the inserted - * list. If the value is {@link MediaQueueItem#INVALID_ITEM_ID} or - * invalid, the inserted list will be appended to the end of the - * queue. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws IllegalArgumentException - */ - public void queueInsertItems(final MediaQueueItem[] itemsToInsert, final int insertBeforeItemId, - final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - LOGD(TAG, "queueInsertItems"); - checkConnectivity(); - if (itemsToInsert == null || itemsToInsert.length == 0) { - throw new IllegalArgumentException("items cannot be empty or null"); - } - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to insert into queue with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer - .queueInsertItems(mApiClient, itemsToInsert, insertBeforeItemId, customData) - .setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult( - QUEUE_OPERATION_INSERT_ITEMS, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Updates properties of a subset of the existing items in the media queue. - * - * @param itemsToUpdate List of queue items to be updated. The items will retain the existing - * order and will be fully replaced with the ones provided, including the - * media information. Any other items currently in the queue will remain - * unchanged. The tracks information can not change once the item is loaded - * (if the item is the currentItem). If any of the items does not exist it - * will be ignored. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueUpdateItems(final MediaQueueItem[] itemsToUpdate, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to update the queue with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer - .queueUpdateItems(mApiClient, itemsToUpdate, customData).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - LOGD(TAG, "queueUpdateItems() " + result.getStatus() + result.getStatus() - .isSuccess()); - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_UPDATE_ITEMS, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Plays the item with {@code itemId} in the queue. - *

- * If {@code itemId} is not found in the queue, this method will report success without sending - * a request to the receiver. - * - * @param itemId The ID of the item to which to jump. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws IllegalArgumentException - */ - public void queueJumpToItem(int itemId, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException, - IllegalArgumentException { - checkConnectivity(); - if (itemId == MediaQueueItem.INVALID_ITEM_ID) { - throw new IllegalArgumentException("itemId is not valid"); - } - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to jump in a queue with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer - .queueJumpToItem(mApiClient, itemId, customData).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_JUMP, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Removes a list of items from the queue. If the remaining queue is empty, the media session - * will be terminated. - * - * @param itemIdsToRemove The list of media item IDs to remove. Must not be {@code null} or - * empty. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws IllegalArgumentException - */ - public void queueRemoveItems(final int[] itemIdsToRemove, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException, - IllegalArgumentException { - LOGD(TAG, "queueRemoveItems"); - checkConnectivity(); - if (itemIdsToRemove == null || itemIdsToRemove.length == 0) { - throw new IllegalArgumentException("itemIds cannot be empty or null"); - } - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to remove items from queue with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer - .queueRemoveItems(mApiClient, itemIdsToRemove, customData).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_REMOVE_ITEMS, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Removes the item with {@code itemId} from the queue. - *

- * If {@code itemId} is not found in the queue, this method will silently return without sending - * a request to the receiver. A {@code itemId} may not be in the queue because it wasn't - * originally in the queue, or it was removed by another sender. - * - * @param itemId The ID of the item to be removed. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws IllegalArgumentException - */ - public void queueRemoveItem(final int itemId, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException, - IllegalArgumentException { - LOGD(TAG, "queueRemoveItem"); - checkConnectivity(); - if (itemId == MediaQueueItem.INVALID_ITEM_ID) { - throw new IllegalArgumentException("itemId is invalid"); - } - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to remove an item from queue with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer - .queueRemoveItem(mApiClient, itemId, customData).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_REMOVE_ITEM, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Reorder a list of media items in the queue. - * - * @param itemIdsToReorder The list of media item IDs to reorder, in the new order. Any other - * items currently in the queue will maintain their existing order. The - * list will be inserted just before the item specified by - * {@code insertBeforeItemId}, or at the end of the queue if - * {@code insertBeforeItemId} is {@link MediaQueueItem#INVALID_ITEM_ID}. - *

- * For example: - *

- * If insertBeforeItemId is not specified
- * Existing queue: "A","D","G","H","B","E"
- * itemIds: "D","H","B"
- * New Order: "A","G","E","D","H","B"
- *

- * If insertBeforeItemId is "A"
- * Existing queue: "A","D","G","H","B"
- * itemIds: "D","H","B"
- * New Order: "D","H","B","A","G","E"
- *

- * If insertBeforeItemId is "G"
- * Existing queue: "A","D","G","H","B"
- * itemIds: "D","H","B"
- * New Order: "A","D","H","B","G","E"
- *

- * If any of the items does not exist it will be ignored. - * Must not be {@code null} or empty. - * @param insertBeforeItemId ID of the item that will be located immediately after the reordered - * list. If set to {@link MediaQueueItem#INVALID_ITEM_ID}, the - * reordered list will be appended at the end of the queue. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueReorderItems(final int[] itemIdsToReorder, final int insertBeforeItemId, - final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException, - IllegalArgumentException { - LOGD(TAG, "queueReorderItems"); - checkConnectivity(); - if (itemIdsToReorder == null || itemIdsToReorder.length == 0) { - throw new IllegalArgumentException("itemIdsToReorder cannot be empty or null"); - } - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to reorder items in a queue with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer - .queueReorderItems(mApiClient, itemIdsToReorder, insertBeforeItemId, customData) - .setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_REORDER, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Moves the item with {@code itemId} to a new position in the queue. - *

- * If {@code itemId} is not found in the queue, either because it wasn't there originally or it - * was removed by another sender before calling this function, this function will silently - * return without sending a request to the receiver. - * - * @param itemId The ID of the item to be moved. - * @param newIndex The new index of the item. If the value is negative, an error will be - * returned. If the value is out of bounds, or becomes out of bounds because the - * queue was shortened by another sender while this request is in progress, the - * item will be moved to the end of the queue. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueMoveItemToNewIndex(int itemId, int newIndex, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - mRemoteMediaPlayer - .queueMoveItemToNewIndex(mApiClient, itemId, newIndex, customData) - .setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_MOVE, - result.getStatus().getStatusCode());; - } - } - }); - } - - /** - * Appends a new media item to the end of the queue. - * - * @param item The item to append. Must not be {@code null}. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueAppendItem(MediaQueueItem item, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - mRemoteMediaPlayer - .queueAppendItem(mApiClient, item, customData) - .setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_APPEND, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Jumps to the next item in the queue. - * - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueNext(final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to update the queue with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer - .queueNext(mApiClient, customData).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_NEXT, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Jumps to the previous item in the queue. - * - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queuePrev(final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to update the queue with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer - .queuePrev(mApiClient, customData).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_PREV, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Inserts an item in the queue and starts the playback of that newly inserted item. It is - * assumed that we are inserting before the "current item" - * - * @param item The item to be inserted - * @param insertBeforeItemId ID of the item that will be located immediately after the inserted - * and is assumed to be the "current item" - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws IllegalArgumentException - */ - public void queueInsertBeforeCurrentAndPlay(MediaQueueItem item, int insertBeforeItemId, - final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to insert into queue with no active media session"); - throw new NoConnectionException(); - } - if (item == null || insertBeforeItemId == MediaQueueItem.INVALID_ITEM_ID) { - throw new IllegalArgumentException( - "item cannot be empty or insertBeforeItemId cannot be invalid"); - } - mRemoteMediaPlayer.queueInsertItems(mApiClient, new MediaQueueItem[]{item}, - insertBeforeItemId, customData).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - if (result.getStatus().isSuccess()) { - - try { - queuePrev(customData); - } catch (TransientNetworkDisconnectionException | - NoConnectionException e) { - LOGE(TAG, "queuePrev() Failed to skip to previous", e); - } - } - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_INSERT_ITEMS, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Sets the repeat mode of the queue. - * - * @param repeatMode The repeat playback mode for the queue. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueSetRepeatMode(final int repeatMode, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to update the queue with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer - .queueSetRepeatMode(mApiClient, repeatMode, customData).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - if (!result.getStatus().isSuccess()) { - LOGD(TAG, "Failed with status: " + result.getStatus()); - } - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_SET_REPEAT, - result.getStatus().getStatusCode()); - } - } - }); - } - - /** - * Plays the loaded media. - * - * @param position Where to start the playback. Units is milliseconds. - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void play(int position) throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - LOGD(TAG, "attempting to play media at position " + position + " seconds"); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to play a video with no active media session"); - throw new NoConnectionException(); - } - seekAndPlay(position); - } - - /** - * Resumes the playback from where it was left (can be the beginning). - * - * @param customData Optional {@link JSONObject} data to be passed to the cast device - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void play(JSONObject customData) throws - TransientNetworkDisconnectionException, NoConnectionException { - LOGD(TAG, "play(customData)"); - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to play a video with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer.play(mApiClient, customData) - .setResultCallback(new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - if (!result.getStatus().isSuccess()) { - onFailed(R.string.ccl_failed_to_play, - result.getStatus().getStatusCode()); - } - } - - }); - } - - /** - * Resumes the playback from where it was left (can be the beginning). - * - * @throws CastException - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void play() throws CastException, TransientNetworkDisconnectionException, - NoConnectionException { - play(null); - } - - /** - * Stops the playback of media/stream - * - * @param customData Optional {@link JSONObject} - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void stop(JSONObject customData) throws - TransientNetworkDisconnectionException, NoConnectionException { - LOGD(TAG, "stop()"); - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to stop a stream with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer.stop(mApiClient, customData).setResultCallback( - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - if (!result.getStatus().isSuccess()) { - onFailed(R.string.ccl_failed_to_stop, - result.getStatus().getStatusCode()); - } - } - - } - ); - } - - /** - * Stops the playback of media/stream - * - * @throws CastException - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void stop() throws CastException, - TransientNetworkDisconnectionException, NoConnectionException { - stop(null); - } - - /** - * Pauses the playback. - * - * @throws CastException - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void pause() throws CastException, TransientNetworkDisconnectionException, - NoConnectionException { - pause(null); - } - - /** - * Pauses the playback. - * - * @param customData Optional {@link JSONObject} data to be passed to the cast device - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void pause(JSONObject customData) throws - TransientNetworkDisconnectionException, NoConnectionException { - LOGD(TAG, "attempting to pause media"); - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to pause a video with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer.pause(mApiClient, customData) - .setResultCallback(new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - if (!result.getStatus().isSuccess()) { - onFailed(R.string.ccl_failed_to_pause, - result.getStatus().getStatusCode()); - } - } - - }); - } - - /** - * Seeks to the given point without changing the state of the player, i.e. after seek is - * completed, it resumes what it was doing before the start of seek. - * - * @param position in milliseconds - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void seek(int position) throws TransientNetworkDisconnectionException, - NoConnectionException { - LOGD(TAG, "attempting to seek media"); - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to seek a video with no active media session"); - throw new NoConnectionException(); - } - mRemoteMediaPlayer.seek(mApiClient, - position, - RemoteMediaPlayer.RESUME_STATE_UNCHANGED). - setResultCallback(new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - if (!result.getStatus().isSuccess()) { - onFailed(R.string.ccl_failed_seek, result.getStatus().getStatusCode()); - } - } - - }); - } - - /** - * Seeks to the given point and starts playback regardless of the starting state. - * - * @param position in milliseconds - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void seekAndPlay(int position) throws TransientNetworkDisconnectionException, - NoConnectionException { - LOGD(TAG, "attempting to seek media"); - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - LOGE(TAG, "Trying to seekAndPlay a video with no active media session"); - throw new NoConnectionException(); - } - ResultCallback resultCallback = - new ResultCallback() { - - @Override - public void onResult(MediaChannelResult result) { - if (!result.getStatus().isSuccess()) { - onFailed(R.string.ccl_failed_seek, result.getStatus().getStatusCode()); - } - } - - }; - mRemoteMediaPlayer.seek(mApiClient, - position, - RemoteMediaPlayer.RESUME_STATE_PLAY).setResultCallback(resultCallback); - } - - /** - * Toggles the playback of the movie. - * - * @throws CastException - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void togglePlayback() throws CastException, TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - boolean isPlaying = isRemoteMediaPlaying(); - if (isPlaying) { - pause(); - } else { - if (mState == MediaStatus.PLAYER_STATE_IDLE - && mIdleReason == MediaStatus.IDLE_REASON_FINISHED) { - loadMedia(getRemoteMediaInformation(), true, 0); - } else { - play(); - } - } - } - - private void attachMediaChannel() throws TransientNetworkDisconnectionException, - NoConnectionException { - LOGD(TAG, "attachMediaChannel()"); - checkConnectivity(); - if (mRemoteMediaPlayer == null) { - mRemoteMediaPlayer = new RemoteMediaPlayer(); - - mRemoteMediaPlayer.setOnStatusUpdatedListener( - new RemoteMediaPlayer.OnStatusUpdatedListener() { - - @Override - public void onStatusUpdated() { - LOGD(TAG, "RemoteMediaPlayer::onStatusUpdated() is reached"); - VideoCastManager.this.onRemoteMediaPlayerStatusUpdated(); - } - } - ); - - mRemoteMediaPlayer.setOnPreloadStatusUpdatedListener( - new RemoteMediaPlayer.OnPreloadStatusUpdatedListener() { - - @Override - public void onPreloadStatusUpdated() { - LOGD(TAG, - "RemoteMediaPlayer::onPreloadStatusUpdated() is " - + "reached"); - VideoCastManager.this.onRemoteMediaPreloadStatusUpdated(); - } - }); - - - mRemoteMediaPlayer.setOnMetadataUpdatedListener( - new RemoteMediaPlayer.OnMetadataUpdatedListener() { - @Override - public void onMetadataUpdated() { - LOGD(TAG, "RemoteMediaPlayer::onMetadataUpdated() is reached"); - VideoCastManager.this.onRemoteMediaPlayerMetadataUpdated(); - } - } - ); - - mRemoteMediaPlayer.setOnQueueStatusUpdatedListener( - new RemoteMediaPlayer.OnQueueStatusUpdatedListener() { - - @Override - public void onQueueStatusUpdated() { - LOGD(TAG, - "RemoteMediaPlayer::onQueueStatusUpdated() is " - + "reached"); - mMediaStatus = mRemoteMediaPlayer.getMediaStatus(); - if (mMediaStatus != null - && mMediaStatus.getQueueItems() != null) { - List queueItems = mMediaStatus - .getQueueItems(); - int itemId = mMediaStatus.getCurrentItemId(); - MediaQueueItem item = mMediaStatus - .getQueueItemById(itemId); - int repeatMode = mMediaStatus.getQueueRepeatMode(); - boolean shuffle = false; - onQueueUpdated(queueItems, item, repeatMode, shuffle); - } else { - onQueueUpdated(null, null, - MediaStatus.REPEAT_MODE_REPEAT_OFF, - false); - } - } - }); - - } - try { - LOGD(TAG, "Registering MediaChannel namespace"); - Cast.CastApi.setMessageReceivedCallbacks(mApiClient, mRemoteMediaPlayer.getNamespace(), - mRemoteMediaPlayer); - } catch (IOException | IllegalStateException e) { - LOGE(TAG, "attachMediaChannel()", e); - } - } - - private void reattachMediaChannel() { - if (mRemoteMediaPlayer != null && mApiClient != null) { - try { - LOGD(TAG, "Registering MediaChannel namespace"); - Cast.CastApi.setMessageReceivedCallbacks(mApiClient, - mRemoteMediaPlayer.getNamespace(), mRemoteMediaPlayer); - } catch (IOException | IllegalStateException e) { - LOGE(TAG, "reattachMediaChannel()", e); - } - } - } - - private void detachMediaChannel() { - LOGD(TAG, "trying to detach media channel"); - if (mRemoteMediaPlayer != null) { - try { - Cast.CastApi.removeMessageReceivedCallbacks(mApiClient, - mRemoteMediaPlayer.getNamespace()); - } catch (IOException | IllegalStateException e) { - LOGE(TAG, "detachMediaChannel()", e); - } - mRemoteMediaPlayer = null; - } - } - - /** - * Returns the playback status of the remote device. - * - * @return Returns one of the values - *

    - *
  • MediaStatus.PLAYER_STATE_UNKNOWN
  • - *
  • MediaStatus.PLAYER_STATE_IDLE
  • - *
  • MediaStatus.PLAYER_STATE_PLAYING
  • - *
  • MediaStatus.PLAYER_STATE_PAUSED
  • - *
  • MediaStatus.PLAYER_STATE_BUFFERING
  • - *
- */ - public int getPlaybackStatus() { - return mState; - } - - /** - * Returns the latest retrieved value for the {@link MediaStatus}. This value is updated - * whenever the onStatusUpdated callback is called. - */ - public final MediaStatus getMediaStatus() { - return mMediaStatus; - } - - /** - * Returns the Idle reason, defined in MediaStatus.IDLE_*. Note that the returned - * value is only meaningful if the status is truly MediaStatus.PLAYER_STATE_IDLE - * - * - *

Possible values are: - *

    - *
  • IDLE_REASON_NONE
  • - *
  • IDLE_REASON_FINISHED
  • - *
  • IDLE_REASON_CANCELED
  • - *
  • IDLE_REASON_INTERRUPTED
  • - *
  • IDLE_REASON_ERROR
  • - *
- */ - public int getIdleReason() { - return mIdleReason; - } - - /* - * If a data namespace was provided when initializing this class, we set things up for a data - * channel - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - private void attachDataChannel() throws TransientNetworkDisconnectionException, - NoConnectionException { - if (TextUtils.isEmpty(mDataNamespace)) { - return; - } - if (mDataChannel != null) { - return; - } - checkConnectivity(); - mDataChannel = new MessageReceivedCallback() { - - @Override - public void onMessageReceived(CastDevice castDevice, String namespace, String message) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onDataMessageReceived(message); - } - } - }; - try { - Cast.CastApi.setMessageReceivedCallbacks(mApiClient, mDataNamespace, mDataChannel); - } catch (IOException | IllegalStateException e) { - LOGE(TAG, "attachDataChannel()", e); - } - } - - private void reattachDataChannel() { - if (!TextUtils.isEmpty(mDataNamespace) && mDataChannel != null) { - try { - Cast.CastApi.setMessageReceivedCallbacks(mApiClient, mDataNamespace, mDataChannel); - } catch (IOException | IllegalStateException e) { - LOGE(TAG, "reattachDataChannel()", e); - } - } - } - - private void onMessageSendFailed(int errorCode) { - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onDataMessageSendFailed(errorCode); - } - } - - /** - * Sends the message on the data channel for the namespace that was provided - * during the initialization of this class. If messageId > 0, then it has to be - * a unique identifier for the message; this id will be returned if an error occurs. If - * messageId == 0, then an auto-generated unique identifier will be created and - * returned for the message. - * - * @throws IllegalStateException If the namespace is empty or null - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from - * a possibly transient loss of network - */ - public void sendDataMessage(String message) throws TransientNetworkDisconnectionException, - NoConnectionException { - if (TextUtils.isEmpty(mDataNamespace)) { - throw new IllegalStateException("No Data Namespace is configured"); - } - checkConnectivity(); - Cast.CastApi.sendMessage(mApiClient, mDataNamespace, message) - .setResultCallback(new ResultCallback() { - - @Override - public void onResult(Status result) { - if (!result.isSuccess()) { - VideoCastManager.this.onMessageSendFailed(result.getStatusCode()); - } - } - }); - } - - /** - * Remove the custom data channel, if any. It returns true if it succeeds - * otherwise if it encounters an error or if no connection exists or if no custom data channel - * exists, then it returns false - */ - public boolean removeDataChannel() { - if (TextUtils.isEmpty(mDataNamespace)) { - return false; - } - try { - if (mApiClient != null) { - Cast.CastApi.removeMessageReceivedCallbacks(mApiClient, mDataNamespace); - } - mDataChannel = null; - mPreferenceAccessor.saveStringToPreference(PREFS_KEY_CAST_CUSTOM_DATA_NAMESPACE, null); - return true; - } catch (IOException | IllegalStateException e) { - LOGE(TAG, "removeDataChannel() failed to remove namespace " + mDataNamespace, e); - } - return false; - - } - - /* - * This is called by onStatusUpdated() of the RemoteMediaPlayer - */ - private void onRemoteMediaPlayerStatusUpdated() { - LOGD(TAG, "onRemoteMediaPlayerStatusUpdated() reached"); - if (mApiClient == null || mRemoteMediaPlayer == null - || mRemoteMediaPlayer.getMediaStatus() == null) { - LOGD(TAG, "mApiClient or mRemoteMediaPlayer is null, so will not proceed"); - return; - } - mMediaStatus = mRemoteMediaPlayer.getMediaStatus(); - List queueItems = mMediaStatus.getQueueItems(); - if (queueItems != null) { - int itemId = mMediaStatus.getCurrentItemId(); - MediaQueueItem item = mMediaStatus.getQueueItemById(itemId); - int repeatMode = mMediaStatus.getQueueRepeatMode(); - boolean shuffle = false; //mMediaStatus.isShuffleEnabled(); - onQueueUpdated(queueItems, item, repeatMode, shuffle); - } else { - onQueueUpdated(null, null, MediaStatus.REPEAT_MODE_REPEAT_OFF, false); - } - mState = mMediaStatus.getPlayerState(); - mIdleReason = mMediaStatus.getIdleReason(); - - try { - double volume = getVolume(); - boolean isMute = isMute(); - boolean makeUiHidden = false; - if (mState == MediaStatus.PLAYER_STATE_PLAYING) { - LOGD(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = playing"); - updateMediaSession(true); - long mediaDurationLeft = getMediaTimeRemaining(); - startReconnectionService(mediaDurationLeft); - startNotificationService(); - } else if (mState == MediaStatus.PLAYER_STATE_PAUSED) { - LOGD(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = paused"); - updateMediaSession(false); - startNotificationService(); - } else if (mState == MediaStatus.PLAYER_STATE_IDLE) { - LOGD(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = IDLE with reason: " - + mIdleReason ); - updateMediaSession(false); - switch (mIdleReason) { - case MediaStatus.IDLE_REASON_FINISHED: - if (mMediaStatus.getLoadingItemId() == MediaQueueItem.INVALID_ITEM_ID) { - // we have reached the end of queue - clearMediaSession(); - } - makeUiHidden = true; - break; - case MediaStatus.IDLE_REASON_ERROR: - // something bad happened on the cast device - LOGD(TAG, "onRemoteMediaPlayerStatusUpdated(): IDLE reason = ERROR"); - makeUiHidden = true; - clearMediaSession(); - onFailed(R.string.ccl_failed_receiver_player_error, NO_STATUS_CODE); - break; - case MediaStatus.IDLE_REASON_CANCELED: - LOGD(TAG, "onRemoteMediaPlayerStatusUpdated(): IDLE reason = CANCELLED"); - makeUiHidden = !isRemoteStreamLive(); - break; - case MediaStatus.IDLE_REASON_INTERRUPTED: - if (mMediaStatus.getLoadingItemId() == MediaQueueItem.INVALID_ITEM_ID) { - // we have reached the end of queue - clearMediaSession(); - makeUiHidden = true; - } - break; - default: - LOGE(TAG, "onRemoteMediaPlayerStatusUpdated(): Unexpected Idle Reason " - + mIdleReason); - } - if (makeUiHidden) { - stopReconnectionService(); - } - } else if (mState == MediaStatus.PLAYER_STATE_BUFFERING) { - LOGD(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = buffering"); - } else { - LOGD(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = unknown"); - makeUiHidden = true; - } - if (makeUiHidden) { - stopNotificationService(); - } - updateMiniControllersVisibility(!makeUiHidden); - updateMiniControllers(); - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onRemoteMediaPlayerStatusUpdated(); - consumer.onVolumeChanged(volume, isMute); - } - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to get volume state due to network issues", e); - } - - } - - private void onRemoteMediaPreloadStatusUpdated() { - MediaQueueItem item = null; - mMediaStatus = mRemoteMediaPlayer.getMediaStatus(); - if (mMediaStatus != null) { - item = mMediaStatus.getQueueItemById(mMediaStatus.getPreloadedItemId()); - } - mPreLoadingItem = item; - updateMiniControllersVisibilityForUpcoming(item); - LOGD(TAG, "onRemoteMediaPreloadStatusUpdated() " + item); - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onRemoteMediaPreloadStatusUpdated(item); - } - } - - public MediaQueueItem getPreLoadingItem() { - return mPreLoadingItem; - } - - /* - * This is called by onQueueStatusUpdated() of RemoteMediaPlayer - */ - private void onQueueUpdated(List queueItems, MediaQueueItem item, - int repeatMode, boolean shuffle) { - LOGD(TAG, "onQueueUpdated() reached"); - LOGD(TAG, String.format("Queue Items size: %d, Item: %s, Repeat Mode: %d, Shuffle: %s", - queueItems == null ? 0 : queueItems.size(), item, repeatMode, shuffle)); - if (queueItems != null) { - mMediaQueue = new MediaQueue(new CopyOnWriteArrayList<>(queueItems), item, shuffle, - repeatMode); - } else { - mMediaQueue = new MediaQueue(new CopyOnWriteArrayList(), null, false, - MediaStatus.REPEAT_MODE_REPEAT_OFF); - } - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onMediaQueueUpdated(queueItems, item, repeatMode, shuffle); - } - } - - /* - * This is called by onMetadataUpdated() of RemoteMediaPlayer - */ - public void onRemoteMediaPlayerMetadataUpdated() { - LOGD(TAG, "onRemoteMediaPlayerMetadataUpdated() reached"); - updateMediaSessionMetadata(); - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onRemoteMediaPlayerMetadataUpdated(); - } - try { - updateLockScreenImage(getRemoteMediaInformation()); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to update lock screen metadata due to a network issue", e); - } - } - - /** - * Returns the Media Session Token. If there is no media session, it returns {@code null} - */ - public MediaSessionCompat.Token getMediaSessionCompatToken() { - return mMediaSessionCompat == null ? null : mMediaSessionCompat.getSessionToken(); - } - - /* - * Sets up the {@link MediaSessionCompat} for this application. It also handles the audio - * focus. - */ - @SuppressLint("InlinedApi") - private void setUpMediaSession(final MediaInfo info) { - if (!isFeatureEnabled(BaseCastManager.FEATURE_LOCKSCREEN)) { - return; - } - if (mMediaSessionCompat == null) { - mMediaEventReceiver = new ComponentName(mContext, VideoIntentReceiver.class.getName()); - mMediaSessionCompat = new MediaSessionCompat(mContext, "TAG", mMediaEventReceiver, - null); - mMediaSessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS - | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); - mMediaSessionCompat.setActive(true); - mMediaSessionCompat.setCallback(new MediaSessionCompat.Callback() { - @Override - public boolean onMediaButtonEvent(Intent mediaButtonIntent) { - KeyEvent keyEvent = mediaButtonIntent - .getParcelableExtra(Intent.EXTRA_KEY_EVENT); - if (keyEvent != null && (keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE - || keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY)) { - toggle(); - } - return true; - } - - @Override - public void onPlay() { - toggle(); - } - - @Override - public void onPause() { - toggle(); - } - - private void toggle() { - try { - togglePlayback(); - } catch (CastException | TransientNetworkDisconnectionException | - NoConnectionException e) { - LOGE(TAG, "MediaSessionCompat.Callback(): Failed to toggle playback", e); - } - } - }); - } - - mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, - AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); - - mMediaSessionCompat.setPlaybackState(new PlaybackStateCompat.Builder() - .setState(PlaybackStateCompat.STATE_PLAYING, 0, 1.0f) - .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build()); - - // Update the media session's image - updateLockScreenImage(info); - - // update the media session's metadata - updateMediaSessionMetadata(); - - mMediaRouter.setMediaSessionCompat(mMediaSessionCompat); - } - - /* - * Updates lock screen image - */ - private void updateLockScreenImage(final MediaInfo info) { - if (info == null) { - return; - } - setBitmapForLockScreen(info); - } - - /* - * Sets the appropriate {@link Bitmap} for the right size image for lock screen. In ICS and - * JB, the image shown on the lock screen is a small size bitmap but for KitKat, the image is a - * full-screen image so we need to separately handle these two cases. - */ - private void setBitmapForLockScreen(MediaInfo video) { - if (video == null || mMediaSessionCompat == null) { - return; - } - Uri imgUrl = null; - Bitmap bm = null; - List images = video.getMetadata().getImages(); - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) { - if (images.size() > 1) { - imgUrl = images.get(1).getUrl(); - } else if (images.size() == 1) { - imgUrl = images.get(0).getUrl(); - } else if (mContext != null) { - // we don't have a url for image so get a placeholder image from resources - bm = BitmapFactory.decodeResource(mContext.getResources(), - R.drawable.album_art_placeholder_large); - } - } else if (!images.isEmpty()) { - imgUrl = images.get(0).getUrl(); - } else { - // we don't have a url for image so get a placeholder image from resources - bm = BitmapFactory.decodeResource(mContext.getResources(), - R.drawable.album_art_placeholder); - } - if (bm != null) { - MediaMetadataCompat currentMetadata = mMediaSessionCompat.getController().getMetadata(); - MediaMetadataCompat.Builder newBuilder = currentMetadata == null - ? new MediaMetadataCompat.Builder() - : new MediaMetadataCompat.Builder(currentMetadata); - mMediaSessionCompat.setMetadata(newBuilder - .putBitmap(MediaMetadataCompat.METADATA_KEY_ART, bm) - .build()); - } else { - if (mLockScreenFetchTask != null) { - mLockScreenFetchTask.cancel(true); - } - mLockScreenFetchTask = new FetchBitmapTask() { - @Override - protected void onPostExecute(Bitmap bitmap) { - if (mMediaSessionCompat != null) { - MediaMetadataCompat currentMetadata = mMediaSessionCompat.getController() - .getMetadata(); - MediaMetadataCompat.Builder newBuilder = currentMetadata == null - ? new MediaMetadataCompat.Builder() - : new MediaMetadataCompat.Builder(currentMetadata); - mMediaSessionCompat.setMetadata(newBuilder - .putBitmap(MediaMetadataCompat.METADATA_KEY_ART, bitmap) - .build()); - } - mLockScreenFetchTask = null; - } - }; - mLockScreenFetchTask.execute(imgUrl); - } - } - /* - * Updates the playback status of the Media Session - */ - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - private void updateMediaSession(boolean playing) { - if (!isFeatureEnabled(FEATURE_LOCKSCREEN)) { - return; - } - if (!isConnected()) { - return; - } - try { - if ((mMediaSessionCompat == null) && playing) { - setUpMediaSession(getRemoteMediaInformation()); - } - if (mMediaSessionCompat != null) { - int playState = isRemoteStreamLive() ? PlaybackStateCompat.STATE_BUFFERING - : PlaybackStateCompat.STATE_PLAYING; - int state = playing ? playState : PlaybackStateCompat.STATE_PAUSED; - - mMediaSessionCompat.setPlaybackState(new PlaybackStateCompat.Builder() - .setState(state, 0, 1.0f) - .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build()); - } - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to set up MediaSessionCompat due to network issues", e); - } - } - - /* - * On ICS and JB, lock screen metadata is one liner: Title - Album Artist - Album. On KitKat, it - * has two lines: Title , Album Artist - Album - */ - private void updateMediaSessionMetadata() { - if ((mMediaSessionCompat == null) || !isFeatureEnabled(FEATURE_LOCKSCREEN)) { - return; - } - - try { - MediaInfo info = getRemoteMediaInformation(); - if (info == null) { - return; - } - final MediaMetadata mm = info.getMetadata(); - MediaMetadataCompat currentMetadata = mMediaSessionCompat.getController().getMetadata(); - MediaMetadataCompat.Builder newBuilder = currentMetadata == null - ? new MediaMetadataCompat.Builder() - : new MediaMetadataCompat.Builder(currentMetadata); - MediaMetadataCompat metadata = newBuilder - // used in lock screen for pre-lollipop - .putString(MediaMetadataCompat.METADATA_KEY_TITLE, - mm.getString(MediaMetadata.KEY_TITLE)) - // used in lock screen for pre-lollipop - .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, - mContext.getResources().getString( - R.string.ccl_casting_to_device, getDeviceName())) - // used in MediaRouteController dialog - .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, - mm.getString(MediaMetadata.KEY_TITLE)) - // used in MediaRouteController dialog - .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, - mm.getString(MediaMetadata.KEY_SUBTITLE)) - .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, - info.getStreamDuration()) - .build(); - mMediaSessionCompat.setMetadata(metadata); - - Uri iconUri = mm.hasImages() ? mm.getImages().get(0).getUrl() : null; - if (iconUri == null) { - Bitmap bm = BitmapFactory.decodeResource( - mContext.getResources(), R.drawable.album_art_placeholder); - mMediaSessionCompat.setMetadata(newBuilder - .putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, bm) - .build()); - } else { - if (mMediaSessionIconFetchTask != null) { - mMediaSessionIconFetchTask.cancel(true); - } - mMediaSessionIconFetchTask = new FetchBitmapTask() { - @Override - protected void onPostExecute(Bitmap bitmap) { - if (mMediaSessionCompat != null) { - MediaMetadataCompat currentMetadata = mMediaSessionCompat - .getController().getMetadata(); - MediaMetadataCompat.Builder newBuilder = currentMetadata == null - ? new MediaMetadataCompat.Builder() - : new MediaMetadataCompat.Builder(currentMetadata); - mMediaSessionCompat.setMetadata(newBuilder.putBitmap( - MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, bitmap).build()); - } - mMediaSessionIconFetchTask = null; - } - }; - mMediaSessionIconFetchTask.execute(iconUri); - } - - } catch (NotFoundException e) { - LOGE(TAG, "Failed to update Media Session due to resource not found", e); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to update Media Session due to network issues", e); - } - } - - /* - * Clears Media Session - */ - public void clearMediaSession() { - LOGD(TAG, "clearMediaSession()"); - if (isFeatureEnabled(FEATURE_LOCKSCREEN)) { - if (mLockScreenFetchTask != null) { - mLockScreenFetchTask.cancel(true); - } - if (mMediaSessionIconFetchTask != null) { - mMediaSessionIconFetchTask.cancel(true); - } - mAudioManager.abandonAudioFocus(null); - if (mMediaSessionCompat != null) { - mMediaSessionCompat.setMetadata(null); - PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder() - .setState(PlaybackStateCompat.STATE_NONE, 0, 1.0f).build(); - mMediaSessionCompat.setPlaybackState(playbackState); - mMediaSessionCompat.release(); - mMediaSessionCompat.setActive(false); - mMediaSessionCompat = null; - } - } - } - - /** - * Registers an - * {@link com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumer} - * interface with this class. Registered listeners will be notified of changes to a variety of - * lifecycle and media status changes through the callbacks that the interface provides. - * - * @see VideoCastConsumerImpl - */ - public synchronized void addVideoCastConsumer(VideoCastConsumer listener) { - if (listener != null) { - addBaseCastConsumer(listener); - mVideoConsumers.add(listener); - LOGD(TAG, "Successfully added the new CastConsumer listener " + listener); - } - } - - /** - * Unregisters an - * {@link com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumer}. - */ - public synchronized void removeVideoCastConsumer(VideoCastConsumer listener) { - if (listener != null) { - removeBaseCastConsumer(listener); - mVideoConsumers.remove(listener); - } - } - - /** - * Adds a new {@link IMiniController} component. Callers need to provide their own - * {@link OnMiniControllerChangedListener}. - * - * @see {@link #removeMiniController(IMiniController)} - */ - public void addMiniController(IMiniController miniController, - OnMiniControllerChangedListener onChangedListener) { - if (miniController != null) { - boolean result; - synchronized (mMiniControllers) { - result = mMiniControllers.add(miniController); - } - if (result) { - miniController.setOnMiniControllerChangedListener(onChangedListener == null ? this - : onChangedListener); - try { - if (isConnected() && isRemoteMediaLoaded()) { - updateMiniController(miniController); - miniController.setVisibility(View.VISIBLE); - } - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to get the status of media playback on receiver", e); - } - LOGD(TAG, "Successfully added the new MiniController " + miniController); - } else { - LOGD(TAG, "Attempting to adding " + miniController + " but it was already " - + "registered, skipping this step"); - } - } - } - - /** - * Adds a new {@link IMiniController} component and assigns {@link VideoCastManager} as the - * {@link OnMiniControllerChangedListener} for this component. - */ - public void addMiniController(IMiniController miniController) { - addMiniController(miniController, null); - } - - /** - * Removes a {@link IMiniController} listener from the list of listeners. - */ - public void removeMiniController(IMiniController listener) { - if (listener != null) { - listener.setOnMiniControllerChangedListener(null); - synchronized (mMiniControllers) { - mMiniControllers.remove(listener); - } - } - } - - @Override - protected void onDeviceUnselected() { - stopNotificationService(); - detachMediaChannel(); - removeDataChannel(); - mState = MediaStatus.PLAYER_STATE_IDLE; - } - - @Override - protected Builder getCastOptionBuilder(CastDevice device) { - Builder builder = Cast.CastOptions.builder(mSelectedCastDevice, new CastListener()); - if (isFeatureEnabled(FEATURE_DEBUGGING)) { - builder.setVerboseLoggingEnabled(true); - } - return builder; - } - - @Override - public void onConnectionFailed(ConnectionResult result) { - super.onConnectionFailed(result); - updateMediaSession(false); - stopNotificationService(); - } - - @Override - public void onDisconnected(boolean stopAppOnExit, boolean clearPersistedConnectionData, - boolean setDefaultRoute) { - super.onDisconnected(stopAppOnExit, clearPersistedConnectionData, setDefaultRoute); - updateMiniControllersVisibility(false); - if (clearPersistedConnectionData && !mConnectionSuspended) { - clearMediaSession(); - } - mState = MediaStatus.PLAYER_STATE_IDLE; - mMediaQueue = null; - } - - @Override - protected MediaRouteDialogFactory getMediaRouteDialogFactory() { - return new VideoMediaRouteDialogFactory(); - } - - class CastListener extends Cast.Listener { - - /* - * (non-Javadoc) - * @see com.google.android.gms.cast.Cast.Listener#onApplicationDisconnected (int) - */ - @Override - public void onApplicationDisconnected(int statusCode) { - VideoCastManager.this.onApplicationDisconnected(statusCode); - } - - /* - * (non-Javadoc) - * @see com.google.android.gms.cast.Cast.Listener#onApplicationStatusChanged () - */ - @Override - public void onApplicationStatusChanged() { - VideoCastManager.this.onApplicationStatusChanged(); - } - - @Override - public void onVolumeChanged() { - VideoCastManager.this.onVolumeChanged(); - } - } - - @Override - public void onFailed(int resourceId, int statusCode) { - LOGD(TAG, "onFailed: " + mContext.getString(resourceId) + ", code: " + statusCode); - super.onFailed(resourceId, statusCode); - } - - /** - * Returns the class for the full screen activity that can control the remote media playback. - * This activity will also be invoked from the notification shade. If {@code null} is returned, - * this library will use a default implementation. - * - * @see {@link VideoCastControllerActivity} - */ - public Class getTargetActivity() { - return mTargetActivity; - } - - /** - * Clients can call this method to delegate handling of the volume. Clients should override - * {@code dispatchEvent} and call this method: - *
-     public boolean dispatchKeyEvent(KeyEvent event) {
-         if (mCastManager.onDispatchVolumeKeyEvent(event, VOLUME_DELTA)) {
-            return true;
-         }
-         return super.dispatchKeyEvent(event);
-     }
-     * 
- * @param event The dispatched event. - * @param volumeDelta The amount by which volume should be increased or decreased in each step - * @return true if volume is handled by the library, false otherwise. - */ - public boolean onDispatchVolumeKeyEvent(KeyEvent event, double volumeDelta) { - if (isConnected()) { - boolean isKeyDown = event.getAction() == KeyEvent.ACTION_DOWN; - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_VOLUME_UP: - if (changeVolume(volumeDelta, isKeyDown)) { - return true; - } - break; - case KeyEvent.KEYCODE_VOLUME_DOWN: - if (changeVolume(-volumeDelta, isKeyDown)) { - return true; - } - break; - } - } - return false; - } - - private boolean changeVolume(double volumeIncrement, boolean isKeyDown) { - if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) - && getPlaybackStatus() == MediaStatus.PLAYER_STATE_PLAYING - && isFeatureEnabled(BaseCastManager.FEATURE_LOCKSCREEN)) { - return false; - } - - if (isKeyDown) { - try { - adjustVolume(volumeIncrement); - } catch (CastException | TransientNetworkDisconnectionException | - NoConnectionException e) { - LOGE(TAG, "Failed to change volume", e); - } - } - return true; - } - - /** - * Sets the volume step, i.e. the fraction by which volume will increase or decrease each time - * user presses the hard volume buttons on the device. - * - * @param volumeStep Should be a double between 0 and 1, inclusive. - */ - public VideoCastManager setVolumeStep(double volumeStep) { - if ((volumeStep > 1) || (volumeStep < 0)) { - throw new IllegalArgumentException("Volume Step should be between 0 and 1, inclusive"); - } - mVolumeStep = volumeStep; - return this; - } - - /** - * Returns the volume step. The default value is {@code DEFAULT_VOLUME_STEP}. - */ - public double getVolumeStep() { - return mVolumeStep; - } - - /** - * Set the live stream duration; this is purely used in the reconnection logic. If this method - * is not called, the default value {@code DEFAULT_LIVE_STREAM_DURATION_MS} is used. - * - * @param duration Duration, specified in milliseconds. - */ - public void setLiveStreamDuration(long duration) { - mLiveStreamDuration = duration; - } - - /** - * Sets the active tracks for the currently loaded media. - */ - public void setActiveTrackIds(long[] trackIds) { - if (mRemoteMediaPlayer == null || mRemoteMediaPlayer.getMediaInfo() == null) { - return; - } - mRemoteMediaPlayer.setActiveMediaTracks(mApiClient, trackIds) - .setResultCallback(new ResultCallback() { - @Override - public void onResult(MediaChannelResult mediaChannelResult) { - LOGD(TAG, "Setting track result was successful? " - + mediaChannelResult.getStatus().isSuccess()); - if (!mediaChannelResult.getStatus().isSuccess()) { - LOGD(TAG, "Failed since: " + mediaChannelResult.getStatus() - + " and status code:" + mediaChannelResult.getStatus() - .getStatusCode()); - } - } - }); - } - - /** - * Sets or updates the style of the Text Track. - */ - public void setTextTrackStyle(TextTrackStyle style) { - mRemoteMediaPlayer.setTextTrackStyle(mApiClient, style) - .setResultCallback(new ResultCallback() { - @Override - public void onResult(MediaChannelResult result) { - if (!result.getStatus().isSuccess()) { - onFailed(R.string.ccl_failed_to_set_track_style, - result.getStatus().getStatusCode()); - } - } - }); - for (VideoCastConsumer consumer : mVideoConsumers) { - try { - consumer.onTextTrackStyleChanged(style); - } catch (Exception e) { - LOGE(TAG, "onTextTrackStyleChanged(): Failed to inform " + consumer, e); - } - } - } - - /** - * Signals a change in the Text Track style. Clients should not call this directly. - */ - public void onTextTrackStyleChanged(TextTrackStyle style) { - LOGD(TAG, "onTextTrackStyleChanged() reached"); - if (mRemoteMediaPlayer == null || mRemoteMediaPlayer.getMediaInfo() == null) { - return; - } - mRemoteMediaPlayer.setTextTrackStyle(mApiClient, style) - .setResultCallback(new ResultCallback() { - @Override - public void onResult(MediaChannelResult result) { - if (!result.getStatus().isSuccess()) { - onFailed(R.string.ccl_failed_to_set_track_style, - result.getStatus().getStatusCode()); - } - } - }); - for (VideoCastConsumer consumer : mVideoConsumers) { - try { - consumer.onTextTrackStyleChanged(style); - } catch (Exception e) { - LOGE(TAG, "onTextTrackStyleChanged(): Failed to inform " + consumer, e); - } - } - } - - /** - * Signals a change in the Text Track on/off state. Clients should not call this directly. - */ - public void onTextTrackEnabledChanged(boolean isEnabled) { - LOGD(TAG, "onTextTrackEnabledChanged() reached"); - if (!isEnabled) { - setActiveTrackIds(new long[]{}); - } - - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onTextTrackEnabledChanged(isEnabled); - } - } - - /** - * Signals a change in the Text Track locale. Clients should not call this directly. - */ - public void onTextTrackLocaleChanged(Locale locale) { - LOGD(TAG, "onTextTrackLocaleChanged() reached"); - for (VideoCastConsumer consumer : mVideoConsumers) { - consumer.onTextTrackLocaleChanged(locale); - } - } - - @SuppressLint("NewApi") - private void registerCaptionListener(final Context context) { - if (Utils.IS_KITKAT_OR_ABOVE) { - CaptioningManager captioningManager = - (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE); - captioningManager.addCaptioningChangeListener( - new CaptioningManager.CaptioningChangeListener() { - @Override - public void onEnabledChanged(boolean enabled) { - onTextTrackEnabledChanged(enabled); - } - - @Override - public void onUserStyleChanged( - CaptioningManager.CaptionStyle userStyle) { - onTextTrackStyleChanged(mTrackManager.getTextTrackStyle()); - } - - @Override - public void onFontScaleChanged(float fontScale) { - onTextTrackStyleChanged(mTrackManager.getTextTrackStyle()); - } - - @Override - public void onLocaleChanged(Locale locale) { - onTextTrackLocaleChanged(locale); - } - } - ); - } - } - - /** - * Updates the summary of the captions between "on" and "off" based on the user selected - * preferences. This can be called by the caller application when they add captions settings to - * their preferences. Preferably this should be called in the {@code onResume()} of the - * PreferenceActivity so that it gets updated when needed. - */ - public void updateCaptionSummary(String captionScreenKey, PreferenceScreen preferenceScreen) { - int status = R.string.ccl_info_na; - if (isFeatureEnabled(FEATURE_CAPTIONS_PREFERENCE)) { - status = mTrackManager.isCaptionEnabled() ? R.string.ccl_on : R.string.ccl_off; - } - preferenceScreen.findPreference(captionScreenKey) - .setSummary(status); - } - - /** - * Returns the instance of {@link TracksPreferenceManager} that is being used. - */ - public TracksPreferenceManager getTracksPreferenceManager() { - return mTrackManager; - } - - /** - * Returns the list of current active tracks. If there is no remote media, then this will - * return null. - */ - public long[] getActiveTrackIds() { - if (mRemoteMediaPlayer != null && mRemoteMediaPlayer.getMediaStatus() != null) { - return mRemoteMediaPlayer.getMediaStatus().getActiveTrackIds(); - } - return null; - } - - /** - * Adds an - * {@link com.google.android.libraries.cast.companionlibrary.cast.tracks.OnTracksSelectedListener} // NOLINT - * to the lis of listeners. - */ - public void addTracksSelectedListener(OnTracksSelectedListener listener) { - if (listener != null) { - mTracksSelectedListeners.add(listener); - } - } - - /** - * Removes an - * {@link com.google.android.libraries.cast.companionlibrary.cast.tracks.OnTracksSelectedListener} // NOLINT - * from the lis of listeners. - */ - public void removeTracksSelectedListener(OnTracksSelectedListener listener) { - if (listener != null) { - mTracksSelectedListeners.remove(listener); - } - } - - /** - * Notifies all the - * {@link com.google.android.libraries.cast.companionlibrary.cast.tracks.OnTracksSelectedListener} // NOLINT - * that the set of active tracks has changed. - * - * @param tracks the set of active tracks. Must be {@code non-null} but can be an empty list. - */ - public void notifyTracksSelectedListeners(List tracks) { - if (tracks == null) { - throw new IllegalArgumentException("tracks must not be null"); - } - for (OnTracksSelectedListener listener : mTracksSelectedListeners) { - listener.onTracksSelected(tracks); - } - } - - public final MediaQueue getMediaQueue() { - return mMediaQueue; - } - - private void stopProgressTimer() { - LOGD(TAG, "Stopped TrickPlay Timer"); - if (mProgressTask != null) { - mProgressTask.cancel(); - mProgressTask = null; - } - if (mProgressTimer != null) { - mProgressTimer.cancel(); - mProgressTimer = null; - } - } - - private void restartProgressTimer() { - stopProgressTimer(); - mProgressTimer = new Timer(); - mProgressTask = new UpdateProgressTask(); - mProgressTimer.scheduleAtFixedRate(mProgressTask, 100, PROGRESS_UPDATE_INTERVAL_MS); - LOGD(TAG, "Restarted Progress Timer"); - } - - private class UpdateProgressTask extends TimerTask { - - @Override - public void run() { - int currentPos; - if (mState == MediaStatus.PLAYER_STATE_BUFFERING || !isConnected() - || mRemoteMediaPlayer == null) { - return; - } - try { - int duration = (int) getMediaDuration(); - if (duration > 0) { - currentPos = (int) getCurrentMediaPosition(); - updateProgress(currentPos, duration); - } - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to update the progress tracker due to network issues", e); - } - } - } - - /** - * Note: This is called on a worker thread - */ - private void updateProgress(int currentPosition, int duration) { - synchronized (mMiniControllers) { - for (final IMiniController controller : mMiniControllers) { - controller.setProgress(currentPosition, duration); - } - } - } - - /** - * Sets the policy to be used for the visibility of skip forward/backward on the {@link - * VideoCastControllerActivity}. Note that the new policy is enforced the next time that - * activity is opened and does not apply to the currently runnig one, if any. - * - * @param policy can be one of {@link VideoCastController#NEXT_PREV_VISIBILITY_POLICY_DISABLED}, - * {@link VideoCastController#NEXT_PREV_VISIBILITY_POLICY_HIDDEN} or - * {@link VideoCastController#NEXT_PREV_VISIBILITY_POLICY_ALWAYS}. - */ - public void setNextPreviousVisibilityPolicy(final int policy) { - switch(policy) { - case VideoCastController.NEXT_PREV_VISIBILITY_POLICY_DISABLED: - case VideoCastController.NEXT_PREV_VISIBILITY_POLICY_ALWAYS: - case VideoCastController.NEXT_PREV_VISIBILITY_POLICY_HIDDEN: - mPreferenceAccessor.saveIntToPreference(PREFS_KEY_NEXT_PREV_POLICY, policy); - return; - default: - LOGD(TAG, "Invalid value for the NextPreviousVisibilityPolicy was requested"); - } - throw new IllegalArgumentException( - "Invalid value for the NextPreviousVisibilityPolicy was requested"); - } - - /** - * Turns on/off the immersive mode for the full screen cast controller - * {@link VideoCastControllerActivity}. Calls to this will take effect the next time that - * activity is launched so it is recommended to be called early in the application lifecycle. - */ - public void setCastControllerImmersive(boolean mode) { - mPreferenceAccessor.saveBooleanToPreference(PREFS_KEY_IMMERSIVE_MODE, mode); - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/BaseCastConsumer.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/BaseCastConsumer.java deleted file mode 100644 index be67c0347..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/BaseCastConsumer.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.callbacks; - -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.OnFailedListener; - -import android.support.v7.media.MediaRouter.RouteInfo; - -/** - * An interface for receiving callbacks around the connectivity status to a Cast device. - */ -public interface BaseCastConsumer extends OnFailedListener { - - /** - * Called when connection is established - */ - void onConnected(); - - /** - * Called when the client is temporarily in a disconnected state. This can happen if there is a - * problem with the remote service (e.g. a crash or resource problem causes it to be killed by - * the system). When called, all requests have been canceled and no outstanding listeners will - * be executed. Applications could disable UI components that require the service, and wait for - * a call to onConnectivityRecovered() to re-enable them. - * - * @param cause The reason for the disconnection. Defined by constants CAUSE_*. - */ - void onConnectionSuspended(int cause); - - /** - * Called when a device is disconnected - */ - void onDisconnected(); - - /** - * Called when a device is disconnected or fails to reconnect and provides a reason for the - * disconnect or failure. - * - * @param reason The failure/disconnect reason; can be one of the following: - *
    - *
  • {@link BaseCastManager#DISCONNECT_REASON_APP_NOT_RUNNING}
  • - *
  • {@link BaseCastManager#DISCONNECT_REASON_EXPLICIT}
  • - *
  • {@link BaseCastManager#DISCONNECT_REASON_CONNECTIVITY}
  • - *
  • {@link BaseCastManager#DISCONNECT_REASON_OTHER}
  • - *
@BaseCastManager.DISCONNECT_REASON - */ - void onDisconnectionReason(@BaseCastManager.DISCONNECT_REASON int reason); - - /** - * Called when an error happens while connecting to a device. - */ - void onConnectionFailed(ConnectionResult result); - - /** - * Called when the MediaRouterCallback detects a non-default route. - */ - void onCastDeviceDetected(RouteInfo info); - - /** - * Called when the number of cast devices present on the network changes from 0 to a positive - * number or vice versa. Can be used, for example, to control the visibility of {@link - * android.support.v7.app.MediaRouteButton} - * - * @param castPresent set to {@code true} if at least one device becomes available, - * {@code false} otherwise - */ - void onCastAvailabilityChanged(boolean castPresent); - - /** - * Called after reconnection is established following a temporary disconnection, say, due to - * network issues. - */ - void onConnectivityRecovered(); - - /** - * Called when visibility of the application has changed. - */ - void onUiVisibilityChanged(boolean visible); - - /** - * Called when the status of reconnection changes. - * @param status - */ - void onReconnectionStatusChanged(int status); - - /** - * Called when a device is selected/unselected. - * @param device - */ - void onDeviceSelected(CastDevice device); -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/BaseCastConsumerImpl.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/BaseCastConsumerImpl.java deleted file mode 100644 index 09cef6c6d..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/BaseCastConsumerImpl.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.callbacks; - -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager; - -import android.support.v7.media.MediaRouter.RouteInfo; - -/** - * A no-op implementation of the {@link BaseCastConsumer} - */ -public class BaseCastConsumerImpl implements BaseCastConsumer { - - @Override - public void onConnected() { - // no-op - } - - @Override - public void onDisconnected() { - // no-op - } - - @Override - public void onDisconnectionReason(@BaseCastManager.DISCONNECT_REASON int reason) { - // no-op - } - - @Override - public void onConnectionFailed(ConnectionResult result) { - // no-op - } - - @Override - public void onCastDeviceDetected(RouteInfo info) { - // no-op - } - - @Override - public void onCastAvailabilityChanged(boolean castPresent) { - // no-op - } - - @Override - public void onConnectionSuspended(int cause) { - // no-op - } - - @Override - public void onConnectivityRecovered() { - // no-op - } - - @Override - public void onUiVisibilityChanged(boolean visible) { - // no-op - } - - @Override - public void onReconnectionStatusChanged(int status) { - // no-op - } - - @Override - public void onDeviceSelected(CastDevice device) { - // no-op - } - - @Override - public void onFailed(int resourceId, int statusCode) { - // no-op - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/DataCastConsumer.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/DataCastConsumer.java deleted file mode 100644 index 367e9e687..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/DataCastConsumer.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.callbacks; - -import com.google.android.gms.cast.ApplicationMetadata; -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.common.api.Status; - -/** - * An interface that extends {@link BaseCastConsumer} and adds callbacks for application lifecycle - * and success or failure of message exchange with a cast device. - */ -public interface DataCastConsumer extends BaseCastConsumer { - /** - * Called when the application is successfully launched or joined. Upon successful connection, a - * session ID is returned. wasLaunched indicates if the application was launched or - * joined. - */ - void onApplicationConnected(ApplicationMetadata appMetadata, - String applicationStatus, String sessionId, boolean wasLaunched); - - /** - * Called when the current application has stopped - */ - void onApplicationDisconnected(int errorCode); - - /** - * Called when an attempt to stop a receiver application has failed. - */ - void onApplicationStopFailed(int errorCode); - - /** - * Called when an application launch has failed. Failure reason is captured in the - * errorCode argument. Here is a list of possible values: - *
    - *
  • 4 : Application not found - *
  • 5 : Application not currently running - *
  • 6 : Application already running - *
- */ - void onApplicationConnectionFailed(int errorCode); - - /** - * Called when application status changes. The argument is built by the receiver - */ - void onApplicationStatusChanged(String appStatus); - - /** - * Called when the device's volume is changed. Note not to mix that with the stream's volume - */ - void onVolumeChanged(double value, boolean isMute); - - /** - * Called when a message is received from a given {@link CastDevice} for a given - * namespace. - */ - void onMessageReceived(CastDevice castDevice, String namespace, String message); - - /** - * Called when there is an error sending a message. - * - * @param status The status of the result - */ - void onMessageSendFailed(Status status); - - /** - * Called when this callback is removed from the Cast object. - * - * @param castDevice The castDevice from where the message originated. - * @param namespace The associated namespace of the removed listener. - */ - void onRemoved(CastDevice castDevice, String namespace); -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/DataCastConsumerImpl.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/DataCastConsumerImpl.java deleted file mode 100644 index 54ecba6c6..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/DataCastConsumerImpl.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.callbacks; - -import com.google.android.gms.cast.ApplicationMetadata; -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.common.api.Status; - -/** - * A no-op implementation of the {@link DataCastConsumer} - */ -public class DataCastConsumerImpl extends BaseCastConsumerImpl implements DataCastConsumer { - - @Override - public void onApplicationConnected(ApplicationMetadata appMetadata, String applicationStatus, - String sessionId, boolean wasLaunched) { - } - - @Override - public void onApplicationDisconnected(int errorCode) { - } - - @Override - public void onApplicationStopFailed(int errorCode) { - } - - @Override - public void onApplicationConnectionFailed(int errorCode) { - } - - @Override - public void onApplicationStatusChanged(String appStatus) { - } - - @Override - public void onVolumeChanged(double value, boolean isMute) { - } - - @Override - public void onMessageReceived(CastDevice castDevice, String namespace, String message) { - } - - @Override - public void onMessageSendFailed(Status status) { - } - - @Override - public void onRemoved(CastDevice castDevice, String namespace) { - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/VideoCastConsumer.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/VideoCastConsumer.java deleted file mode 100644 index bbcb2f172..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/VideoCastConsumer.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.callbacks; - -import com.google.android.gms.cast.ApplicationMetadata; -import com.google.android.gms.cast.Cast; -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.cast.MediaQueueItem; -import com.google.android.gms.cast.TextTrackStyle; - -import android.view.View; - -import java.util.List; -import java.util.Locale; - -/** - * An interface that extends {@link BaseCastConsumer} and - * adds callbacks related to the lifecycle of a video-centric application. - */ -public interface VideoCastConsumer extends BaseCastConsumer { - - /** - * Called when the application is successfully launched or joined. Upon successful connection, a - * session ID is returned. wasLaunched indicates if the application was launched or - * joined. - */ - void onApplicationConnected(ApplicationMetadata appMetadata, - String sessionId, boolean wasLaunched); - - /** - * Called when an application launch has failed. Failure reason is captured in the - * errorCode argument. Here is a list of possible values: - *
    - *
  • {@link com.google.android.gms.cast.CastStatusCodes#APPLICATION_NOT_FOUND} - *
  • {@link com.google.android.gms.cast.CastStatusCodes#APPLICATION_NOT_RUNNING} - *
- */ - void onApplicationConnectionFailed(int errorCode); - - /** - * Called when an attempt to stop a receiver application has failed. - */ - void onApplicationStopFailed(int errorCode); - - /** - * Called when application status changes. The argument is built by the receiver - */ - void onApplicationStatusChanged(String appStatus); - - /** - * Called when the device's volume is changed. Note not to mix that with the stream's volume - */ - void onVolumeChanged(double value, boolean isMute); - - /** - * Called when the current application has stopped - */ - void onApplicationDisconnected(int errorCode); - - /** - * Called when metadata of the current media changes - */ - void onRemoteMediaPlayerMetadataUpdated(); - - /** - * Called when media's status updated. - */ - void onRemoteMediaPlayerStatusUpdated(); - - /** - * Called when the data channel callback is removed from the {@link Cast} object. - */ - void onNamespaceRemoved(); - - /** - * Called when there is an error sending a message. - * - * @param errorCode An error code indicating the reason for the disconnect. One of the error - * constants defined in CastErrors. - */ - void onDataMessageSendFailed(int errorCode); - - /** - * Called when a message is received from a given {@link CastDevice}. - * - * @param message The received payload for the message. - */ - void onDataMessageReceived(String message); - - /** - * Called when the style of the text caption has changed - * @param style The new style - */ - void onTextTrackStyleChanged(TextTrackStyle style); - - /** - * Called when Close Captions on/off is changed - */ - void onTextTrackEnabledChanged(boolean isEnabled); - - /** - * Called when the locale for the caption has changed - */ - void onTextTrackLocaleChanged(Locale locale); - - /** - * A callback to inform the client of the result of a - * {@link com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager#loadMedia} - * request - * - * @param statusCode The status code that represents the success or failure of the request. - * The possible value are defined in - * {@link com.google.android.gms.common.api.CommonStatusCodes} or - * {@link com.google.android.gms.cast.CastStatusCodes}. - * {@link com.google.android.gms.cast.CastStatusCodes#SUCCESS} signifies a successful request. - */ - void onMediaLoadResult(int statusCode); - - /** - * A callback to inform the clients that queue has been updated. - * - * @param queueItems The updated list of queue items - * @param item The item that was updated - * @param repeatMode The repeat mode of the updated item - * @param shuffle The shuffle status of the updated item - */ - void onMediaQueueUpdated(List queueItems, MediaQueueItem item, - int repeatMode, boolean shuffle); - - /** - * A callback to inform the client that pre-loading of a queue item has started - * - * @param item The queue item that the receiver has started to preload (if supported) - */ - void onRemoteMediaPreloadStatusUpdated(MediaQueueItem item); - - /** - * A callback to inform the clients that the "Play" button for the upcoming item has been - * clicked, - * - * @param view The view that was clicked - * @param upcomingItem The queue item that represents the item that is being preloaded - */ - void onUpcomingPlayClicked(View view, MediaQueueItem upcomingItem); - - /** - * A callback to inform the clients that the "Stop" button for the upcoming item has been - * clicked. - * - * @param view The view that was clicked - * @param upcomingItem The queue item that represents the item that is being preloaded - */ - void onUpcomingStopClicked(View view, MediaQueueItem upcomingItem); - - /** - * A callback to inform the client of the result of a queueing operation. - * - * @param operationId Identifier of the operation, see - * {@code VideoCastManager#QUEUE_OPERATION_*} - * @param statusCode The status code that represents the success or failure of the request. - * The possible value are defined in - * {@link com.google.android.gms.common.api.CommonStatusCodes} or - * {@link com.google.android.gms.cast.CastStatusCodes}. - * {@link com.google.android.gms.cast.CastStatusCodes#SUCCESS} signifies a successful request. - */ - void onMediaQueueOperationResult(int operationId, int statusCode); -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/VideoCastConsumerImpl.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/VideoCastConsumerImpl.java deleted file mode 100644 index 3977edc58..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/callbacks/VideoCastConsumerImpl.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.callbacks; - -import com.google.android.gms.cast.ApplicationMetadata; -import com.google.android.gms.cast.MediaQueueItem; -import com.google.android.gms.cast.TextTrackStyle; - -import android.view.View; - -import java.util.List; -import java.util.Locale; - -/** - * This is a no-ops implementation of {@link VideoCastConsumer} so that the clients that need to - * (partially) implement {@link VideoCastConsumer} can extend this class and only override the - * desired methods. - */ -public class VideoCastConsumerImpl extends BaseCastConsumerImpl - implements VideoCastConsumer { - - @Override - public void onApplicationConnected(ApplicationMetadata appMetadata, - String sessionId, boolean wasLaunched) { - } - - @Override - public void onApplicationConnectionFailed(int errorCode) { - } - - @Override - public void onApplicationStatusChanged(String appStatus) { - } - - @Override - public void onApplicationDisconnected(int errorCode) { - } - - @Override - public void onRemoteMediaPlayerMetadataUpdated() { - } - - @Override - public void onRemoteMediaPlayerStatusUpdated() { - } - - @Override - public void onVolumeChanged(double value, boolean isMute) { - } - - @Override - public void onApplicationStopFailed(int errorCode) { - } - - @Override - public void onNamespaceRemoved() { - } - - @Override - public void onDataMessageSendFailed(int errorCode) { - } - - @Override - public void onDataMessageReceived(String message) { - } - - @Override - public void onTextTrackStyleChanged(TextTrackStyle style) { - } - - @Override - public void onTextTrackEnabledChanged(boolean isEnabled) { - } - - @Override - public void onTextTrackLocaleChanged(Locale locale) { - } - - @Override - public void onMediaLoadResult(int statusCode) { - } - - @Override - public void onMediaQueueUpdated(List queueItems, MediaQueueItem item, - int repeatMode, boolean shuffle) { - } - - @Override - public void onRemoteMediaPreloadStatusUpdated(MediaQueueItem item) { - } - - @Override - public void onUpcomingPlayClicked(View v, MediaQueueItem item) { - } - - @Override - public void onUpcomingStopClicked(View view, MediaQueueItem upcomingItem) { - } - - @Override - public void onMediaQueueOperationResult(int operationId, int statusCode) { - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/dialog/video/VideoMediaRouteControllerDialog.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/dialog/video/VideoMediaRouteControllerDialog.java deleted file mode 100755 index 4d8e60616..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/dialog/video/VideoMediaRouteControllerDialog.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.dialog.video; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.gms.cast.MediaInfo; -import com.google.android.gms.cast.MediaMetadata; -import com.google.android.gms.cast.MediaStatus; -import com.google.android.libraries.cast.companionlibrary.R; -import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager; -import com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumerImpl; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.utils.FetchBitmapTask; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Bundle; -import android.support.v7.app.MediaRouteControllerDialog; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; - -/** - * A custom {@link MediaRouteControllerDialog} that provides an album art, a play/pause button and - * the ability to take user to the target activity when the album art is tapped. - */ -public class VideoMediaRouteControllerDialog extends MediaRouteControllerDialog { - - private static final String TAG = - LogUtils.makeLogTag(VideoMediaRouteControllerDialog.class); - - private ImageView mIcon; - private ImageView mPausePlay; - private TextView mTitle; - private TextView mSubTitle; - private TextView mEmptyText; - private ProgressBar mLoading; - private Uri mIconUri; - private VideoCastManager mCastManager; - protected int mState; - private VideoCastConsumerImpl mCastConsumerImpl; - private Drawable mPauseDrawable; - private Drawable mPlayDrawable; - private Drawable mStopDrawable; - private Context mContext; - private View mIconContainer; - private View mTextContainer; - private FetchBitmapTask mFetchBitmap; - - private int mStreamType; - - public VideoMediaRouteControllerDialog(Context context, int theme) { - super(context, theme); - } - - /** - * Creates a new VideoMediaRouteControllerDialog with the given context. - */ - public VideoMediaRouteControllerDialog(Context context) { - super(context, R.style.CCLCastDialog); - try { - this.mContext = context; - mCastManager = VideoCastManager.getInstance(); - mState = mCastManager.getPlaybackStatus(); - mCastConsumerImpl = new VideoCastConsumerImpl() { - - @Override - public void onRemoteMediaPlayerStatusUpdated() { - mState = mCastManager.getPlaybackStatus(); - updatePlayPauseState(mState); - } - - /* - * (non-Javadoc) - * @see - * com.google.android.libraries.cast.companionlibrary.cast.VideoCastConsumerImpl - * #onMediaChannelMetadataUpdated() - */ - @Override - public void onRemoteMediaPlayerMetadataUpdated() { - updateMetadata(); - } - - }; - mCastManager.addVideoCastConsumer(mCastConsumerImpl); - mPauseDrawable = context.getResources() - .getDrawable(R.drawable.ic_media_route_controller_pause); - mPlayDrawable = context.getResources() - .getDrawable(R.drawable.ic_media_route_controller_play); - mStopDrawable = context.getResources() - .getDrawable(R.drawable.ic_media_route_controller_stop); - } catch (IllegalStateException e) { - LOGE(TAG, "Failed to update the content of dialog", e); - } - } - - @Override - protected void onStop() { - if (mCastManager != null) { - mCastManager.removeVideoCastConsumer(mCastConsumerImpl); - mCastManager = null; - } - if (mFetchBitmap != null) { - mFetchBitmap.cancel(true); - mFetchBitmap = null; - } - super.onStop(); - } - - /* - * Hides/show the icon and metadata and play/pause if there is no media - */ - private void hideControls(boolean hide, int resId) { - int visibility = hide ? View.GONE : View.VISIBLE; - mIcon.setVisibility(visibility); - mIconContainer.setVisibility(visibility); - mTextContainer.setVisibility(visibility); - mEmptyText.setText(resId == 0 ? R.string.ccl_no_media_info : resId); - mEmptyText.setVisibility(hide ? View.VISIBLE : View.GONE); - if (hide) { - mPausePlay.setVisibility(visibility); - } - } - - private void updateMetadata() { - MediaInfo info; - try { - info = mCastManager.getRemoteMediaInformation(); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - hideControls(true, R.string.ccl_failed_no_connection_short); - return; - } - if (info == null) { - hideControls(true, R.string.ccl_no_media_info); - return; - } - mStreamType = info.getStreamType(); - hideControls(false, 0); - MediaMetadata mm = info.getMetadata(); - mTitle.setText(mm.getString(MediaMetadata.KEY_TITLE)); - mSubTitle.setText(mm.getString(MediaMetadata.KEY_SUBTITLE)); - setIcon(mm.hasImages() ? mm.getImages().get(0).getUrl() : null); - } - - public void setIcon(Uri uri) { - if (mIconUri != null && mIconUri.equals(uri)) { - return; - } - mIconUri = uri; - if (uri == null) { - Bitmap bm = BitmapFactory.decodeResource( - mContext.getResources(), R.drawable.album_art_placeholder); - mIcon.setImageBitmap(bm); - return; - } - if (mFetchBitmap != null) { - mFetchBitmap.cancel(true); - } - - mFetchBitmap = new FetchBitmapTask() { - @Override - protected void onPostExecute(Bitmap bitmap) { - mIcon.setImageBitmap(bitmap); - if (this == mFetchBitmap) { - mFetchBitmap = null; - } - } - }; - - mFetchBitmap.execute(mIconUri); - } - - private void updatePlayPauseState(int state) { - if (mPausePlay != null) { - switch (state) { - case MediaStatus.PLAYER_STATE_PLAYING: - mPausePlay.setImageDrawable(getPauseStopDrawable()); - adjustControlsVisibility(true); - break; - case MediaStatus.PLAYER_STATE_PAUSED: - mPausePlay.setImageDrawable(mPlayDrawable); - adjustControlsVisibility(true); - break; - case MediaStatus.PLAYER_STATE_IDLE: - mPausePlay.setVisibility(View.INVISIBLE); - setLoadingVisibility(false); - - if (mState == MediaStatus.PLAYER_STATE_IDLE - && mCastManager.getIdleReason() == MediaStatus.IDLE_REASON_FINISHED) { - hideControls(true, R.string.ccl_no_media_info); - } else { - switch (mStreamType) { - case MediaInfo.STREAM_TYPE_BUFFERED: - mPausePlay.setVisibility(View.INVISIBLE); - setLoadingVisibility(false); - break; - case MediaInfo.STREAM_TYPE_LIVE: - int idleReason = mCastManager.getIdleReason(); - if (idleReason == MediaStatus.IDLE_REASON_CANCELED) { - mPausePlay.setImageDrawable(mPlayDrawable); - adjustControlsVisibility(true); - } else { - mPausePlay.setVisibility(View.INVISIBLE); - setLoadingVisibility(false); - } - break; - } - } - break; - case MediaStatus.PLAYER_STATE_BUFFERING: - adjustControlsVisibility(false); - break; - default: - mPausePlay.setVisibility(View.INVISIBLE); - setLoadingVisibility(false); - } - } - } - - private Drawable getPauseStopDrawable() { - switch (mStreamType) { - case MediaInfo.STREAM_TYPE_BUFFERED: - return mPauseDrawable; - case MediaInfo.STREAM_TYPE_LIVE: - return mStopDrawable; - default: - return mPauseDrawable; - } - } - - private void setLoadingVisibility(boolean show) { - mLoading.setVisibility(show ? View.VISIBLE : View.GONE); - } - - private void adjustControlsVisibility(boolean showPlayPause) { - int visible = showPlayPause ? View.VISIBLE : View.INVISIBLE; - mPausePlay.setVisibility(visible); - setLoadingVisibility(!showPlayPause); - } - - /** - * Initializes this dialog's set of playback buttons and adds click listeners. - */ - @Override - public View onCreateMediaControlView(Bundle savedInstanceState) { - LayoutInflater inflater = getLayoutInflater(); - View controls = inflater.inflate(R.layout.custom_media_route_controller_controls_dialog, - null); - - loadViews(controls); - mState = mCastManager.getPlaybackStatus(); - updateMetadata(); - updatePlayPauseState(mState); - setUpCallbacks(); - return controls; - } - - private void setUpCallbacks() { - - mPausePlay.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - if (mCastManager == null) { - return; - } - try { - adjustControlsVisibility(false); - mCastManager.togglePlayback(); - } catch (CastException e) { - adjustControlsVisibility(true); - LOGE(TAG, "Failed to toggle playback", e); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - adjustControlsVisibility(true); - LOGE(TAG, "Failed to toggle playback due to network issues", e); - } - } - }); - - mIcon.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - showTargetActivity(); - } - - }); - - mTextContainer.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - showTargetActivity(); - } - - }); - } - - private void showTargetActivity() { - if (mCastManager != null - && mCastManager.getTargetActivity() != null) { - try { - mCastManager.onTargetActivityInvoked(mContext); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to start the target activity due to network issues", e); - } - cancel(); - } - } - - private void loadViews(View controls) { - mIcon = (ImageView) controls.findViewById(R.id.iconView); - mIconContainer = controls.findViewById(R.id.iconContainer); - mTextContainer = controls.findViewById(R.id.textContainer); - mPausePlay = (ImageView) controls.findViewById(R.id.playPauseView); - mTitle = (TextView) controls.findViewById(R.id.titleView); - mSubTitle = (TextView) controls.findViewById(R.id.subTitleView); - mLoading = (ProgressBar) controls.findViewById(R.id.loadingView); - mEmptyText = (TextView) controls.findViewById(R.id.emptyView); - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/dialog/video/VideoMediaRouteControllerDialogFragment.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/dialog/video/VideoMediaRouteControllerDialogFragment.java deleted file mode 100755 index baa6c8d61..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/dialog/video/VideoMediaRouteControllerDialogFragment.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.dialog.video; - -import android.content.Context; -import android.os.Bundle; -import android.support.v7.app.MediaRouteControllerDialogFragment; - -/** - * An extension of MediaRouteControllerDialogFragment which contains a - * VideoMediaRouteControllerDialog. - */ -public class VideoMediaRouteControllerDialogFragment extends MediaRouteControllerDialogFragment { - - @Override - public VideoMediaRouteControllerDialog onCreateControllerDialog( - Context context, Bundle savedInstanceState) { - VideoMediaRouteControllerDialog customControllerDialog - = new VideoMediaRouteControllerDialog(context); - customControllerDialog.setVolumeControlEnabled(false); - return customControllerDialog; - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/dialog/video/VideoMediaRouteDialogFactory.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/dialog/video/VideoMediaRouteDialogFactory.java deleted file mode 100644 index c8fbeb4cf..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/dialog/video/VideoMediaRouteDialogFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.dialog.video; - -import android.support.v7.app.MediaRouteDialogFactory; - -/** - * A factory for the MediaRoute Dialog. - */ -public class VideoMediaRouteDialogFactory extends MediaRouteDialogFactory { - - @Override - public VideoMediaRouteControllerDialogFragment onCreateControllerDialogFragment() { - return new VideoMediaRouteControllerDialogFragment(); - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/CastException.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/CastException.java deleted file mode 100644 index a25a6fde6..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/CastException.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.exceptions; - -import android.content.Context; - -/** - * A generic exception that a method can throw to indicate an issue related to the cast operation. - * More specific issues will be thrown separately. - */ -public class CastException extends Exception { - - private static final long serialVersionUID = 1L; - - public CastException() { - } - - public CastException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - } - - public CastException(String detailMessage) { - super(detailMessage); - } - - public CastException(Context ctx, int resId) { - super(ctx.getResources().getString(resId)); - } - - public CastException(Context ctx, int resId, Exception e) { - super(ctx.getResources().getString(resId), e); - } - - public CastException(Throwable throwable) { - super(throwable); - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/NoConnectionException.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/NoConnectionException.java deleted file mode 100644 index 55ee933f9..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/NoConnectionException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.exceptions; - -import java.io.IOException; - -/** - * Is used to indicate that the connectivity to the cast device is not there. User needs to take - * manual steps to fix this issue. - */ -@SuppressWarnings("serial") -public class NoConnectionException extends IOException { - - public NoConnectionException() { - } - - public NoConnectionException(Throwable throwable) { - super(throwable); - } - - public NoConnectionException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/OnFailedListener.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/OnFailedListener.java deleted file mode 100644 index 34d44c36d..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/OnFailedListener.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.exceptions; - -/** - * An interface for reporting back errors in an asynchronous way. - */ -public interface OnFailedListener { - - /** - * This method is called to report a failure. - * - * @param resourceId The resource that has a textual description of the problem - * @param statusCode An additional integer to further specify the error. Value - * {@link com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager#NO_STATUS_CODE} //NOLINT - * would be interpreted as no status code available. - */ - void onFailed(int resourceId, int statusCode); -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/TransientNetworkDisconnectionException.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/TransientNetworkDisconnectionException.java deleted file mode 100644 index a794177c5..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/exceptions/TransientNetworkDisconnectionException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.exceptions; - -import java.io.IOException; - -/** - * Is used to indicate a transient disconnection that may be corrected automatically by the - * framework. - */ -@SuppressWarnings("serial") -public class TransientNetworkDisconnectionException extends IOException { -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/MediaAuthListener.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/MediaAuthListener.java deleted file mode 100644 index 720692891..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/MediaAuthListener.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.player; - -import com.google.android.gms.cast.MediaInfo; - -import org.json.JSONObject; - -/** - * A public interface that provides callbacks for the {@link MediaAuthService} to communicate with - * the framework - */ -public interface MediaAuthListener { - - /** - * Called when MediaAuthService has successfully obtained a result. - * - * @param status Provides the status of result, will be one of - * {@link MediaAuthStatus#AUTHORIZED} or - * {@link MediaAuthStatus#NOT_AUTHORIZED} - * @param info The fully populated {@link MediaInfo} that is obtained through authorization. - * @param message If authorization was not granted, then an optional message can be provided - * to be presented to the user. If no message is provided, it will be silently ignored. - * Implementers have to make sure the message is localized. - * @param startPoint The position in video to start the playback at (in milliseconds) - * @param customData Optional {@link org.json.JSONObject} - */ - void onAuthResult(MediaAuthStatus status, MediaInfo info, String message, - int startPoint, JSONObject customData); - - /** - * Called when MediaAuthService returns with a failure message due to some issues such as - * network, backend issues, etc. - * - * @param failureMessage The message stating the reason for failure. This message should be - * localized. - */ - void onAuthFailure(String failureMessage); - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/MediaAuthService.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/MediaAuthService.java deleted file mode 100644 index f549af925..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/MediaAuthService.java +++ /dev/null @@ -1,99 +0,0 @@ - -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.player; - -import com.google.android.gms.cast.MediaInfo; - -/** - * A public interface if an application requires a pre-authorization of a media, prior to its - * playback. Applications should implement this interface when they want to obtain a - * pre-authorization prior to calling the {@link VideoCastControllerActivity}. The implementation - * should prepare the stage for its own out-of-bound process but should not start that till the - * {@link MediaAuthService#startAuthorization()} is called by the CCL library. Applications should - * provide a timeout limit to make sure that this out-of-bound process is completed within a - * reasonable period of time. - *

- * Framework passes an {@link MediaAuthListener} to the implementation of this interface to provide - * a way for the implementation to callback to the framework with its results. When the - * authorization process ends, the implementation has to call - * {@link com.google.android.libraries.cast.companionlibrary.cast.player.MediaAuthListener#onAuthResult(MediaAuthStatus, MediaInfo, String, int, org.json.JSONObject)} // NOLINT - * with the relevant results; whether the authorization was granted or rejected. If, however, the - * process encounters an unrecoverable error, it has to call the - * {@link com.google.android.libraries.cast.companionlibrary.cast.player.MediaAuthListener#onAuthFailure(String)} // NOLINT - * callback of the {@link MediaAuthListener} to inform the framework. - *

- * If the library decides to to interrupt the authorization process (say, a user decides to - * interrupt the process or if it times out), it will call - * {@link #abortAuthorization(MediaAuthStatus)} and provides a reason. Implementation has to make - * sure that it will not call any of the framework callbacks after it has received an abort message. - *

- * Since authorization process can be involved and may require network access, the - * {@link MediaAuthService#startAuthorization()} method is called on a non-UI thread. Callbacks into - * the framework can happen on or off the UI thread. - */ -public interface MediaAuthService { - - /** - * Starts the authorization process. Before this call, it is assumed that the implementor has - * all the information required to perform the authorization task. This is where the dynamic - * life cycle of this class starts. - */ - public void startAuthorization(); - - /** - * Registers an {@link MediaAuthListener} listener to be notified when the authentication - * service has obtained its result. To remove a previously set listener, pass a - * null argument. - */ - public void setMediaAuthListener(MediaAuthListener listener); - - /** - * Returns the current {@link MediaInfo} object that is the subject of authorization. At a - * minimum, it is expected to have images for the media at any stage. - */ - public MediaInfo getMediaInfo(); - - /** - * In pending state, implementors can provide an optional localized message to be shown to the - * user. If null is returned, no message will be shown to the user. - */ - public String getPendingMessage(); - - /** - * Returns the current status of the service. - */ - public MediaAuthStatus getStatus(); - - /** - * Returns the length of time within which the library expects to have heard back from the - * authorization service. If it doesn't, it will call - * {@link #abortAuthorization(MediaAuthStatus)}. - * - * @return Timeout in milliseconds - */ - public long getTimeout(); - - /** - * If authorization times out or user cancels the authorization process, this method will be - * called. - * - * @param abortReason One of the {@code MediaAuthStatus#ABORT_*} reasons - */ - public void abortAuthorization(MediaAuthStatus abortReason); - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/MediaAuthStatus.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/MediaAuthStatus.java deleted file mode 100644 index c0c7ab39a..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/MediaAuthStatus.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.player; - -/** - * An enum to enumerate various states of the authentication process used in - * {@link MediaAuthService} - */ -public enum MediaAuthStatus { - /* Service has not started yet */ - NOT_STARTED, - - /* Service is running but no results is available yet */ - PENDING, - - /* Service has finished its query and results are available */ - FINISHED, - - /* Service has finished and user was authorized */ - AUTHORIZED, - - /* Service has finished but user was not authorized */ - NOT_AUTHORIZED, - - /* Timeout has reached with no result */ - TIMED_OUT, - - /* User triggered abort */ - CANCELED_BY_USER, - - /* Abort due to an unknown issue */ - ABORT_UNKNOWN; - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/OnVideoCastControllerListener.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/OnVideoCastControllerListener.java deleted file mode 100644 index 4c831ffed..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/OnVideoCastControllerListener.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.player; - -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.tracks.OnTracksSelectedListener; - -import android.view.View; -import android.widget.SeekBar; - -/** - * An interface that enables an alternative implementation of - * {@link com.google.android.libraries.cast.companionlibrary.cast.player.VideoCastControllerFragment}. // NOLINT - */ -public interface OnVideoCastControllerListener extends OnTracksSelectedListener { - - /** - * Called when seeking is stopped by user. - */ - void onStopTrackingTouch(SeekBar seekBar); - - /** - * Called when seeking starts by user - */ - void onStartTrackingTouch(SeekBar seekBar); - - /** - * Called while seeking is happening by the user - */ - void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser); - - /** - * Notification that user has clicked on the Play/Pause button - * - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws CastException - */ - void onPlayPauseClicked(View v) throws CastException, - TransientNetworkDisconnectionException, NoConnectionException; - - /** - * Called when a configuration change happens (for example device is rotated) - */ - void onConfigurationChanged(); - - /** - * Called when user clicks on the Skip Next button - * - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - void onSkipNextClicked(View v) throws TransientNetworkDisconnectionException, - NoConnectionException; - - /** - * Called when user clicks on the Skip Previous button - * - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - void onSkipPreviousClicked(View v) - throws TransientNetworkDisconnectionException, NoConnectionException; - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/VideoCastController.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/VideoCastController.java deleted file mode 100644 index ee7f415ee..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/VideoCastController.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.player; - -import com.google.android.gms.cast.MediaStatus; - -import android.graphics.Bitmap; - -/** - * An interface that can be used to display a remote controller for the video that is playing on - * the cast device. - */ -public interface VideoCastController { - - int CC_ENABLED = 1; - int CC_DISABLED = 2; - int CC_HIDDEN = 3; - - int NEXT_PREV_VISIBILITY_POLICY_HIDDEN = 1; - int NEXT_PREV_VISIBILITY_POLICY_DISABLED = 2; - int NEXT_PREV_VISIBILITY_POLICY_ALWAYS = 3; - - /** - * Sets the bitmap for the album art - */ - void setImage(Bitmap bitmap); - - /** - * Sets the title - */ - void setTitle(String text); - - /** - * Sets the subtitle - */ - void setSubTitle(String text); - - /** - * Sets the playback state, and the idleReason (this is only used when the state is idle). - * Values that can be passed to this method are from {@link MediaStatus} - */ - void setPlaybackStatus(int state); - - /** - * Assigns a {@link OnVideoCastControllerListener} listener to be notified of the changes in - * the {@link VideoCastController} - */ - void setOnVideoCastControllerChangedListener(OnVideoCastControllerListener listener); - - /** - * Sets the type of stream. {@code streamType} can be - * {@link com.google.android.gms.cast.MediaInfo#STREAM_TYPE_LIVE} or - * {@link com.google.android.gms.cast.MediaInfo#STREAM_TYPE_BUFFERED} - */ - void setStreamType(int streamType); - - /** - * Updates the position and total duration for the seekbar that presents the progress of media. - * Both of these need to be provided in milliseconds. - */ - void updateSeekbar(int position, int duration); - - /** - * Adjust the visibility of control widgets on the UI. - */ - void updateControllersStatus(boolean enabled); - - /** - * Can be used to show a loading icon during processes that could take time. - */ - void showLoading(boolean visible); - - /** - * Closes the activity related to the UI. - */ - void closeActivity(); - - /** - * This can be used to adjust the UI for playback of live versus pre-recorded streams. Certain - * UI widgets may need to be updated when playing a live stream. For example, the progress bar - * may not be needed for a live stream while it may be required for a pre-recorded stream. - */ - void adjustControllersForLiveStream(boolean isLive); - - /** - * Updates the visual status of the Closed Caption icon. Possible states are provided by - * CC_ENABLED, CC_DISABLED, CC_HIDDEN - */ - void setClosedCaptionState(int status); - - /** - * Called when the queue items are updated and provides information about the updated size of - * the queue and the position of the current item in the queue. This can be useful to update - * the UI if the relative position of the current item is relevant (e.g. to disable or hide - * "skip next/prev" buttons). - */ - void onQueueItemsUpdated(int queueLength, int position); - - /** - * Sets the policy for the visibility/status of the Skip Next/Prev buttons. The policy declares - * what should the visibility or status of these buttons be when the position of the current - * item is at the edges of the queue. For example, if the current item is the last item in the - * queue, what should be the visibility or status of the "Skip Next" button. Available policies - * are: - *

    - *
  • {@link VideoCastController#NEXT_PREV_VISIBILITY_POLICY_ALWAYS}: always show the button - *
  • - *
  • {@link VideoCastController#NEXT_PREV_VISIBILITY_POLICY_DISABLED}: disable the button - *
  • - *
  • {@link VideoCastController#NEXT_PREV_VISIBILITY_POLICY_HIDDEN}: hide the button
  • - *
- * The default behavior is {@link VideoCastController#NEXT_PREV_VISIBILITY_POLICY_DISABLED} - */ - void setNextPreviousVisibilityPolicy(int policy); -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/VideoCastControllerActivity.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/VideoCastControllerActivity.java deleted file mode 100644 index 9f78f6634..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/VideoCastControllerActivity.java +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (C) 2014 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.player; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGD; -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.gms.cast.MediaInfo; -import com.google.android.gms.cast.MediaStatus; -import com.google.android.libraries.cast.companionlibrary.R; -import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions - .TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.tracks.ui.TracksChooserDialog; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; -import com.google.android.libraries.cast.companionlibrary.utils.Utils; -import com.google.android.libraries.cast.companionlibrary.widgets.MiniController; - -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; - -/** - * This class provides an {@link android.app.Activity} that clients can easily add to their - * applications to provide an out-of-the-box remote player when a video is casting to a cast device. - * {@link com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager} can manage the - * lifecycle and presentation of this activity. - *

- * This activity provides a number of controllers for managing the playback of the remote content: - * play/pause (or play/stop when a live stream is used) and seekbar (for non-live streams). - *

- * Clients who need to perform a pre-authorization process for playback can register a - * {@link MediaAuthListener} by calling - * {@link VideoCastManager#startVideoCastControllerActivity(android.content.Context, MediaAuthService)} - * In that case, this activity manages starting the {@link MediaAuthService} and will register a - * listener to handle the result. - */ -public class VideoCastControllerActivity extends AppCompatActivity implements - VideoCastController { - - private static final String TAG = LogUtils - .makeLogTag(VideoCastControllerActivity.class); - public static final String TASK_TAG = "task"; - public static final String DIALOG_TAG = "dialog"; - private VideoCastManager mCastManager; - private View mPageView; - private ImageButton mPlayPause; - private TextView mLiveText; - private TextView mStart; - private TextView mEnd; - private SeekBar mSeekbar; - private TextView mLine2; - private ProgressBar mLoading; - private double mVolumeIncrement; - private View mControllers; - private Drawable mPauseDrawable; - private Drawable mPlayDrawable; - private Drawable mStopDrawable; - private OnVideoCastControllerListener mListener; - private int mStreamType; - private ImageButton mClosedCaptionIcon; - private ImageButton mSkipNext; - private ImageButton mSkipPrevious; - private View mPlaybackControls; - private Toolbar mToolbar; - private int mNextPreviousVisibilityPolicy - = VideoCastController.NEXT_PREV_VISIBILITY_POLICY_DISABLED; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.cast_activity); - loadAndSetupViews(); - mCastManager = VideoCastManager.getInstance(); - mVolumeIncrement = mCastManager.getVolumeStep(); - - Bundle extras = getIntent().getExtras(); - if (extras == null) { - finish(); - return; - } - - setUpActionBar(); - - FragmentManager fm = getSupportFragmentManager(); - VideoCastControllerFragment videoCastControllerFragment - = (VideoCastControllerFragment) fm.findFragmentByTag(TASK_TAG); - - // if fragment is null, it means this is the first time, so create it - if (videoCastControllerFragment == null) { - videoCastControllerFragment = VideoCastControllerFragment - .newInstance(extras); - fm.beginTransaction().add(videoCastControllerFragment, TASK_TAG).commit(); - setOnVideoCastControllerChangedListener(videoCastControllerFragment); - } else { - setOnVideoCastControllerChangedListener(videoCastControllerFragment); - mListener.onConfigurationChanged(); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.cast_player_menu, menu); - mCastManager.addMediaRouterButton(menu, R.id.media_route_menu_item); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; - } - - @Override - public boolean dispatchKeyEvent(@NonNull KeyEvent event) { - return mCastManager.onDispatchVolumeKeyEvent(event, mVolumeIncrement) || super - .dispatchKeyEvent(event); - } - - private void loadAndSetupViews() { - mPauseDrawable = getResources().getDrawable(R.drawable.ic_pause_circle_white_80dp); - mPlayDrawable = getResources().getDrawable(R.drawable.ic_play_circle_white_80dp); - mStopDrawable = getResources().getDrawable(R.drawable.ic_stop_circle_white_80dp); - mPageView = findViewById(R.id.pageview); - mPlayPause = (ImageButton) findViewById(R.id.play_pause_toggle); - mLiveText = (TextView) findViewById(R.id.live_text); - mStart = (TextView) findViewById(R.id.start_text); - mEnd = (TextView) findViewById(R.id.end_text); - mSeekbar = (SeekBar) findViewById(R.id.seekbar); - mLine2 = (TextView) findViewById(R.id.textview2); - mLoading = (ProgressBar) findViewById(R.id.progressbar1); - mControllers = findViewById(R.id.controllers); - mClosedCaptionIcon = (ImageButton) findViewById(R.id.cc); - mSkipNext = (ImageButton) findViewById(R.id.next); - mSkipPrevious = (ImageButton) findViewById(R.id.previous); - mPlaybackControls = findViewById(R.id.playback_controls); - ((MiniController) findViewById(R.id.miniController1)).setCurrentVisibility(false); - setClosedCaptionState(CC_DISABLED); - mPlayPause.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - try { - mListener.onPlayPauseClicked(v); - } catch (TransientNetworkDisconnectionException e) { - LOGE(TAG, "Failed to toggle playback due to temporary network issue", e); - Utils.showToast(VideoCastControllerActivity.this, - R.string.ccl_failed_no_connection_trans); - } catch (NoConnectionException e) { - LOGE(TAG, "Failed to toggle playback due to network issues", e); - Utils.showToast(VideoCastControllerActivity.this, - R.string.ccl_failed_no_connection); - } catch (Exception e) { - LOGE(TAG, "Failed to toggle playback due to other issues", e); - Utils.showToast(VideoCastControllerActivity.this, - R.string.ccl_failed_perform_action); - } - } - }); - - mSeekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - try { - if (mListener != null) { - mListener.onStopTrackingTouch(seekBar); - } - } catch (Exception e) { - LOGE(TAG, "Failed to complete seek", e); - finish(); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - try { - if (mListener != null) { - mListener.onStartTrackingTouch(seekBar); - } - } catch (Exception e) { - LOGE(TAG, "Failed to start seek", e); - finish(); - } - } - - @Override - public void onProgressChanged(SeekBar seekBar, int progress, - boolean fromUser) { - mStart.setText(Utils.formatMillis(progress)); - try { - if (mListener != null) { - mListener.onProgressChanged(seekBar, progress, fromUser); - } - } catch (Exception e) { - LOGE(TAG, "Failed to set the progress result", e); - } - } - }); - - mClosedCaptionIcon.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - try { - showTracksChooserDialog(); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to get the media", e); - } - } - }); - - mSkipNext.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - try { - mListener.onSkipNextClicked(v); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to move to the next item in the queue", e); - } - } - }); - - mSkipPrevious.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - try { - mListener.onSkipPreviousClicked(v); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to move to the previous item in the queue", e); - } - } - }); - } - - private void showTracksChooserDialog() - throws TransientNetworkDisconnectionException, NoConnectionException { - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - Fragment prev = getSupportFragmentManager().findFragmentByTag(DIALOG_TAG); - if (prev != null) { - transaction.remove(prev); - } - transaction.addToBackStack(null); - - // Create and show the dialog. - TracksChooserDialog dialogFragment = TracksChooserDialog - .newInstance(mCastManager.getRemoteMediaInformation()); - dialogFragment.show(transaction, DIALOG_TAG); - } - - private void setUpActionBar() { - mToolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(mToolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - } - - @Override - public void showLoading(boolean visible) { - mLoading.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); - } - - @Override - public void adjustControllersForLiveStream(boolean isLive) { - int visibility = isLive ? View.INVISIBLE : View.VISIBLE; - mLiveText.setVisibility(isLive ? View.VISIBLE : View.INVISIBLE); - mStart.setVisibility(visibility); - mEnd.setVisibility(visibility); - mSeekbar.setVisibility(visibility); - } - - @Override - public void setClosedCaptionState(int status) { - switch (status) { - case CC_ENABLED: - mClosedCaptionIcon.setVisibility(View.VISIBLE); - mClosedCaptionIcon.setEnabled(true); - break; - case CC_DISABLED: - mClosedCaptionIcon.setVisibility(View.VISIBLE); - mClosedCaptionIcon.setEnabled(false); - break; - case CC_HIDDEN: - mClosedCaptionIcon.setVisibility(View.GONE); - break; - default: - LOGE(TAG, "setClosedCaptionState(): Invalid state requested: " + status); - } - } - - @Override - public void onQueueItemsUpdated(int queueLength, int position) { - boolean prevAvailable = position > 0; - boolean nextAvailable = position < queueLength - 1; - switch(mNextPreviousVisibilityPolicy) { - case VideoCastController.NEXT_PREV_VISIBILITY_POLICY_HIDDEN: - if (nextAvailable) { - mSkipNext.setVisibility(View.VISIBLE); - mSkipNext.setEnabled(true); - } else { - mSkipNext.setVisibility(View.INVISIBLE); - } - if (prevAvailable) { - mSkipPrevious.setVisibility(View.VISIBLE); - mSkipPrevious.setEnabled(true); - } else { - mSkipPrevious.setVisibility(View.INVISIBLE); - } - break; - case VideoCastController.NEXT_PREV_VISIBILITY_POLICY_ALWAYS: - mSkipNext.setVisibility(View.VISIBLE); - mSkipNext.setEnabled(true); - mSkipPrevious.setVisibility(View.VISIBLE); - mSkipPrevious.setEnabled(true); - break; - case VideoCastController.NEXT_PREV_VISIBILITY_POLICY_DISABLED: - if (nextAvailable) { - mSkipNext.setVisibility(View.VISIBLE); - mSkipNext.setEnabled(true); - } else { - mSkipNext.setVisibility(View.VISIBLE); - mSkipNext.setEnabled(false); - } - if (prevAvailable) { - mSkipPrevious.setVisibility(View.VISIBLE); - mSkipPrevious.setEnabled(true); - } else { - mSkipPrevious.setVisibility(View.VISIBLE); - mSkipPrevious.setEnabled(false); - } - break; - default: - LOGE(TAG, "onQueueItemsUpdated(): Invalid NextPreviousPolicy has been set"); - } - } - - @Override - public void setPlaybackStatus(int state) { - LOGD(TAG, "setPlaybackStatus(): state = " + state); - switch (state) { - case MediaStatus.PLAYER_STATE_PLAYING: - mLoading.setVisibility(View.INVISIBLE); - mPlaybackControls.setVisibility(View.VISIBLE); - if (mStreamType == MediaInfo.STREAM_TYPE_LIVE) { - mPlayPause.setImageDrawable(mStopDrawable); - } else { - mPlayPause.setImageDrawable(mPauseDrawable); - } - - mLine2.setText(getString(R.string.ccl_casting_to_device, - mCastManager.getDeviceName())); - mControllers.setVisibility(View.VISIBLE); - break; - case MediaStatus.PLAYER_STATE_PAUSED: - mControllers.setVisibility(View.VISIBLE); - mLoading.setVisibility(View.INVISIBLE); - mPlaybackControls.setVisibility(View.VISIBLE); - mPlayPause.setImageDrawable(mPlayDrawable); - mLine2.setText(getString(R.string.ccl_casting_to_device, - mCastManager.getDeviceName())); - break; - case MediaStatus.PLAYER_STATE_IDLE: - case MediaStatus.PLAYER_STATE_BUFFERING: - mPlaybackControls.setVisibility(View.INVISIBLE); - mLoading.setVisibility(View.VISIBLE); - mLine2.setText(getString(R.string.ccl_loading)); - break; - default: - } - } - - @Override - public void updateSeekbar(int position, int duration) { - mSeekbar.setProgress(position); - mSeekbar.setMax(duration); - mStart.setText(Utils.formatMillis(position)); - mEnd.setText(Utils.formatMillis(duration)); - } - - @SuppressWarnings("deprecation") - @Override - public void setImage(Bitmap bitmap) { - if (bitmap != null) { - if (mPageView instanceof ImageView) { - ((ImageView) mPageView).setImageBitmap(bitmap); - } else { - mPageView.setBackgroundDrawable(new BitmapDrawable(getResources(), bitmap)); - } - } - } - - @Override - public void setTitle(String text) { - mToolbar.setTitle(text); - } - - @Override - public void setSubTitle(String text) { - mLine2.setText(text); - } - - @Override - public void setOnVideoCastControllerChangedListener(OnVideoCastControllerListener listener) { - if (listener != null) { - mListener = listener; - } - } - - @Override - public void setStreamType(int streamType) { - this.mStreamType = streamType; - } - - @Override - public void updateControllersStatus(boolean enabled) { - mControllers.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE); - if (enabled) { - adjustControllersForLiveStream(mStreamType == MediaInfo.STREAM_TYPE_LIVE); - } - } - - @Override - public void closeActivity() { - finish(); - } - - @Override // from VideoCastController - public void setNextPreviousVisibilityPolicy(int policy) { - mNextPreviousVisibilityPolicy = policy; - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/VideoCastControllerFragment.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/VideoCastControllerFragment.java deleted file mode 100644 index 196162c89..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/player/VideoCastControllerFragment.java +++ /dev/null @@ -1,910 +0,0 @@ -/* - * Copyright (C) 2014 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.player; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGD; -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.gms.cast.MediaInfo; -import com.google.android.gms.cast.MediaMetadata; -import com.google.android.gms.cast.MediaQueueItem; -import com.google.android.gms.cast.MediaStatus; -import com.google.android.gms.cast.MediaTrack; -import com.google.android.gms.cast.RemoteMediaPlayer; -import com.google.android.libraries.cast.companionlibrary.R; -import com.google.android.libraries.cast.companionlibrary.cast.MediaQueue; -import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager; -import com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumerImpl; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions - .TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.utils.FetchBitmapTask; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; -import com.google.android.libraries.cast.companionlibrary.utils.Utils; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.support.annotation.Nullable; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.Fragment; -import android.text.TextUtils; -import android.view.View; -import android.widget.SeekBar; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -/** - * A fragment that provides a mechanism to retain the state and other needed objects for - * {@link VideoCastControllerActivity} (or more generally, for any class implementing - * {@link VideoCastController} interface). This can come very handy when set up of that activity - * allows for a configuration changes. Most of the logic required for - * {@link VideoCastControllerActivity} is maintained in this fragment to enable application - * developers provide a different implementation, if desired. - *

- * This fragment also provides an implementation of {@link MediaAuthListener} which can be useful - * if a pre-authorization is required for playback of a media. - */ -public class VideoCastControllerFragment extends Fragment implements - OnVideoCastControllerListener, MediaAuthListener { - - private static final String EXTRAS = "extras"; - private static final String TAG = LogUtils.makeLogTag(VideoCastControllerFragment.class); - private MediaInfo mSelectedMedia; - private VideoCastManager mCastManager; - private MediaAuthService mMediaAuthService; - private Thread mAuthThread; - private Timer mMediaAuthTimer; - private Handler mHandler; - protected boolean mAuthSuccess = true; - private VideoCastController mCastController; - private FetchBitmapTask mImageAsyncTask; - private Timer mSeekbarTimer; - private int mPlaybackState; - private MyCastConsumer mCastConsumer; - private OverallState mOverallState = OverallState.UNKNOWN; - private UrlAndBitmap mUrlAndBitmap; - private static boolean sDialogCanceled = false; - private boolean mIsFresh = true; - private MediaStatus mMediaStatus; - - private enum OverallState { - AUTHORIZING, PLAYBACK, UNKNOWN - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - sDialogCanceled = false; - mCastController = (VideoCastController) activity; - mHandler = new Handler(); - mCastManager = VideoCastManager.getInstance(); - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - if (mCastManager.getPreferenceAccessor() - .getBooleanFromPreference(VideoCastManager.PREFS_KEY_IMMERSIVE_MODE, true)) { - setImmersive(); - } - mCastConsumer = new MyCastConsumer(); - Bundle bundle = getArguments(); - if (bundle == null) { - return; - } - Bundle extras = bundle.getBundle(EXTRAS); - Bundle mediaWrapper = extras.getBundle(VideoCastManager.EXTRA_MEDIA); - - // Retain this fragment across configuration changes. - setRetainInstance(true); - mCastManager.addTracksSelectedListener(this); - boolean explicitStartActivity = mCastManager.getPreferenceAccessor() - .getBooleanFromPreference(VideoCastManager.PREFS_KEY_START_ACTIVITY, false); - if (explicitStartActivity) { - mIsFresh = true; - } - mCastManager.getPreferenceAccessor().saveBooleanToPreference( - VideoCastManager.PREFS_KEY_START_ACTIVITY, false); - int nextPreviousVisibilityPolicy = mCastManager.getPreferenceAccessor() - .getIntFromPreference(VideoCastManager.PREFS_KEY_NEXT_PREV_POLICY, - VideoCastController.NEXT_PREV_VISIBILITY_POLICY_DISABLED); - mCastController.setNextPreviousVisibilityPolicy(nextPreviousVisibilityPolicy); - if (extras.getBoolean(VideoCastManager.EXTRA_HAS_AUTH)) { - if (mIsFresh) { - mOverallState = OverallState.AUTHORIZING; - mMediaAuthService = mCastManager.getMediaAuthService(); - handleMediaAuthTask(mMediaAuthService); - showImage(Utils.getImageUri(mMediaAuthService.getMediaInfo(), 1)); - } - } else if (mediaWrapper != null) { - mOverallState = OverallState.PLAYBACK; - boolean shouldStartPlayback = extras.getBoolean(VideoCastManager.EXTRA_SHOULD_START); - String customDataStr = extras.getString(VideoCastManager.EXTRA_CUSTOM_DATA); - JSONObject customData = null; - if (!TextUtils.isEmpty(customDataStr)) { - try { - customData = new JSONObject(customDataStr); - } catch (JSONException e) { - LOGE(TAG, "Failed to unmarshalize custom data string: customData=" - + customDataStr, e); - } - } - MediaInfo info = Utils.bundleToMediaInfo(mediaWrapper); - int startPoint = extras.getInt(VideoCastManager.EXTRA_START_POINT, 0); - onReady(info, shouldStartPlayback && explicitStartActivity, startPoint, customData); - } - } - - /* - * Starts a background thread for starting the Auth Service - */ - private void handleMediaAuthTask(final MediaAuthService authService) { - mCastController.showLoading(true); - if (authService == null) { - return; - } - mCastController.setSubTitle(authService.getPendingMessage() != null - ? authService.getPendingMessage() : ""); - mAuthThread = new Thread(new Runnable() { - - @Override - public void run() { - authService.setMediaAuthListener(VideoCastControllerFragment.this); - authService.startAuthorization(); - } - }); - mAuthThread.start(); - - // start a timeout timer; we don't want authorization process to take too long - mMediaAuthTimer = new Timer(); - mMediaAuthTimer.schedule(new MediaAuthServiceTimerTask(mAuthThread), - authService.getTimeout()); - } - - /* - * A TimerTask that will be called when the auth timer expires - */ - class MediaAuthServiceTimerTask extends TimerTask { - - private final Thread mThread; - - public MediaAuthServiceTimerTask(Thread thread) { - this.mThread = thread; - } - - @Override - public void run() { - if (mThread != null) { - LOGD(TAG, "Timer is expired, going to interrupt the thread"); - mThread.interrupt(); - mHandler.post(new Runnable() { - - @Override - public void run() { - mCastController.showLoading(false); - showErrorDialog(getString(R.string.ccl_failed_authorization_timeout)); - mAuthSuccess = false; - if ((mMediaAuthService != null) - && (mMediaAuthService.getStatus() == MediaAuthStatus.PENDING)) { - mMediaAuthService.abortAuthorization(MediaAuthStatus.TIMED_OUT); - } - } - }); - - } - } - - } - - private class MyCastConsumer extends VideoCastConsumerImpl { - - @Override - public void onDisconnected() { - mCastController.closeActivity(); - } - - @Override - public void onApplicationDisconnected(int errorCode) { - mCastController.closeActivity(); - } - - @Override - public void onRemoteMediaPlayerMetadataUpdated() { - try { - mSelectedMedia = mCastManager.getRemoteMediaInformation(); - updateClosedCaptionState(); - updateMetadata(); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to update the metadata due to network issues", e); - } - } - - @Override - public void onFailed(int resourceId, int statusCode) { - LOGD(TAG, "onFailed(): " + getString(resourceId) + ", status code: " + statusCode); - if (statusCode == RemoteMediaPlayer.STATUS_FAILED - || statusCode == RemoteMediaPlayer.STATUS_TIMED_OUT) { - Utils.showToast(getActivity(), resourceId); - mCastController.closeActivity(); - } - } - - @Override - public void onRemoteMediaPlayerStatusUpdated() { - updatePlayerStatus(); - } - - @Override - public void onMediaQueueUpdated(List queueItems, MediaQueueItem item, - int repeatMode, boolean shuffle) { - - int size = 0; - int position = 0; - if (queueItems != null) { - size = queueItems.size(); - position = queueItems.indexOf(item); - } - mCastController.onQueueItemsUpdated(size, position); - } - - @Override - public void onConnectionSuspended(int cause) { - mCastController.updateControllersStatus(false); - } - - @Override - public void onConnectivityRecovered() { - mCastController.updateControllersStatus(true); - } - - } - - private class UpdateSeekbarTask extends TimerTask { - - @Override - public void run() { - mHandler.post(new Runnable() { - - @Override - public void run() { - int currentPos; - if (mPlaybackState == MediaStatus.PLAYER_STATE_BUFFERING) { - return; - } - if (!mCastManager.isConnected()) { - return; - } - try { - int duration = (int) mCastManager.getMediaDuration(); - if (duration > 0) { - try { - currentPos = (int) mCastManager.getCurrentMediaPosition(); - mCastController.updateSeekbar(currentPos, duration); - } catch (Exception e) { - LOGE(TAG, "Failed to get current media position", e); - } - } - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to update the progress bar due to network issues", e); - } - - } - }); - } - } - - /** - * Loads the media on the cast device. - * - * @param mediaInfo The media to be loaded - * @param shouldStartPlayback If {@code true}, playback starts after load automatically - * @param startPoint The position to start the play back - * @param customData An optional custom data to be sent along the load api; it can be - * {@code null} - */ - private void onReady(MediaInfo mediaInfo, boolean shouldStartPlayback, int startPoint, - JSONObject customData) { - mSelectedMedia = mediaInfo; - updateClosedCaptionState(); - try { - mCastController.setStreamType(mSelectedMedia.getStreamType()); - if (shouldStartPlayback) { - // need to start remote playback - mPlaybackState = MediaStatus.PLAYER_STATE_BUFFERING; - mCastController.setPlaybackStatus(mPlaybackState); - mCastManager.loadMedia(mSelectedMedia, true, startPoint, customData); - } else { - // we don't change the status of remote playback - if (mCastManager.isRemoteMediaPlaying()) { - mPlaybackState = MediaStatus.PLAYER_STATE_PLAYING; - } else { - mPlaybackState = MediaStatus.PLAYER_STATE_PAUSED; - } - mCastController.setPlaybackStatus(mPlaybackState); - } - } catch (Exception e) { - LOGE(TAG, "Failed to get playback and media information", e); - mCastController.closeActivity(); - } - MediaQueue mediaQueue = mCastManager.getMediaQueue(); - int size = 0; - int position = 0; - if (mediaQueue != null) { - size = mediaQueue.getCount(); - position = mediaQueue.getCurrentItemPosition(); - } - mCastController.onQueueItemsUpdated(size, position); - updateMetadata(); - restartTrickplayTimer(); - } - - private void updateClosedCaptionState() { - int state = VideoCastController.CC_HIDDEN; - if (mCastManager.isFeatureEnabled(VideoCastManager.FEATURE_CAPTIONS_PREFERENCE) - && mSelectedMedia != null - && mCastManager.getTracksPreferenceManager().isCaptionEnabled()) { - List tracks = mSelectedMedia.getMediaTracks(); - state = hasAudioOrTextTrack(tracks) ? VideoCastController.CC_ENABLED - : VideoCastController.CC_DISABLED; - } - mCastController.setClosedCaptionState(state); - } - - private boolean hasAudioOrTextTrack(List tracks) { - if (tracks == null || tracks.isEmpty()) { - return false; - } - for (MediaTrack track : tracks) { - if (track.getType() == MediaTrack.TYPE_AUDIO - || track.getType() == MediaTrack.TYPE_TEXT) { - return true; - } - } - return false; - } - - private void stopTrickplayTimer() { - LOGD(TAG, "Stopped TrickPlay Timer"); - if (mSeekbarTimer != null) { - mSeekbarTimer.cancel(); - } - } - - private void restartTrickplayTimer() { - stopTrickplayTimer(); - mSeekbarTimer = new Timer(); - mSeekbarTimer.scheduleAtFixedRate(new UpdateSeekbarTask(), 100, 1000); - LOGD(TAG, "Restarted TrickPlay Timer"); - } - - private void updateOverallState() { - MediaAuthService authService; - switch (mOverallState) { - case AUTHORIZING: - authService = mCastManager.getMediaAuthService(); - if (authService != null) { - mCastController.setSubTitle(authService.getPendingMessage() != null - ? authService.getPendingMessage() : ""); - mCastController.showLoading(true); - } - break; - case PLAYBACK: - // nothing yet, may be needed in future - break; - default: - break; - } - } - - private void updateMetadata() { - Uri imageUrl = null; - if (mSelectedMedia == null) { - if (mMediaAuthService != null) { - imageUrl = Utils.getImageUri(mMediaAuthService.getMediaInfo(), 1); - } - } else { - imageUrl = Utils.getImageUri(mSelectedMedia, 1); - } - showImage(imageUrl); - if (mSelectedMedia == null) { - return; - } - MediaMetadata mm = mSelectedMedia.getMetadata(); - mCastController.setTitle(mm.getString(MediaMetadata.KEY_TITLE) != null - ? mm.getString(MediaMetadata.KEY_TITLE) : ""); - boolean isLive = mSelectedMedia.getStreamType() == MediaInfo.STREAM_TYPE_LIVE; - mCastController.adjustControllersForLiveStream(isLive); - } - - private void updatePlayerStatus() { - int mediaStatus = mCastManager.getPlaybackStatus(); - mMediaStatus = mCastManager.getMediaStatus(); - LOGD(TAG, "updatePlayerStatus(), state: " + mediaStatus); - if (mSelectedMedia == null) { - return; - } - mCastController.setStreamType(mSelectedMedia.getStreamType()); - if (mediaStatus == MediaStatus.PLAYER_STATE_BUFFERING) { - mCastController.setSubTitle(getString(R.string.ccl_loading)); - } else { - mCastController.setSubTitle(getString(R.string.ccl_casting_to_device, - mCastManager.getDeviceName())); - } - switch (mediaStatus) { - case MediaStatus.PLAYER_STATE_PLAYING: - mIsFresh = false; - if (mPlaybackState != MediaStatus.PLAYER_STATE_PLAYING) { - mPlaybackState = MediaStatus.PLAYER_STATE_PLAYING; - mCastController.setPlaybackStatus(mPlaybackState); - } - break; - case MediaStatus.PLAYER_STATE_PAUSED: - mIsFresh = false; - if (mPlaybackState != MediaStatus.PLAYER_STATE_PAUSED) { - mPlaybackState = MediaStatus.PLAYER_STATE_PAUSED; - mCastController.setPlaybackStatus(mPlaybackState); - } - break; - case MediaStatus.PLAYER_STATE_BUFFERING: - mIsFresh = false; - if (mPlaybackState != MediaStatus.PLAYER_STATE_BUFFERING) { - mPlaybackState = MediaStatus.PLAYER_STATE_BUFFERING; - mCastController.setPlaybackStatus(mPlaybackState); - } - break; - case MediaStatus.PLAYER_STATE_IDLE: - LOGD(TAG, "Idle Reason: " + (mCastManager.getIdleReason())); - switch (mCastManager.getIdleReason()) { - case MediaStatus.IDLE_REASON_FINISHED: - if (!mIsFresh && mMediaStatus.getLoadingItemId() - == MediaQueueItem.INVALID_ITEM_ID) { - mCastController.closeActivity(); - } - break; - case MediaStatus.IDLE_REASON_CANCELED: - try { - if (mCastManager.isRemoteStreamLive()) { - if (mPlaybackState != MediaStatus.PLAYER_STATE_IDLE) { - mPlaybackState = MediaStatus.PLAYER_STATE_IDLE; - mCastController.setPlaybackStatus(mPlaybackState); - } - } else { - mCastController.closeActivity(); - } - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGD(TAG, "Failed to determine if stream is live", e); - } - break; - case MediaStatus.IDLE_REASON_INTERRUPTED: - mPlaybackState = MediaStatus.PLAYER_STATE_IDLE; - mCastController.setPlaybackStatus(mPlaybackState); - break; - default: - break; - } - break; - - default: - break; - } - } - - @Override - public void onDestroy() { - LOGD(TAG, "onDestroy()"); - stopTrickplayTimer(); - cleanup(); - super.onDestroy(); - } - - @Override - public void onResume() { - super.onResume(); - try { - if (mCastManager.isRemoteMediaPaused() || mCastManager.isRemoteMediaPlaying()) { - if (mCastManager.getRemoteMediaInformation() != null && mSelectedMedia - .getContentId().equals( - mCastManager.getRemoteMediaInformation().getContentId())) { - mIsFresh = false; - } - } - if (!mCastManager.isConnecting()) { - boolean shouldFinish = !mCastManager.isConnected() - || (mCastManager.getPlaybackStatus() == MediaStatus.PLAYER_STATE_IDLE - && mCastManager.getIdleReason() == MediaStatus.IDLE_REASON_FINISHED); - if (shouldFinish && !mIsFresh) { - mCastController.closeActivity(); - return; - } - } - mMediaStatus = mCastManager.getMediaStatus(); - mCastManager.addVideoCastConsumer(mCastConsumer); - if (!mIsFresh) { - updatePlayerStatus(); - // updating metadata in case another client has changed it and we are resuming the - // activity - mSelectedMedia = mCastManager.getRemoteMediaInformation(); - updateClosedCaptionState(); - updateMetadata(); - } - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to get media information or status of media playback", e); - } finally { - mCastManager.incrementUiCounter(); - } - } - - @Override - public void onPause() { - mCastManager.removeVideoCastConsumer(mCastConsumer); - mCastManager.decrementUiCounter(); - mIsFresh = false; - super.onPause(); - } - - /** - * Call this static method to create an instance of this fragment. - */ - public static VideoCastControllerFragment newInstance(Bundle extras) { - VideoCastControllerFragment f = new VideoCastControllerFragment(); - Bundle b = new Bundle(); - b.putBundle(EXTRAS, extras); - f.setArguments(b); - return f; - } - - /* - * Gets the image at the given url and populates the image view with that. It tries to cache the - * image to avoid unnecessary network calls. - */ - private void showImage(final Uri uri) { - if (mImageAsyncTask != null) { - mImageAsyncTask.cancel(true); - } - if (uri == null) { - mCastController.setImage(BitmapFactory.decodeResource(getActivity().getResources(), - R.drawable.album_art_placeholder_large)); - return; - } - if (mUrlAndBitmap != null && mUrlAndBitmap.isMatch(uri)) { - // we can reuse mBitmap - mCastController.setImage(mUrlAndBitmap.mBitmap); - return; - } - mUrlAndBitmap = null; - if (mImageAsyncTask != null) { - mImageAsyncTask.cancel(true); - } - mImageAsyncTask = new FetchBitmapTask() { - @Override - protected void onPostExecute(Bitmap bitmap) { - if (bitmap != null) { - mUrlAndBitmap = new UrlAndBitmap(); - mUrlAndBitmap.mBitmap = bitmap; - mUrlAndBitmap.mUrl = uri; - if (!isCancelled()) { - mCastController.setImage(bitmap); - } - } - if (this == mImageAsyncTask) { - mImageAsyncTask = null; - } - } - }; - mImageAsyncTask.execute(uri); - } - - /** - * A modal dialog with an OK button, where upon clicking on it, will finish the activity. We - * use a DialogFragment so during configuration changes, system manages the dialog for us. - */ - public static class ErrorDialogFragment extends DialogFragment { - - private VideoCastController mController; - private static final String MESSAGE = "message"; - - public static ErrorDialogFragment newInstance(String message) { - ErrorDialogFragment frag = new ErrorDialogFragment(); - Bundle args = new Bundle(); - args.putString(MESSAGE, message); - frag.setArguments(args); - return frag; - } - - @Override - public void onAttach(Activity activity) { - mController = (VideoCastController) activity; - super.onAttach(activity); - setCancelable(false); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - String message = getArguments().getString(MESSAGE); - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.ccl_error) - .setMessage(message) - .setPositiveButton(R.string.ccl_ok, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - sDialogCanceled = true; - mController.closeActivity(); - } - }) - .create(); - } - } - - /* - * Shows an error dialog - */ - private void showErrorDialog(String message) { - ErrorDialogFragment.newInstance(message).show(getFragmentManager(), "dlg"); - } - - @Override - public void onStop() { - super.onStop(); - if (mImageAsyncTask != null) { - mImageAsyncTask.cancel(true); - mImageAsyncTask = null; - } - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - try { - if (mPlaybackState == MediaStatus.PLAYER_STATE_PLAYING) { - mPlaybackState = MediaStatus.PLAYER_STATE_BUFFERING; - mCastController.setPlaybackStatus(mPlaybackState); - mCastManager.play(seekBar.getProgress()); - } else if (mPlaybackState == MediaStatus.PLAYER_STATE_PAUSED) { - mCastManager.seek(seekBar.getProgress()); - } - restartTrickplayTimer(); - } catch (Exception e) { - LOGE(TAG, "Failed to complete seek", e); - mCastController.closeActivity(); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - stopTrickplayTimer(); - } - - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - } - - @Override - public void onPlayPauseClicked(View v) throws CastException, - TransientNetworkDisconnectionException, NoConnectionException { - LOGD(TAG, "isConnected returning: " + mCastManager.isConnected()); - togglePlayback(); - } - - private void togglePlayback() throws CastException, TransientNetworkDisconnectionException, - NoConnectionException { - switch (mPlaybackState) { - case MediaStatus.PLAYER_STATE_PAUSED: - mCastManager.play(); - mPlaybackState = MediaStatus.PLAYER_STATE_BUFFERING; - restartTrickplayTimer(); - break; - case MediaStatus.PLAYER_STATE_PLAYING: - mCastManager.pause(); - mPlaybackState = MediaStatus.PLAYER_STATE_BUFFERING; - break; - case MediaStatus.PLAYER_STATE_IDLE: - if ((mSelectedMedia.getStreamType() == MediaInfo.STREAM_TYPE_LIVE) - && (mCastManager.getIdleReason() == MediaStatus.IDLE_REASON_CANCELED)) { - mCastManager.play(); - } else { - mCastManager.loadMedia(mSelectedMedia, true, 0); - } - mPlaybackState = MediaStatus.PLAYER_STATE_BUFFERING; - restartTrickplayTimer(); - break; - default: - break; - } - mCastController.setPlaybackStatus(mPlaybackState); - } - - @Override - public void onConfigurationChanged() { - updateOverallState(); - if (mSelectedMedia == null) { - if (mMediaAuthService != null) { - showImage(Utils.getImageUri(mMediaAuthService.getMediaInfo(), 1)); - } - } else { - updateMetadata(); - updatePlayerStatus(); - mCastController.updateControllersStatus(mCastManager.isConnected()); - - } - } - - @Override - public void onAuthResult(MediaAuthStatus status, final MediaInfo info, final String message, - final int startPoint, final JSONObject customData) { - if (status == MediaAuthStatus.AUTHORIZED && mAuthSuccess) { - // successful authorization - mMediaAuthService = null; - if (mMediaAuthTimer != null) { - mMediaAuthTimer.cancel(); - } - mSelectedMedia = info; - updateClosedCaptionState(); - mHandler.post(new Runnable() { - - @Override - public void run() { - mOverallState = OverallState.PLAYBACK; - onReady(info, true, startPoint, customData); - } - }); - } else { - if (mMediaAuthTimer != null) { - mMediaAuthTimer.cancel(); - } - mHandler.post(new Runnable() { - @Override - public void run() { - mOverallState = OverallState.UNKNOWN; - showErrorDialog(message); - } - }); - - } - } - - @Override - public void onAuthFailure(final String failureMessage) { - if (mMediaAuthTimer != null) { - mMediaAuthTimer.cancel(); - } - mHandler.post(new Runnable() { - - @Override - public void run() { - mOverallState = OverallState.UNKNOWN; - showErrorDialog(failureMessage); - } - }); - - } - - @Override - public void onTracksSelected(List tracks) { - long[] tracksArray; - if (tracks.isEmpty()) { - tracksArray = new long[]{}; - } else { - tracksArray = new long[tracks.size()]; - for (int i = 0; i < tracks.size(); i++) { - tracksArray[i] = tracks.get(i).getId(); - } - } - mCastManager.setActiveTrackIds(tracksArray); - if (tracks.size() > 0) { - mCastManager.setTextTrackStyle(mCastManager.getTracksPreferenceManager() - .getTextTrackStyle()); - } - } - - /* - * A simple class that holds a URL and a bitmap, mainly used to cache the fetched image - */ - private class UrlAndBitmap { - - private Bitmap mBitmap; - private Uri mUrl; - - private boolean isMatch(Uri url) { - return url != null && mBitmap != null && url.equals(mUrl); - } - } - - /* - * Cleanup of threads and timers and bitmap and ... - */ - private void cleanup() { - MediaAuthService authService = mCastManager.getMediaAuthService(); - if (mMediaAuthTimer != null) { - mMediaAuthTimer.cancel(); - } - if (mAuthThread != null) { - mAuthThread = null; - } - if (mCastManager.getMediaAuthService() != null) { - authService.setMediaAuthListener(null); - mCastManager.removeMediaAuthService(); - } - if (mCastManager != null) { - mCastManager.removeVideoCastConsumer(mCastConsumer); - } - if (mHandler != null) { - mHandler.removeCallbacksAndMessages(null); - } - if (mUrlAndBitmap != null) { - mUrlAndBitmap.mBitmap = null; - } - if (!sDialogCanceled && mMediaAuthService != null) { - mMediaAuthService.abortAuthorization(MediaAuthStatus.CANCELED_BY_USER); - } - - mCastManager.removeTracksSelectedListener(this); - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - private void setImmersive() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - return; - } - int newUiOptions = getActivity().getWindow().getDecorView().getSystemUiVisibility(); - - // Navigation bar hiding: Backwards compatible to ICS. - if (Build.VERSION.SDK_INT >= 14) { - newUiOptions ^= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; - } - - // Status bar hiding: Backwards compatible to Jellybean - if (Build.VERSION.SDK_INT >= 16) { - newUiOptions ^= View.SYSTEM_UI_FLAG_FULLSCREEN; - } - - if (Build.VERSION.SDK_INT >= 18) { - newUiOptions ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - } - - getActivity().getWindow().getDecorView().setSystemUiVisibility(newUiOptions); - } - - @Override - public void onSkipNextClicked(View v) - throws TransientNetworkDisconnectionException, NoConnectionException { - mCastController.showLoading(true); - mCastManager.queueNext(null); - } - - @Override - public void onSkipPreviousClicked(View v) - throws TransientNetworkDisconnectionException, NoConnectionException { - mCastController.showLoading(true); - mCastManager.queuePrev(null); - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/reconnection/ReconnectionService.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/reconnection/ReconnectionService.java deleted file mode 100644 index f56abe067..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/reconnection/ReconnectionService.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.reconnection; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGD; -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager; -import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; -import com.google.android.libraries.cast.companionlibrary.utils.Utils; - -import android.app.Service; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.NetworkInfo; -import android.net.wifi.WifiManager; -import android.os.IBinder; -import android.os.SystemClock; - -import java.util.Timer; -import java.util.TimerTask; - -/** - * A service to run in the background when the playback of a media starts, to help with reconnection - * if needed. Due to various reasons, connectivity to the cast device can be lost; for example wifi - * radio may turn off when device goes to sleep or user may step outside of the wifi range, etc. - * This service helps with recovering the connectivity when circumstances are right, for example - * when user steps back within the wifi range, etc. In order to avoid ending up with a background - * service that lingers around longer than it is needed, this implementation uses certain heuristics - * to stop itself when needed. - */ -public class ReconnectionService extends Service { - - private static final String TAG = LogUtils.makeLogTag(ReconnectionService.class); - // the tolerance for considering a time value (in millis) to be zero - private static final long EPSILON_MS = 500; - private static final int RECONNECTION_ATTEMPT_PERIOD_S = 15; - private BroadcastReceiver mScreenOnOffBroadcastReceiver; - private VideoCastManager mCastManager; - private BroadcastReceiver mWifiBroadcastReceiver; - private boolean mWifiConnectivity = true; - private Timer mEndTimer; - private TimerTask mEndTimerTask; - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - LOGD(TAG, "onStartCommand() is called"); - setUpEndTimer(); - return Service.START_STICKY; - } - - @Override - public void onCreate() { - LOGD(TAG, "onCreate() is called"); - mCastManager = VideoCastManager.getInstance(); - if (!mCastManager.isConnected() && !mCastManager.isConnecting()) { - mCastManager.reconnectSessionIfPossible(); - } - - // register a broadcast receiver to be notified when screen goes on or off - IntentFilter screenOnOffIntentFilter = new IntentFilter(Intent.ACTION_SCREEN_ON); - screenOnOffIntentFilter.addAction(Intent.ACTION_SCREEN_OFF); - mScreenOnOffBroadcastReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - LOGD(TAG, "ScreenOnOffBroadcastReceiver: onReceive(): " + intent.getAction()); - long timeLeft = getMediaRemainingTime(); - if (timeLeft < EPSILON_MS) { - handleTermination(); - } - } - }; - registerReceiver(mScreenOnOffBroadcastReceiver, screenOnOffIntentFilter); - - // register a wifi receiver that would be notified when the network state changes - IntentFilter networkIntentFilter = new IntentFilter(); - networkIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mWifiBroadcastReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - boolean connected = info.isConnected(); - String networkSsid = connected ? Utils.getWifiSsid(context) : null; - ReconnectionService.this.onWifiConnectivityChanged(connected, networkSsid); - } - } - }; - registerReceiver(mWifiBroadcastReceiver, networkIntentFilter); - - super.onCreate(); - } - - /** - * Since framework calls this method twice when a change happens, we are guarding against that - * by caching the state the first time and avoiding the second call if it is the same status. - */ - public void onWifiConnectivityChanged(boolean connected, final String networkSsid) { - LOGD(TAG, "WIFI connectivity changed to " + (connected ? "enabled" : "disabled")); - if (connected && !mWifiConnectivity) { - mWifiConnectivity = true; - if (mCastManager.isFeatureEnabled(BaseCastManager.FEATURE_WIFI_RECONNECT)) { - mCastManager.startCastDiscovery(); - mCastManager.reconnectSessionIfPossible(RECONNECTION_ATTEMPT_PERIOD_S, networkSsid); - } - - } else { - mWifiConnectivity = connected; - } - } - - - @Override - public void onDestroy() { - LOGD(TAG, "onDestroy()"); - if (mScreenOnOffBroadcastReceiver != null) { - unregisterReceiver(mScreenOnOffBroadcastReceiver); - mScreenOnOffBroadcastReceiver = null; - } - - if (mWifiBroadcastReceiver != null) { - unregisterReceiver(mWifiBroadcastReceiver); - mWifiBroadcastReceiver = null; - } - - clearEndTimer(); - super.onDestroy(); - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - private void setUpEndTimer() { - LOGD(TAG, "setUpEndTimer(): setting up a timer for the end of current media"); - long timeLeft = getMediaRemainingTime(); - if (timeLeft <= 0) { - stopSelf(); - return; - } - clearEndTimer(); - mEndTimer = new Timer(); - mEndTimerTask = new TimerTask() { - @Override - public void run() { - LOGD(TAG, "setUpEndTimer(): stopping ReconnectionService since reached the end of" - + " allotted time"); - handleTermination(); - } - }; - mEndTimer.schedule(mEndTimerTask, timeLeft); - } - - private void clearEndTimer() { - if (mEndTimerTask != null) { - mEndTimerTask.cancel(); - mEndTimerTask = null; - } - - if (mEndTimer != null) { - mEndTimer.cancel(); - mEndTimer = null; - } - } - - private long getMediaRemainingTime() { - long endTime = mCastManager.getPreferenceAccessor().getLongFromPreference( - BaseCastManager.PREFS_KEY_MEDIA_END, 0); - return endTime - SystemClock.elapsedRealtime(); - } - - private void handleTermination() { - if (!mCastManager.isConnected()) { - mCastManager.clearMediaSession(); - mCastManager.clearPersistedConnectionInfo(BaseCastManager.CLEAR_ALL); - stopSelf(); - } else { - // since we are connected and our timer has gone off, lets update the time remaining - // on the media (since media may have been paused) and reset teh time left - long timeLeft = 0; - try { - timeLeft = mCastManager.isRemoteStreamLive() ? 0 - : mCastManager.getMediaTimeRemaining(); - - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to calculate the time left for media due to lack of connectivity", - e); - } - if (timeLeft < EPSILON_MS) { - // no time left - stopSelf(); - } else { - // lets reset the counter - mCastManager.getPreferenceAccessor().saveLongToPreference( - BaseCastManager.PREFS_KEY_MEDIA_END, - timeLeft + SystemClock.elapsedRealtime()); - LOGD(TAG, "handleTermination(): resetting the timer"); - setUpEndTimer(); - } - - } - } -} - diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/CaptionsPreferenceActivity.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/CaptionsPreferenceActivity.java deleted file mode 100644 index d1ca5758d..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/CaptionsPreferenceActivity.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.tracks; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.libraries.cast.companionlibrary.R; -import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; -import com.google.android.libraries.cast.companionlibrary.utils.Utils; - -import android.content.Intent; -import android.os.Bundle; -import android.preference.PreferenceActivity; -import android.provider.Settings; - -/** - * An Activity to show the Captions Preferences for Android versions prior to KitKat - */ -public class CaptionsPreferenceActivity extends PreferenceActivity { - - private static final String TAG = LogUtils.makeLogTag(CaptionsPreferenceActivity.class); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - VideoCastManager castManager = VideoCastManager.getInstance(); - if (!castManager.isFeatureEnabled(VideoCastManager.FEATURE_CAPTIONS_PREFERENCE)) { - LOGE(TAG, "Did you forget to enable FEATURE_CAPTIONS_PREFERENCE when you initialized" - + " the VideoCastManage?"); - finish(); - return; - } - if (Utils.IS_KITKAT_OR_ABOVE) { - startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)); - finish(); - return; - } - addPreferencesFromResource(R.xml.caption_preference); - castManager.getTracksPreferenceManager().setUpPreferences(getPreferenceScreen()); - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/OnTracksSelectedListener.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/OnTracksSelectedListener.java deleted file mode 100644 index eb29320cb..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/OnTracksSelectedListener.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.tracks; - -import com.google.android.gms.cast.MediaTrack; - -import java.util.List; - -/** - * An interface to listen to changes to the active tracks for a media. - */ -public interface OnTracksSelectedListener { - - /** - * Called to inform the listeners of the new set of active tracks. - * - * @param tracks A Non-null list of MediaTracks. - */ - void onTracksSelected(List tracks); -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/TracksPreferenceManager.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/TracksPreferenceManager.java deleted file mode 100644 index faee35f23..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/TracksPreferenceManager.java +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.tracks; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGD; - -import com.google.android.gms.cast.TextTrackStyle; -import com.google.android.libraries.cast.companionlibrary.R; -import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; -import com.google.android.libraries.cast.companionlibrary.utils.PreferenceAccessor; -import com.google.android.libraries.cast.companionlibrary.utils.Utils; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.graphics.Color; -import android.graphics.Typeface; -import android.preference.CheckBoxPreference; -import android.preference.ListPreference; -import android.preference.PreferenceManager; -import android.preference.PreferenceScreen; -import android.view.accessibility.CaptioningManager; - -import java.util.HashMap; -import java.util.Map; - -/** - * This class manages preference settings for captions for Android versions prior to KitKat and - * provides a number of methods that would work across all supported versions of Android. - */ -public class TracksPreferenceManager implements SharedPreferences.OnSharedPreferenceChangeListener { - - private static final String TAG = LogUtils.makeLogTag(TracksPreferenceManager.class); - - private final Context mContext; - private final SharedPreferences mSharedPreferences; - private final PreferenceAccessor mPreferenceAccessor; - - private static final String FONT_FAMILY_SANS_SERIF = "FONT_FAMILY_SANS_SERIF"; - private static final String EDGE_TYPE_DEFAULT = "EDGE_TYPE_NONE"; - private static final Map OPACITY_MAPPING = new HashMap<>(); - private static final Map FONT_FAMILY_MAPPING = new HashMap<>(); - private static final Map EDGE_TYPE_MAPPING = new HashMap<>(); - - private ListPreference mCaptionFontScaleListPreference; - private ListPreference mCaptionFontFamilyListPreference; - private ListPreference mCaptionTextColorListPreference; - private ListPreference mCaptionTextOpacityListPreference; - private ListPreference mCaptionEdgeTypeListPreference; - private ListPreference mCaptionBackgroundColorListPreference; - private ListPreference mCaptionBackgroundOpacityListPreference; - - private CheckBoxPreference mCaptionAvailability; - private boolean isInitialized = false; - - static { - OPACITY_MAPPING.put("FF", "100"); - OPACITY_MAPPING.put("BF", "75"); - OPACITY_MAPPING.put("80", "50"); - OPACITY_MAPPING.put("3F", "25"); - } - - static { - FONT_FAMILY_MAPPING.put("FONT_FAMILY_SANS_SERIF", TextTrackStyle.FONT_FAMILY_SANS_SERIF); - FONT_FAMILY_MAPPING.put("FONT_FAMILY_SERIF", TextTrackStyle.FONT_FAMILY_SERIF); - FONT_FAMILY_MAPPING.put("FONT_FAMILY_MONOSPACED_SANS_SERIF", - TextTrackStyle.FONT_FAMILY_MONOSPACED_SANS_SERIF); - } - - static { - EDGE_TYPE_MAPPING.put("EDGE_TYPE_NONE", TextTrackStyle.EDGE_TYPE_NONE); - EDGE_TYPE_MAPPING.put("EDGE_TYPE_OUTLINE", TextTrackStyle.EDGE_TYPE_OUTLINE); - EDGE_TYPE_MAPPING.put("EDGE_TYPE_DROP_SHADOW", TextTrackStyle.EDGE_TYPE_DROP_SHADOW); - } - - public TracksPreferenceManager(Context context) { - mContext = context; - mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); - mSharedPreferences.registerOnSharedPreferenceChangeListener(this); - mPreferenceAccessor = VideoCastManager.getInstance().getPreferenceAccessor(); - } - - public TextTrackStyle getTextTrackStyle() { - final TextTrackStyle textTrackStyle = TextTrackStyle.fromSystemSettings(mContext); - if (Utils.IS_KITKAT_OR_ABOVE) { - return textTrackStyle; - } else { - // we need to populate all the fields ourselves - textTrackStyle.setFontGenericFamily(FONT_FAMILY_MAPPING.get(getFontFamily())); - textTrackStyle.setBackgroundColor(Color.parseColor(getBackgroundColor())); - textTrackStyle.setEdgeType(EDGE_TYPE_MAPPING.get(getEdgeType())); - textTrackStyle.setFontScale(getFontScale()); - boolean isBold = Typeface.DEFAULT.isBold(); - boolean isItalic = Typeface.DEFAULT.isItalic(); - int fontStyle = TextTrackStyle.FONT_STYLE_NORMAL; - if (isBold && isItalic) { - fontStyle = TextTrackStyle.FONT_STYLE_BOLD_ITALIC; - } else if (!isBold && !isItalic) { - fontStyle = TextTrackStyle.FONT_STYLE_NORMAL; - } else if (isBold) { - fontStyle = TextTrackStyle.FONT_STYLE_BOLD; - } - textTrackStyle.setFontStyle(fontStyle); - textTrackStyle.setForegroundColor( - combineColorAndOpacity(getTextColor(), getTextOpacity())); - LOGD(TAG, "Edge is: " + getEdgeType()); - textTrackStyle.setBackgroundColor(combineColorAndOpacity(getBackgroundColor(), - getBackgroundOpacity()) - ); - } - - return textTrackStyle; - } - - @SuppressLint("NewApi") - public boolean isCaptionEnabled() { - if (Utils.IS_KITKAT_OR_ABOVE) { - CaptioningManager captioningManager = - (CaptioningManager) mContext.getSystemService(Context.CAPTIONING_SERVICE); - return captioningManager.isEnabled(); - } else { - return mPreferenceAccessor.getBooleanFromPreference( - mContext.getString(R.string.ccl_key_caption_enabled), false); - } - } - - public void setFontFamily(String fontFamily) { - mPreferenceAccessor.saveStringToPreference( - mContext.getString(R.string.ccl_key_caption_font_family), fontFamily); - } - - public String getFontFamily() { - return mPreferenceAccessor.getStringFromPreference( - mContext.getString(R.string.ccl_key_caption_font_family), FONT_FAMILY_SANS_SERIF); - } - - public void setFontScale(String value) { - mPreferenceAccessor.saveStringToPreference( - mContext.getString(R.string.ccl_key_caption_font_scale), value); - } - - public float getFontScale() { - String scaleStr = mPreferenceAccessor.getStringFromPreference( - mContext.getString(R.string.ccl_key_caption_font_scale), - String.valueOf(TextTrackStyle.DEFAULT_FONT_SCALE)); - return Float.parseFloat(scaleStr); - } - - public void setTextColor(String textColor) { - mPreferenceAccessor.saveStringToPreference( - mContext.getString(R.string.ccl_key_caption_text_color), textColor); - } - - public String getTextColor() { - return mPreferenceAccessor.getStringFromPreference( - mContext.getString(R.string.ccl_key_caption_text_color), - mContext.getString(R.string.ccl_prefs_caption_text_color_value_default)); - } - - public void setTextOpacity(String textColor) { - mPreferenceAccessor.saveStringToPreference( - mContext.getString(R.string.ccl_key_caption_text_opacity), textColor); - } - - public String getTextOpacity() { - return mPreferenceAccessor.getStringFromPreference( - mContext.getString(R.string.ccl_key_caption_text_opacity), - mContext.getString(R.string.ccl_prefs_caption_text_opacity_value_default)); - } - - public void setEdgeType(String textColor) { - mPreferenceAccessor.saveStringToPreference( - mContext.getString(R.string.ccl_key_caption_edge_type), textColor); - } - - public String getEdgeType() { - return mPreferenceAccessor.getStringFromPreference( - mContext.getString(R.string.ccl_key_caption_edge_type), EDGE_TYPE_DEFAULT); - } - - public void setBackgroundColor(Context mContext, String textColor) { - mPreferenceAccessor.saveStringToPreference( - mContext.getString(R.string.ccl_key_caption_background_color), textColor); - } - - public String getBackgroundColor() { - return mPreferenceAccessor.getStringFromPreference( - mContext.getString(R.string.ccl_key_caption_background_color), - mContext.getString(R.string.ccl_prefs_caption_background_color_value_default)); - } - - public void setBackgroundOpacity(String textColor) { - mPreferenceAccessor.saveStringToPreference( - mContext.getString(R.string.ccl_key_caption_background_opacity), textColor); - } - - public String getBackgroundOpacity() { - return mPreferenceAccessor.getStringFromPreference( - mContext.getString(R.string.ccl_key_caption_background_opacity), - mContext.getString(R.string.ccl_prefs_caption_background_opacity_value_default)); - } - - public void setUpPreferences(PreferenceScreen screen) { - mCaptionAvailability = (CheckBoxPreference) screen.findPreference( - mContext.getString(R.string.ccl_key_caption_enabled)); - - mCaptionFontScaleListPreference = (ListPreference) screen.findPreference( - mContext.getString(R.string.ccl_key_caption_font_scale)); - - mCaptionFontFamilyListPreference = (ListPreference) screen.findPreference( - mContext.getString(R.string.ccl_key_caption_font_family)); - - mCaptionTextColorListPreference = (ListPreference) screen.findPreference( - mContext.getString(R.string.ccl_key_caption_text_color)); - - mCaptionTextOpacityListPreference = (ListPreference) screen.findPreference( - mContext.getString(R.string.ccl_key_caption_text_opacity)); - - mCaptionEdgeTypeListPreference = (ListPreference) screen.findPreference( - mContext.getString(R.string.ccl_key_caption_edge_type)); - - mCaptionBackgroundColorListPreference = (ListPreference) screen.findPreference( - mContext.getString(R.string.ccl_key_caption_background_color)); - - mCaptionBackgroundOpacityListPreference = (ListPreference) screen.findPreference( - mContext.getString(R.string.ccl_key_caption_background_opacity)); - isInitialized = true; - - onSharedPreferenceChanged(mSharedPreferences, - mContext.getString(R.string.ccl_key_caption_enabled), false); - onSharedPreferenceChanged(mSharedPreferences, - mContext.getString(R.string.ccl_key_caption_font_family), false); - onSharedPreferenceChanged(mSharedPreferences, - mContext.getString(R.string.ccl_key_caption_font_scale), false); - onSharedPreferenceChanged(mSharedPreferences, - mContext.getString(R.string.ccl_key_caption_text_color), false); - onSharedPreferenceChanged(mSharedPreferences, - mContext.getString(R.string.ccl_key_caption_text_opacity), false); - onSharedPreferenceChanged(mSharedPreferences, - mContext.getString(R.string.ccl_key_caption_edge_type), false); - onSharedPreferenceChanged(mSharedPreferences, - mContext.getString(R.string.ccl_key_caption_background_color), false); - onSharedPreferenceChanged(mSharedPreferences, - mContext.getString(R.string.ccl_key_caption_background_opacity), false); - } - - private void setCaptionAvailability(boolean status) { - mCaptionFontScaleListPreference.setEnabled(status); - mCaptionFontFamilyListPreference.setEnabled(status); - mCaptionTextColorListPreference.setEnabled(status); - mCaptionTextOpacityListPreference.setEnabled(status); - mCaptionEdgeTypeListPreference.setEnabled(status); - mCaptionBackgroundColorListPreference.setEnabled(status); - mCaptionBackgroundOpacityListPreference.setEnabled(status); - } - - /** - * Returns the label of the selected item in a list preference, to be used for the summary of - * that preference item - */ - private String getCaptionSummaryForList(SharedPreferences sharedPreferences, int keyResourceId, - int defaultResourceId, int namesResourceId, int valuesResourceId) { - Resources resources = mContext.getResources(); - String value = sharedPreferences.getString(resources.getString(keyResourceId), - resources.getString(defaultResourceId)); - String[] labels = resources.getStringArray(namesResourceId); - String[] values = resources.getStringArray(valuesResourceId); - for (int i = 0; i < values.length; i++) { - if (values[i].equals(value)) { - return labels[i]; - } - } - return ""; - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - onSharedPreferenceChanged(sharedPreferences, key, true); - } - - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, - String key, boolean broadcast) { - if (!isInitialized) { - return; - } - if (mContext.getString(R.string.ccl_key_caption_enabled).equals(key)) { - mCaptionAvailability.setSummary( - mCaptionAvailability.isChecked() ? R.string.ccl_prefs_caption_enabled - : R.string.ccl_prefs_caption_disabled - ); - setCaptionAvailability(mCaptionAvailability.isChecked()); - if (broadcast) { - VideoCastManager.getInstance() - .onTextTrackEnabledChanged(mCaptionAvailability.isChecked()); - } - return; - } - - if (mContext.getString(R.string.ccl_key_caption_font_scale).equals(key)) { - mCaptionFontScaleListPreference - .setSummary( - getCaptionSummaryForList(sharedPreferences, - R.string.ccl_key_caption_font_scale, - R.string.ccl_prefs_caption_font_scale_value_default, - R.array.ccl_prefs_caption_font_scale_names, - R.array.ccl_prefs_caption_font_scale_values) - ); - } else if (mContext.getString(R.string.ccl_key_caption_font_family).equals(key)) { - mCaptionFontFamilyListPreference - .setSummary( - getCaptionSummaryForList(sharedPreferences, - R.string.ccl_key_caption_font_family, - R.string.ccl_prefs_caption_font_family_value_default, - R.array.ccl_prefs_caption_font_family_names, - R.array.ccl_prefs_caption_font_family_values) - ); - } else if (mContext.getString(R.string.ccl_key_caption_text_color).equals(key)) { - mCaptionTextColorListPreference - .setSummary( - getCaptionSummaryForList(sharedPreferences, - R.string.ccl_key_caption_text_color, - R.string.ccl_prefs_caption_text_color_value_default, - R.array.ccl_prefs_caption_color_names, - R.array.ccl_prefs_caption_color_values) - ); - } else if (mContext.getString(R.string.ccl_key_caption_text_opacity).equals(key)) { - String opacity = mPreferenceAccessor.getStringFromPreference( - mContext.getString(R.string.ccl_key_caption_text_opacity), - mContext.getString(R.string.ccl_prefs_caption_text_opacity_value_default)); - mCaptionTextOpacityListPreference - .setSummary(OPACITY_MAPPING.get(opacity) + "%%"); - } else if (mContext.getString(R.string.ccl_key_caption_edge_type).equals(key)) { - mCaptionEdgeTypeListPreference - .setSummary( - getCaptionSummaryForList(sharedPreferences, - R.string.ccl_key_caption_edge_type, - R.string.ccl_prefs_caption_edge_type_value_default, - R.array.ccl_prefs_caption_edge_type_names, - R.array.ccl_prefs_caption_edge_type_values) - ); - } else if (mContext.getString(R.string.ccl_key_caption_background_color).equals(key)) { - mCaptionBackgroundColorListPreference - .setSummary(getCaptionSummaryForList(sharedPreferences, - R.string.ccl_key_caption_background_color, - R.string.ccl_prefs_caption_background_color_value_default, - R.array.ccl_prefs_caption_color_names, - R.array.ccl_prefs_caption_color_values)); - } else if (mContext.getString(R.string.ccl_key_caption_background_opacity).equals(key)) { - String opacity = mPreferenceAccessor.getStringFromPreference( - mContext.getString(R.string.ccl_key_caption_background_opacity), - mContext.getString(R.string.ccl_prefs_caption_background_opacity_value_default)); - mCaptionBackgroundOpacityListPreference - .setSummary(OPACITY_MAPPING.get(opacity) + "%%"); - } - if (broadcast) { - VideoCastManager.getInstance().onTextTrackStyleChanged(getTextTrackStyle()); - } - - } - - private static int combineColorAndOpacity(String color, String opacity) { - color = color.replace("#", ""); - return Color.parseColor("#" + opacity + color); - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/ui/TracksChooserDialog.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/ui/TracksChooserDialog.java deleted file mode 100644 index ac3ca8054..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/ui/TracksChooserDialog.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.tracks.ui; - -import com.google.android.gms.cast.MediaInfo; -import com.google.android.gms.cast.MediaTrack; -import com.google.android.libraries.cast.companionlibrary.R; -import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager; -import com.google.android.libraries.cast.companionlibrary.utils.Utils; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ListView; -import android.widget.TabHost; -import android.widget.TextView; - -import java.util.ArrayList; -import java.util.List; - -/** - * A dialog to show the available tracks (Text and Audio) for user to select. - */ -public class TracksChooserDialog extends DialogFragment { - - private VideoCastManager mCastManager; - private long[] mActiveTracks = null; - private MediaInfo mMediaInfo; - private TracksListAdapter mTextAdapter; - private TracksListAdapter mAudioVideoAdapter; - private List mTextTracks = new ArrayList<>(); - private List mAudioTracks = new ArrayList<>(); - private static final long TEXT_TRACK_NONE_ID = -1; - private int mSelectedTextPosition = 0; - private int mSelectedAudioPosition = -1; - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - LayoutInflater inflater = getActivity().getLayoutInflater(); - View view = inflater.inflate(R.layout.custom_tracks_dialog_layout, null); - setUpView(view); - - builder.setView(view) - .setPositiveButton(getString(R.string.ccl_ok), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - List selectedTracks = new ArrayList<>(); - MediaTrack textTrack = mTextAdapter.getSelectedTrack(); - if (textTrack.getId() != TEXT_TRACK_NONE_ID) { - selectedTracks.add(textTrack); - } - MediaTrack audioVideoTrack = mAudioVideoAdapter.getSelectedTrack(); - if (audioVideoTrack != null) { - selectedTracks.add(audioVideoTrack); - } - mCastManager.notifyTracksSelectedListeners(selectedTracks); - TracksChooserDialog.this.getDialog().cancel(); - } - }) - .setNegativeButton(R.string.ccl_cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - TracksChooserDialog.this.getDialog().cancel(); - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - TracksChooserDialog.this.getDialog().cancel(); - } - }); - - return builder.create(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setRetainInstance(true); - Bundle mediaWrapper = getArguments().getBundle(VideoCastManager.EXTRA_MEDIA); - mMediaInfo = Utils.bundleToMediaInfo(mediaWrapper); - mCastManager = VideoCastManager.getInstance(); - mActiveTracks = mCastManager.getActiveTrackIds(); - List allTracks = mMediaInfo.getMediaTracks(); - if (allTracks == null || allTracks.isEmpty()) { - Utils.showToast(getActivity(), R.string.ccl_caption_no_tracks_available); - dismiss(); - } - } - - /** - * This is to get around the following bug: - * https://code.google.com/p/android/issues/detail?id=17423 - */ - @Override - public void onDestroyView() { - if (getDialog() != null && getRetainInstance()) { - getDialog().setDismissMessage(null); - } - super.onDestroyView(); - } - - private void setUpView(View view) { - ListView listView1 = (ListView) view.findViewById(R.id.listview1); - ListView listView2 = (ListView) view.findViewById(R.id.listview2); - TextView textEmptyMessageView = (TextView) view.findViewById(R.id.text_empty_message); - TextView audioEmptyMessageView = (TextView) view.findViewById(R.id.audio_empty_message); - partitionTracks(); - - mTextAdapter = new TracksListAdapter(getActivity(), R.layout.tracks_row_layout, - mTextTracks, mSelectedTextPosition); - mAudioVideoAdapter = new TracksListAdapter(getActivity(), R.layout.tracks_row_layout, - mAudioTracks, mSelectedAudioPosition); - - listView1.setAdapter(mTextAdapter); - listView2.setAdapter(mAudioVideoAdapter); - - TabHost tabs = (TabHost) view.findViewById(R.id.tabhost); - tabs.setup(); - - // create tab 1 - TabHost.TabSpec tab1 = tabs.newTabSpec("tab1"); - if (mTextTracks == null || mTextTracks.isEmpty()) { - listView1.setVisibility(View.INVISIBLE); - tab1.setContent(R.id.text_empty_message); - } else { - textEmptyMessageView.setVisibility(View.INVISIBLE); - tab1.setContent(R.id.listview1); - } - tab1.setIndicator(getString(R.string.ccl_caption_subtitles)); - tabs.addTab(tab1); - - // create tab 2 - TabHost.TabSpec tab2 = tabs.newTabSpec("tab2"); - if (mAudioTracks == null || mAudioTracks.isEmpty()) { - listView2.setVisibility(View.INVISIBLE); - tab2.setContent(R.id.audio_empty_message); - } else { - audioEmptyMessageView.setVisibility(View.INVISIBLE); - tab2.setContent(R.id.listview2); - } - tab2.setIndicator(getString(R.string.ccl_caption_audio)); - tabs.addTab(tab2); - } - - private MediaTrack buildNoneTrack() { - return new MediaTrack.Builder(TEXT_TRACK_NONE_ID, MediaTrack.TYPE_TEXT) - .setName(getString(R.string.ccl_none)) - .setSubtype(MediaTrack.SUBTYPE_CAPTIONS) - .setContentId("").build(); - } - - /** - * This method loops through the tracks and partitions them into a group of Text tracks and a - * group of Audio tracks, and skips over the Video tracks. - */ - private void partitionTracks() { - List allTracks = mMediaInfo.getMediaTracks(); - mAudioTracks.clear(); - mTextTracks.clear(); - mTextTracks.add(buildNoneTrack()); - mSelectedTextPosition = 0; - mSelectedAudioPosition = -1; - if (allTracks != null) { - int textPosition = 1; /* start from 1 since we have a NONE selection at the beginning */ - int audioPosition = 0; - for (MediaTrack track : allTracks) { - switch (track.getType()) { - case MediaTrack.TYPE_TEXT: - mTextTracks.add(track); - if (mActiveTracks != null) { - for (long mActiveTrack : mActiveTracks) { - if (mActiveTrack == track.getId()) { - mSelectedTextPosition = textPosition; - } - } - } - textPosition++; - break; - case MediaTrack.TYPE_AUDIO: - mAudioTracks.add(track); - if (mActiveTracks != null) { - for (long mActiveTrack : mActiveTracks) { - if (mActiveTrack == track.getId()) { - mSelectedAudioPosition = audioPosition; - } - } - } - audioPosition++; - break; - } - } - } - } - - /** - * Call this static method to create a new instance of the dialog. - */ - public static TracksChooserDialog newInstance(MediaInfo mediaInfo) { - TracksChooserDialog fragment = new TracksChooserDialog(); - Bundle bundle = new Bundle(); - bundle.putBundle(VideoCastManager.EXTRA_MEDIA, Utils.mediaInfoToBundle(mediaInfo)); - fragment.setArguments(bundle); - return fragment; - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/ui/TracksListAdapter.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/ui/TracksListAdapter.java deleted file mode 100644 index a36e8d1dd..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/cast/tracks/ui/TracksListAdapter.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.cast.tracks.ui; - -import com.google.android.gms.cast.MediaTrack; -import com.google.android.libraries.cast.companionlibrary.R; - -import android.app.Activity; -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.RadioButton; -import android.widget.TextView; - -import java.util.ArrayList; -import java.util.List; - -/** - * An {@link android.widget.ArrayAdapter} for presenting tracks. - */ -public class TracksListAdapter extends ArrayAdapter - implements View.OnClickListener { - - private final List mTracks; - private final Context mContext; - private int mSelectedPosition = -1; - - public TracksListAdapter(Context context, int resource, List tracks, - int activePosition) { - super(context, resource); - this.mContext = context; - mTracks = new ArrayList<>(); - mTracks.addAll(tracks); - mSelectedPosition = activePosition; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Holder holder; - - if (convertView == null) { - LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( - Activity.LAYOUT_INFLATER_SERVICE); - convertView = inflater.inflate(R.layout.tracks_row_layout, parent, false); - - holder = new Holder((TextView) convertView.findViewById(R.id.text), - (RadioButton) convertView.findViewById(R.id.radio)); - convertView.setTag(holder); - } else { - holder = (Holder) convertView.getTag(); - } - holder.radio.setTag(position); - holder.radio.setChecked(mSelectedPosition == position); - convertView.setOnClickListener(this); - holder.label.setText(mTracks.get(position).getName()); - return convertView; - } - - @Override - public int getCount() { - return mTracks == null ? 0 : mTracks.size(); - } - - @Override - public void onClick(View v) { - Holder holder = (Holder) v.getTag(); - mSelectedPosition = (Integer) holder.radio.getTag(); - notifyDataSetChanged(); - } - - private class Holder { - - private final TextView label; - private final RadioButton radio; - - private Holder(TextView label, RadioButton radio) { - this.label = label; - this.radio = radio; - } - } - - public MediaTrack getSelectedTrack() { - if (mSelectedPosition >= 0) { - return mTracks.get(mSelectedPosition); - } - return null; - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/notification/VideoCastNotificationService.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/notification/VideoCastNotificationService.java deleted file mode 100644 index dc9bb7016..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/notification/VideoCastNotificationService.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.notification; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGD; -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.gms.cast.MediaInfo; -import com.google.android.gms.cast.MediaMetadata; -import com.google.android.gms.cast.MediaStatus; -import com.google.android.libraries.cast.companionlibrary.R; -import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager; -import com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumerImpl; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.player.VideoCastControllerActivity; -import com.google.android.libraries.cast.companionlibrary.utils.FetchBitmapTask; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; -import com.google.android.libraries.cast.companionlibrary.utils.Utils; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Bundle; -import android.os.IBinder; -import android.support.v4.app.TaskStackBuilder; -import android.support.v7.app.NotificationCompat; - -/** - * A service to provide status bar Notifications when we are casting. For JB+ versions, notification - * area provides a play/pause toggle and an "x" button to disconnect but that for GB, we do not - * show that due to the framework limitations. - */ -public class VideoCastNotificationService extends Service { - - private static final String TAG = LogUtils.makeLogTag(VideoCastNotificationService.class); - - public static final String ACTION_TOGGLE_PLAYBACK = - "com.google.android.libraries.cast.companionlibrary.action.toggleplayback"; - public static final String ACTION_STOP = - "com.google.android.libraries.cast.companionlibrary.action.stop"; - public static final String ACTION_VISIBILITY = - "com.google.android.libraries.cast.companionlibrary.action.notificationvisibility"; - private static final int NOTIFICATION_ID = 1; - public static final String NOTIFICATION_VISIBILITY = "visible"; - - private Bitmap mVideoArtBitmap; - private boolean mIsPlaying; - private Class mTargetActivity; - private int mOldStatus = -1; - private Notification mNotification; - private boolean mVisible; - private VideoCastManager mCastManager; - private VideoCastConsumerImpl mConsumer; - private FetchBitmapTask mBitmapDecoderTask; - private int mDimensionInPixels; - - @Override - public void onCreate() { - super.onCreate(); - mDimensionInPixels = Utils.convertDpToPixel(VideoCastNotificationService.this, - getResources().getDimension(R.dimen.ccl_notification_image_size)); - mCastManager = VideoCastManager.getInstance(); - readPersistedData(); - if (!mCastManager.isConnected() && !mCastManager.isConnecting()) { - mCastManager.reconnectSessionIfPossible(); - } - mConsumer = new VideoCastConsumerImpl() { - @Override - public void onApplicationDisconnected(int errorCode) { - LOGD(TAG, "onApplicationDisconnected() was reached, stopping the notification" - + " service"); - stopSelf(); - } - - @Override - public void onRemoteMediaPlayerStatusUpdated() { - int mediaStatus = mCastManager.getPlaybackStatus(); - VideoCastNotificationService.this.onRemoteMediaPlayerStatusUpdated(mediaStatus); - } - - @Override - public void onUiVisibilityChanged(boolean visible) { - mVisible = !visible; - if (mVisible && (mNotification != null)) { - startForeground(NOTIFICATION_ID, mNotification); - } else { - stopForeground(true); - } - } - }; - mCastManager.addVideoCastConsumer(mConsumer); - - } - - @Override - public IBinder onBind(Intent arg0) { - return null; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - LOGD(TAG, "onStartCommand"); - if (intent != null) { - - String action = intent.getAction(); - if (ACTION_VISIBILITY.equals(action)) { - mVisible = intent.getBooleanExtra(NOTIFICATION_VISIBILITY, false); - LOGD(TAG, "onStartCommand(): Action: ACTION_VISIBILITY " + mVisible); - onRemoteMediaPlayerStatusUpdated(mCastManager.getPlaybackStatus()); - if (mNotification == null) { - try { - setUpNotification(mCastManager.getRemoteMediaInformation()); - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "onStartCommand() failed to get media", e); - } - } - if (mVisible && mNotification != null) { - startForeground(NOTIFICATION_ID, mNotification); - } else { - stopForeground(true); - } - } else { - LOGD(TAG, "onStartCommand(): Action: none"); - } - - } else { - LOGD(TAG, "onStartCommand(): Intent was null"); - } - - return Service.START_STICKY; - } - - private void setUpNotification(final MediaInfo info) - throws TransientNetworkDisconnectionException, NoConnectionException { - if (info == null) { - return; - } - if (mBitmapDecoderTask != null) { - mBitmapDecoderTask.cancel(false); - } - Uri imgUri = null; - try { - if (!info.getMetadata().hasImages()) { - build(info, null, mIsPlaying); - return; - } else { - imgUri = info.getMetadata().getImages().get(0).getUrl(); - } - } catch (CastException e) { - LOGE(TAG, "Failed to build notification", e); - } - mBitmapDecoderTask = new FetchBitmapTask() { - @Override - protected void onPostExecute(Bitmap bitmap) { - try { - mVideoArtBitmap = Utils.scaleAndCenterCropBitmap(bitmap, mDimensionInPixels, - mDimensionInPixels); - build(info, mVideoArtBitmap, mIsPlaying); - } catch (CastException | NoConnectionException - | TransientNetworkDisconnectionException e) { - LOGE(TAG, "Failed to set notification for " + info.toString(), e); - } - if (mVisible && (mNotification != null)) { - startForeground(NOTIFICATION_ID, mNotification); - } - if (this == mBitmapDecoderTask) { - mBitmapDecoderTask = null; - } - } - }; - mBitmapDecoderTask.execute(imgUri); - } - - /** - * Removes the existing notification. - */ - private void removeNotification() { - ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)). - cancel(NOTIFICATION_ID); - } - - private void onRemoteMediaPlayerStatusUpdated(int mediaStatus) { - if (mOldStatus == mediaStatus) { - // not need to make any updates here - return; - } - mOldStatus = mediaStatus; - LOGD(TAG, "onRemoteMediaPlayerStatusUpdated() reached with status: " + mediaStatus); - try { - switch (mediaStatus) { - case MediaStatus.PLAYER_STATE_BUFFERING: // (== 4) - mIsPlaying = false; - setUpNotification(mCastManager.getRemoteMediaInformation()); - break; - case MediaStatus.PLAYER_STATE_PLAYING: // (== 2) - mIsPlaying = true; - setUpNotification(mCastManager.getRemoteMediaInformation()); - break; - case MediaStatus.PLAYER_STATE_PAUSED: // (== 3) - mIsPlaying = false; - setUpNotification(mCastManager.getRemoteMediaInformation()); - break; - case MediaStatus.PLAYER_STATE_IDLE: // (== 1) - mIsPlaying = false; - if (!mCastManager.shouldRemoteUiBeVisible(mediaStatus, - mCastManager.getIdleReason())) { - stopForeground(true); - } else { - setUpNotification(mCastManager.getRemoteMediaInformation()); - } - break; - case MediaStatus.PLAYER_STATE_UNKNOWN: // (== 0) - mIsPlaying = false; - stopForeground(true); - break; - default: - break; - } - } catch (TransientNetworkDisconnectionException | NoConnectionException e) { - LOGE(TAG, "Failed to update the playback status due to network issues", e); - } - } - - /* - * (non-Javadoc) - * @see android.app.Service#onDestroy() - */ - @Override - public void onDestroy() { - if (mBitmapDecoderTask != null) { - mBitmapDecoderTask.cancel(false); - } - removeNotification(); - if (mCastManager != null && mConsumer != null) { - mCastManager.removeVideoCastConsumer(mConsumer); - mCastManager = null; - } - } - - /* - * Build the RemoteViews for the notification. We also need to add the appropriate "back stack" - * so when user goes into the CastPlayerActivity, she can have a meaningful "back" experience. - */ - private void build(MediaInfo info, Bitmap bitmap, boolean isPlaying) - throws CastException, TransientNetworkDisconnectionException, NoConnectionException { - - // Playback PendingIntent - Intent playbackIntent = new Intent(ACTION_TOGGLE_PLAYBACK); - playbackIntent.setPackage(getPackageName()); - PendingIntent playbackPendingIntent = PendingIntent - .getBroadcast(this, 0, playbackIntent, 0); - - // Disconnect PendingIntent - Intent stopIntent = new Intent(ACTION_STOP); - stopIntent.setPackage(getPackageName()); - PendingIntent stopPendingIntent = PendingIntent.getBroadcast(this, 0, stopIntent, 0); - - // Main Content PendingIntent - Bundle mediaWrapper = Utils.mediaInfoToBundle(mCastManager.getRemoteMediaInformation()); - Intent contentIntent = new Intent(this, mTargetActivity); - contentIntent.putExtra(VideoCastManager.EXTRA_MEDIA, mediaWrapper); - - // Media metadata - MediaMetadata metadata = info.getMetadata(); - String castingTo = getResources().getString(R.string.ccl_casting_to_device, - mCastManager.getDeviceName()); - TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); - stackBuilder.addParentStack(mTargetActivity); - stackBuilder.addNextIntent(contentIntent); - if (stackBuilder.getIntentCount() > 1) { - stackBuilder.editIntentAt(1).putExtra(VideoCastManager.EXTRA_MEDIA, mediaWrapper); - } - PendingIntent contentPendingIntent = - stackBuilder.getPendingIntent(NOTIFICATION_ID, PendingIntent.FLAG_UPDATE_CURRENT); - - int pauseOrStopResourceId = 0; - if (info.getStreamType() == MediaInfo.STREAM_TYPE_LIVE) { - pauseOrStopResourceId = R.drawable.ic_notification_stop_48dp; - } else { - pauseOrStopResourceId = R.drawable.ic_notification_pause_48dp; - } - int pauseOrPlayTextResourceId = isPlaying ? R.string.ccl_pause : R.string.ccl_play; - - NotificationCompat.Builder builder - = (NotificationCompat.Builder) new NotificationCompat.Builder(this) - .setSmallIcon(R.drawable.ic_stat_action_notification) - .setContentTitle(metadata.getString(MediaMetadata.KEY_TITLE)) - .setContentText(castingTo) - .setContentIntent(contentPendingIntent) - .setLargeIcon(bitmap) - .addAction(isPlaying ? pauseOrStopResourceId - : R.drawable.ic_notification_play_48dp, - getString(pauseOrPlayTextResourceId), playbackPendingIntent) - .addAction(R.drawable.ic_notification_disconnect_24dp, - getString(R.string.ccl_disconnect), - stopPendingIntent) - .setStyle(new NotificationCompat.MediaStyle() - .setShowActionsInCompactView(0, 1) - .setMediaSession(mCastManager.getMediaSessionCompatToken())) - .setOngoing(true) - .setShowWhen(false) - .setVisibility(Notification.VISIBILITY_PUBLIC); - - - mNotification = builder.build(); - - } - - private void togglePlayback() { - try { - mCastManager.togglePlayback(); - } catch (Exception e) { - LOGE(TAG, "Failed to toggle the playback", e); - } - } - - /* - * We try to disconnect application but even if that fails, we need to remove notification since - * that is the only way to get rid of it without going to the application - */ - private void stopApplication() { - try { - LOGD(TAG, "Calling stopApplication"); - mCastManager.disconnect(); - } catch (Exception e) { - LOGE(TAG, "Failed to disconnect application", e); - } - stopSelf(); - } - - /* - * Reads application ID and target activity from preference storage. - */ - private void readPersistedData() { - String targetName = mCastManager.getPreferenceAccessor().getStringFromPreference( - VideoCastManager.PREFS_KEY_CAST_ACTIVITY_NAME); - try { - if (targetName != null) { - mTargetActivity = Class.forName(targetName); - } else { - mTargetActivity = VideoCastControllerActivity.class; - } - - } catch (ClassNotFoundException e) { - LOGE(TAG, "Failed to find the targetActivity class", e); - } - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/remotecontrol/VideoIntentReceiver.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/remotecontrol/VideoIntentReceiver.java deleted file mode 100644 index 604ac6df3..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/remotecontrol/VideoIntentReceiver.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.remotecontrol; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGD; -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions - .TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.notification.VideoCastNotificationService; -import com.google.android.libraries.cast.companionlibrary.utils.LogUtils; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.view.KeyEvent; - -/** - * A {@link BroadcastReceiver} for receiving media button actions (from the lock screen) as well as - * the the status bar notification media actions. - */ -public class VideoIntentReceiver extends BroadcastReceiver { - - private static final String TAG = LogUtils.makeLogTag(VideoIntentReceiver.class); - - @Override - public void onReceive(Context context, Intent intent) { - VideoCastManager castMgr = VideoCastManager.getInstance(); - String action = intent.getAction(); - if (action == null) { - return; - } - switch (action) { - case VideoCastNotificationService.ACTION_TOGGLE_PLAYBACK: - try { - VideoCastManager.getInstance().togglePlayback(); - } catch (CastException | TransientNetworkDisconnectionException | - NoConnectionException e) { - LOGE(TAG, "onReceive() Failed to toggle playback "); - } - break; - case VideoCastNotificationService.ACTION_STOP: - LOGD(TAG, "Calling stopApplication from intent"); - castMgr.disconnect(); - break; - case Intent.ACTION_MEDIA_BUTTON: - // this is used when we toggle playback from lockscreen in versions prior to - // Lollipop - if (!intent.hasExtra(Intent.EXTRA_KEY_EVENT)) { - return; - } - KeyEvent keyEvent = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT); - if (keyEvent.getAction() != KeyEvent.ACTION_DOWN) { - return; - } - - if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { - try { - VideoCastManager.getInstance().togglePlayback(); - } catch (CastException | TransientNetworkDisconnectionException | - NoConnectionException e) { - LOGE(TAG, "onReceive() Failed to toggle playback "); - } - } - break; - } - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/FetchBitmapTask.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/FetchBitmapTask.java deleted file mode 100644 index 404e2dd26..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/FetchBitmapTask.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.utils; - -import android.annotation.TargetApi; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Build; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; - -/** - * An AsyncTask to fetch an image over HTTP and scale it to the desired size. Clients need to extend - * this and implement their own {@code onPostExecute(Bitmap bitmap)} method. It provides a uniform - * treatment of ThreadPool across various versions of Android. - */ -public abstract class FetchBitmapTask extends AsyncTask { - private final int mPreferredWidth; - private final int mPreferredHeight; - - /** - * Constructs a new FetchBitmapTask that will do scaling. - * - * @param preferredWidth The preferred image width. - * @param preferredHeight The preferred image height. - */ - public FetchBitmapTask(int preferredWidth, int preferredHeight) { - mPreferredWidth = preferredWidth; - mPreferredHeight = preferredHeight; - } - - /** - * Constructs a new FetchBitmapTask. No scaling will be performed if you use this constructor. - */ - public FetchBitmapTask() { - this(0, 0); - } - - @Override - protected Bitmap doInBackground(Uri... uris) { - if (uris.length != 1 || uris[0] == null) { - return null; - } - - Bitmap bitmap = null; - URL url; - try { - url = new URL(uris[0].toString()); - } catch (MalformedURLException e) { - return null; - } - HttpURLConnection urlConnection = null; - try { - urlConnection = (HttpURLConnection) url.openConnection(); - urlConnection.setDoInput(true); - - if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { - InputStream stream = new BufferedInputStream(urlConnection.getInputStream()); - bitmap = BitmapFactory.decodeStream(stream); - if ((mPreferredWidth > 0) && (mPreferredHeight > 0)) { - bitmap = scaleBitmap(bitmap); - } - } - } catch (IOException e) { /* ignore */ - } finally { - if (urlConnection != null) { - urlConnection.disconnect(); - } - } - - return bitmap; - } - - /** - * Executes the task. - */ - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public void execute(Uri uri) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, uri); - } else { - execute(new Uri[] {uri}); - } - } - - /* - * Scales the bitmap to the preferred width and height. - * - * @param bitmap The bitmap to scale. - * @return The scaled bitmap. - */ - private Bitmap scaleBitmap(Bitmap bitmap) { - int width = bitmap.getWidth(); - int height = bitmap.getHeight(); - - // Calculate deltas. - int dw = width - mPreferredWidth; - int dh = height - mPreferredHeight; - - if ((dw == 0) && (dh == 0)) { - return bitmap; - } - - float scaleFactor; - if ((dw > 0) || (dh > 0)) { - // Icon is too big; scale down. - float scaleWidth = (float) mPreferredWidth / width; - float scaleHeight = (float) mPreferredHeight / height; - scaleFactor = Math.min(scaleHeight, scaleWidth); - } else { - // Icon is too small; scale up. - float scaleWidth = width / (float) mPreferredWidth; - float scaleHeight = height / (float) mPreferredHeight; - scaleFactor = Math.min(scaleHeight, scaleWidth); - } - - int finalWidth = (int) ((width * scaleFactor) + 0.5f); - int finalHeight = (int) ((height * scaleFactor) + 0.5f); - - return Bitmap.createScaledBitmap(bitmap, finalWidth, finalHeight, false); - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/LogUtils.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/LogUtils.java deleted file mode 100644 index 1858614a3..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/LogUtils.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.utils; - -import com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager; - -import android.util.Log; - -/** - * Provides a simple wrapper to control logging in development vs production environment. This - * library should only use the wrapper methods that this class provides. - */ -public class LogUtils { - - private static final String LOG_PREFIX = "ccl_"; - private static final int LOG_PREFIX_LENGTH = LOG_PREFIX.length(); - private static final int MAX_LOG_TAG_LENGTH = 23; - - private static final boolean DEBUG = false; - - private LogUtils() { - } - - public static String makeLogTag(String str) { - if (str.length() > MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH) { - return LOG_PREFIX + str.substring(0, MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH - 1); - } - - return LOG_PREFIX + str; - } - - /** - * WARNING: Don't use this when obfuscating class names with Proguard! - */ - public static String makeLogTag(Class cls) { - return makeLogTag(cls.getSimpleName()); - } - - @SuppressWarnings("unused") - public static final void LOGD(final String tag, String message) { - if (DEBUG || Log.isLoggable(tag, Log.DEBUG)) { - Log.d(tag, getVersionPrefix() + message); - } - } - - @SuppressWarnings("unused") - public static final void LOGD(final String tag, String message, Throwable cause) { - if (DEBUG || Log.isLoggable(tag, Log.DEBUG)) { - Log.d(tag, getVersionPrefix() + message, cause); - } - } - - public static final void LOGV(final String tag, String message) { - if (DEBUG && Log.isLoggable(tag, Log.VERBOSE)) { - Log.v(tag, getVersionPrefix() + message); - } - } - - public static final void LOGV(final String tag, String message, Throwable cause) { - if (DEBUG && Log.isLoggable(tag, Log.VERBOSE)) { - Log.v(tag, getVersionPrefix() + message, cause); - } - } - - public static final void LOGI(final String tag, String message) { - Log.i(tag, getVersionPrefix() + message); - } - - public static final void LOGI(final String tag, String message, Throwable cause) { - Log.i(tag, message, cause); - } - - public static final void LOGW(final String tag, String message) { - Log.w(tag, getVersionPrefix() + message); - } - - public static final void LOGW(final String tag, String message, Throwable cause) { - Log.w(tag, getVersionPrefix() + message, cause); - } - - public static final void LOGE(final String tag, String message) { - Log.e(tag, getVersionPrefix() + message); - } - - public static final void LOGE(final String tag, String message, Throwable cause) { - Log.e(tag, getVersionPrefix() + message, cause); - } - - public static final String getVersionPrefix() { - return "[v" + BaseCastManager.getCclVersion() + "] "; - } - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/PreferenceAccessor.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/PreferenceAccessor.java deleted file mode 100644 index b329c1a6f..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/PreferenceAccessor.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.utils; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; - -/** - * A class to streamline access to the Preference storage for both reading and writing. - */ -public class PreferenceAccessor { - private final SharedPreferences mSharedPreference; - - public PreferenceAccessor(Context context) { - mSharedPreference = PreferenceManager.getDefaultSharedPreferences(context); - } - - - /** - * Saves a string value under the provided key in the preference manager. If value - * is null, then the provided key will be removed from the preferences. - */ - public void saveStringToPreference(String key, String value) { - if (value == null) { - // we want to remove - mSharedPreference.edit().remove(key).apply(); - } else { - mSharedPreference.edit().putString(key, value).apply(); - } - } - - /** - * Saves a float value under the provided key in the preference manager. If {@code value} - * is {@code null}, then the provided key will be removed from the preferences. - */ - public void saveFloatToPreference(String key, Float value) { - if (value == null) { - // we want to remove - mSharedPreference.edit().remove(key).apply(); - } else { - mSharedPreference.edit().putFloat(key, value).apply(); - } - } - - /** - * Saves an integer value under the provided key in the preference manager. If {@code value} - * is {@code null}, then the provided key will be removed from the preferences. - */ - public void saveIntToPreference(String key, Integer value) { - if (value == null) { - // we want to remove - mSharedPreference.edit().remove(key).apply(); - } else { - mSharedPreference.edit().putInt(key, value).apply(); - } - } - - /** - * Saves a long value under the provided key in the preference manager. If {@code value} - * is {@code null}, then the provided key will be removed from the preferences. - */ - public void saveLongToPreference(String key, Long value) { - if (value == null) { - // we want to remove - mSharedPreference.edit().remove(key).apply(); - } else { - mSharedPreference.edit().putLong(key, value).apply(); - } - - } - - /** - * Saves a boolean value under the provided key in the preference manager. If value - * is null, then the provided key will be removed from the preferences. - */ - public void saveBooleanToPreference(String key, Boolean value) { - if (value == null) { - // we want to remove - mSharedPreference.edit().remove(key).apply(); - } else { - mSharedPreference.edit().putBoolean(key, value).apply(); - } - } - - /** - * Retrieves a String value from preference manager. If no such key exists, it will return - * null. - */ - public String getStringFromPreference(String key) { - return getStringFromPreference(key, null); - } - - /** - * Retrieves a String value from preference manager. If no such key exists, it will return the - * defaultValue. - */ - public String getStringFromPreference(String key, String defaultValue) { - return mSharedPreference.getString(key, defaultValue); - } - - /** - * Retrieves a float value from preference manager. If no such key exists, it will return - * Float.MIN_VALUE. - */ - public float getFloatFromPreference(String key) { - return mSharedPreference.getFloat(key, Float.MIN_VALUE); - } - - /** - * Retrieves an integer value from preference manager. If no such key exists, it will return - * Integer.MIN_VALUE. - */ - public int getIntFromPreference(String key) { - return mSharedPreference.getInt(key, Integer.MIN_VALUE); - } - - /** - * Retrieves an integer value from preference manager. If no such key exists, it will return - * value provided by the {@code defaultValue}. - */ - public int getIntFromPreference(String key, int defaultValue) { - return mSharedPreference.getInt(key, defaultValue); - } - - /** - * Retrieves a long value from preference manager. If no such key exists, it will return the - * value provided as defaultValue - */ - public long getLongFromPreference(String key, long defaultValue) { - return mSharedPreference.getLong(key, defaultValue); - } - - /** - * Retrieves a boolean value from preference manager. If no such key exists, it will return the - * value provided as defaultValue - */ - public boolean getBooleanFromPreference(String key, boolean defaultValue) { - return mSharedPreference.getBoolean(key, defaultValue); - } - - - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/Utils.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/Utils.java deleted file mode 100644 index ae3b45a80..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/utils/Utils.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.utils; - -import static com.google.android.libraries.cast.companionlibrary.utils.LogUtils.LOGE; - -import com.google.android.gms.cast.MediaInfo; -import com.google.android.gms.cast.MediaMetadata; -import com.google.android.gms.cast.MediaQueueItem; -import com.google.android.gms.cast.MediaTrack; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesUtil; -import com.google.android.gms.common.images.WebImage; - -import android.app.Activity; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.RectF; -import android.net.Uri; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.os.Build; -import android.os.Bundle; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.TypedValue; -import android.widget.Toast; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; - -/** - * A collection of utility methods, all static. - */ -public final class Utils { - - private static final String TAG = LogUtils.makeLogTag(Utils.class); - private static final String KEY_MEDIA_TYPE = "media-type"; - private static final String KEY_IMAGES = "images"; - private static final String KEY_URL = "movie-urls"; - private static final String KEY_CONTENT_TYPE = "content-type"; - private static final String KEY_STREAM_TYPE = "stream-type"; - private static final String KEY_CUSTOM_DATA = "custom-data"; - private static final String KEY_STREAM_DURATION = "stream-duration"; - private static final String KEY_TRACK_ID = "track-id"; - private static final String KEY_TRACK_CONTENT_ID = "track-custom-id"; - private static final String KEY_TRACK_NAME = "track-name"; - private static final String KEY_TRACK_TYPE = "track-type"; - private static final String KEY_TRACK_SUBTYPE = "track-subtype"; - private static final String KEY_TRACK_LANGUAGE = "track-language"; - private static final String KEY_TRACK_CUSTOM_DATA = "track-custom-data"; - private static final String KEY_TRACKS_DATA = "track-data"; - public static final boolean IS_KITKAT_OR_ABOVE = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; - public static final boolean IS_ICS_OR_ABOVE = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; - - private Utils() { - } - - /** - * Formats time from milliseconds to hh:mm:ss string format. - */ - public static String formatMillis(int millisec) { - int seconds = (int) (millisec / 1000); - int hours = seconds / (60 * 60); - seconds %= (60 * 60); - int minutes = seconds / 60; - seconds %= 60; - - String time; - if (hours > 0) { - time = String.format("%d:%02d:%02d", hours, minutes, seconds); - } else { - time = String.format("%d:%02d", minutes, seconds); - } - return time; - } - - /** - * Shows a (long) toast. - */ - public static void showToast(Context context, int resourceId) { - Toast.makeText(context, context.getString(resourceId), Toast.LENGTH_LONG).show(); - } - - /** - * Returns the URL of an image for the {@link MediaInfo} at the given index. Index should be a - * number between 0 and {@code n-1} where {@code n} is the number of images for that given item. - */ - public static String getImageUrl(MediaInfo info, int index) { - Uri uri = getImageUri(info, index); - if (uri != null) { - return uri.toString(); - } - return null; - } - - /** - * Returns the {@code Uri} address of an image for the {@link MediaInfo} at the given - * index. Index should be a number between 0 and {@code n - 1} where {@code n} is the - * number of images for that given item. - */ - public static Uri getImageUri(MediaInfo info, int index) { - MediaMetadata mediaMetadata = info.getMetadata(); - if (mediaMetadata != null && mediaMetadata.getImages().size() > index) { - return mediaMetadata.getImages().get(index).getUrl(); - } - return null; - } - - /** - * A utility method to validate that the appropriate version of the Google Play Services is - * available on the device. If not, it will open a dialog to address the issue. The dialog - * displays a localized message about the error and upon user confirmation (by tapping on - * dialog) will direct them to the Play Store if Google Play services is out of date or - * missing, or to system settings if Google Play services is disabled on the device. - */ - public static boolean checkGooglePlayServices(final Activity activity) { - final int googlePlayServicesCheck = GooglePlayServicesUtil.isGooglePlayServicesAvailable( - activity); - switch (googlePlayServicesCheck) { - case ConnectionResult.SUCCESS: - return true; - default: - Dialog dialog = GooglePlayServicesUtil.getErrorDialog(googlePlayServicesCheck, - activity, 0); - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialogInterface) { - activity.finish(); - } - }); - dialog.show(); - } - return false; - } - - /** - * Builds and returns a {@link Bundle} which contains a select subset of data in the - * {@link MediaInfo}. Since {@link MediaInfo} is not {@link Parcelable}, one can use this - * container bundle to pass around from one activity to another. - * - * @see bundleToMediaInfo() - */ - public static Bundle mediaInfoToBundle(MediaInfo info) { - if (info == null) { - return null; - } - - MediaMetadata md = info.getMetadata(); - Bundle wrapper = new Bundle(); - wrapper.putString(MediaMetadata.KEY_TITLE, md.getString(MediaMetadata.KEY_TITLE)); - wrapper.putString(MediaMetadata.KEY_SUBTITLE, md.getString(MediaMetadata.KEY_SUBTITLE)); - wrapper.putString(MediaMetadata.KEY_ALBUM_TITLE, - md.getString(MediaMetadata.KEY_ALBUM_TITLE)); - wrapper.putString(MediaMetadata.KEY_ALBUM_ARTIST, - md.getString(MediaMetadata.KEY_ALBUM_ARTIST)); - wrapper.putString(MediaMetadata.KEY_COMPOSER, md.getString(MediaMetadata.KEY_COMPOSER)); - Calendar releaseCalendar = md.getDate(MediaMetadata.KEY_RELEASE_DATE); - if (releaseCalendar != null) { - long releaseMillis = releaseCalendar.getTimeInMillis(); - wrapper.putLong(MediaMetadata.KEY_RELEASE_DATE, releaseMillis); - } - wrapper.putInt(KEY_MEDIA_TYPE, info.getMetadata().getMediaType()); - wrapper.putString(KEY_URL, info.getContentId()); - wrapper.putString(MediaMetadata.KEY_STUDIO, md.getString(MediaMetadata.KEY_STUDIO)); - wrapper.putString(KEY_CONTENT_TYPE, info.getContentType()); - wrapper.putInt(KEY_STREAM_TYPE, info.getStreamType()); - wrapper.putLong(KEY_STREAM_DURATION, info.getStreamDuration()); - if (!md.getImages().isEmpty()) { - ArrayList urls = new ArrayList<>(); - for (WebImage img : md.getImages()) { - urls.add(img.getUrl().toString()); - } - wrapper.putStringArrayList(KEY_IMAGES, urls); - } - JSONObject customData = info.getCustomData(); - if (customData != null) { - wrapper.putString(KEY_CUSTOM_DATA, customData.toString()); - } - if (info.getMediaTracks() != null && !info.getMediaTracks().isEmpty()) { - try { - JSONArray jsonArray = new JSONArray(); - for (MediaTrack mt : info.getMediaTracks()) { - JSONObject jsonObject = new JSONObject(); - jsonObject.put(KEY_TRACK_NAME, mt.getName()); - jsonObject.put(KEY_TRACK_CONTENT_ID, mt.getContentId()); - jsonObject.put(KEY_TRACK_ID, mt.getId()); - jsonObject.put(KEY_TRACK_LANGUAGE, mt.getLanguage()); - jsonObject.put(KEY_TRACK_TYPE, mt.getType()); - if (mt.getSubtype() != MediaTrack.SUBTYPE_UNKNOWN) { - jsonObject.put(KEY_TRACK_SUBTYPE, mt.getSubtype()); - } - if (mt.getCustomData() != null) { - jsonObject.put(KEY_TRACK_CUSTOM_DATA, mt.getCustomData().toString()); - } - jsonArray.put(jsonObject); - } - wrapper.putString(KEY_TRACKS_DATA, jsonArray.toString()); - } catch (JSONException e) { - LOGE(TAG, "mediaInfoToBundle(): Failed to convert Tracks data to json", e); - } - } - - return wrapper; - } - - /** - * Builds and returns a {@link MediaInfo} that was wrapped in a {@link Bundle} by - * mediaInfoToBundle. It is assumed that the type of the {@link MediaInfo} is - * {@code MediaMetaData.MEDIA_TYPE_MOVIE} - * - * @see mediaInfoToBundle() - */ - public static MediaInfo bundleToMediaInfo(Bundle wrapper) { - if (wrapper == null) { - return null; - } - - MediaMetadata metaData = new MediaMetadata(wrapper.getInt(KEY_MEDIA_TYPE)); - - metaData.putString(MediaMetadata.KEY_SUBTITLE, - wrapper.getString(MediaMetadata.KEY_SUBTITLE)); - metaData.putString(MediaMetadata.KEY_TITLE, wrapper.getString(MediaMetadata.KEY_TITLE)); - metaData.putString(MediaMetadata.KEY_STUDIO, wrapper.getString(MediaMetadata.KEY_STUDIO)); - metaData.putString(MediaMetadata.KEY_ALBUM_ARTIST, - wrapper.getString(MediaMetadata.KEY_ALBUM_ARTIST)); - metaData.putString(MediaMetadata.KEY_ALBUM_TITLE, - wrapper.getString(MediaMetadata.KEY_ALBUM_TITLE)); - metaData.putString(MediaMetadata.KEY_COMPOSER, - wrapper.getString(MediaMetadata.KEY_COMPOSER)); - - long releaseDateMillis = wrapper.getLong(MediaMetadata.KEY_RELEASE_DATE, 0); - if (releaseDateMillis > 0) { - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(releaseDateMillis); - metaData.putDate(MediaMetadata.KEY_RELEASE_DATE, calendar); - } - ArrayList images = wrapper.getStringArrayList(KEY_IMAGES); - if (images != null && !images.isEmpty()) { - for (String url : images) { - Uri uri = Uri.parse(url); - metaData.addImage(new WebImage(uri)); - } - } - String customDataStr = wrapper.getString(KEY_CUSTOM_DATA); - JSONObject customData = null; - if (!TextUtils.isEmpty(customDataStr)) { - try { - customData = new JSONObject(customDataStr); - } catch (JSONException e) { - LOGE(TAG, "Failed to deserialize the custom data string: custom data= " - + customDataStr); - } - } - List mediaTracks = null; - if (wrapper.getString(KEY_TRACKS_DATA) != null) { - try { - JSONArray jsonArray = new JSONArray(wrapper.getString(KEY_TRACKS_DATA)); - mediaTracks = new ArrayList(); - if (jsonArray.length() > 0) { - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject jsonObj = (JSONObject) jsonArray.get(i); - MediaTrack.Builder builder = new MediaTrack.Builder( - jsonObj.getLong(KEY_TRACK_ID), jsonObj.getInt(KEY_TRACK_TYPE)); - if (jsonObj.has(KEY_TRACK_NAME)) { - builder.setName(jsonObj.getString(KEY_TRACK_NAME)); - } - if (jsonObj.has(KEY_TRACK_SUBTYPE)) { - builder.setSubtype(jsonObj.getInt(KEY_TRACK_SUBTYPE)); - } - if (jsonObj.has(KEY_TRACK_CONTENT_ID)) { - builder.setContentId(jsonObj.getString(KEY_TRACK_CONTENT_ID)); - } - if (jsonObj.has(KEY_TRACK_LANGUAGE)) { - builder.setLanguage(jsonObj.getString(KEY_TRACK_LANGUAGE)); - } - if (jsonObj.has(KEY_TRACKS_DATA)) { - builder.setCustomData( - new JSONObject(jsonObj.getString(KEY_TRACKS_DATA))); - } - mediaTracks.add(builder.build()); - } - } - } catch (JSONException e) { - LOGE(TAG, "Failed to build media tracks from the wrapper bundle", e); - } - } - MediaInfo.Builder mediaBuilder = new MediaInfo.Builder(wrapper.getString(KEY_URL)) - .setStreamType(wrapper.getInt(KEY_STREAM_TYPE)) - .setContentType(wrapper.getString(KEY_CONTENT_TYPE)) - .setMetadata(metaData) - .setCustomData(customData) - .setMediaTracks(mediaTracks); - - if (wrapper.containsKey(KEY_STREAM_DURATION) - && wrapper.getLong(KEY_STREAM_DURATION) >= 0) { - mediaBuilder.setStreamDuration(wrapper.getLong(KEY_STREAM_DURATION)); - } - - return mediaBuilder.build(); - } - - /** - * Returns the SSID of the wifi connection, or null if there is no wifi. - */ - public static String getWifiSsid(Context context) { -// WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); -// WifiInfo wifiInfo = wifiManager.getConnectionInfo(); -// if (wifiInfo != null) { -// return wifiInfo.getSSID(); -// } - - // This hack keeps Santa from depending on the ACCESS_WIFI_STATE permission - return null; - } - - /** - * Scale and center-crop a bitmap to fit the given dimensions. - */ - public static Bitmap scaleAndCenterCropBitmap(Bitmap source, int newHeight, int newWidth) { - if (source == null) { - return null; - } - int sourceWidth = source.getWidth(); - int sourceHeight = source.getHeight(); - - float xScale = (float) newWidth / sourceWidth; - float yScale = (float) newHeight / sourceHeight; - float scale = Math.max(xScale, yScale); - - float scaledWidth = scale * sourceWidth; - float scaledHeight = scale * sourceHeight; - - float left = (newWidth - scaledWidth) / 2; - float top = (newHeight - scaledHeight) / 2; - - RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight); - - Bitmap destination = Bitmap.createBitmap(newWidth, newHeight, source.getConfig()); - Canvas canvas = new Canvas(destination); - canvas.drawBitmap(source, null, targetRect, null); - - return destination; - } - - /** - * Converts DIP (or DP) to Pixels - */ - public static int convertDpToPixel(Context context, float dp) { - return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, - context.getResources().getDisplayMetrics()); - } - - /** - * Given a list of queue items, this method recreates an identical list of items except that the - * {@code itemId} of each item is erased, in effect preparing the list to be reloaded on the - * receiver. - */ - public static MediaQueueItem[] rebuildQueue(List items) { - if (items == null || items.isEmpty()) { - return null; - } - MediaQueueItem[] rebuiltQueue = new MediaQueueItem[items.size()]; - for (int i = 0; i < items.size(); i++) { - rebuiltQueue[i] = rebuildQueueItem(items.get(i)); - } - - return rebuiltQueue; - } - - /** - * Given a list of queue items, and a new item, this method recreates an identical list of items - * from the queue, except that the {@code itemId} of each item is erased, in effect preparing - * the list to be reloaded. Then, it appends the new item to teh end of the rebuilt list and - * returns the result. - */ - public static MediaQueueItem[] rebuildQueueAndAppend(List items, - MediaQueueItem currentItem) { - if (items == null || items.isEmpty()) { - return new MediaQueueItem[]{currentItem}; - } - MediaQueueItem[] rebuiltQueue = new MediaQueueItem[items.size() + 1]; - for (int i = 0; i < items.size(); i++) { - rebuiltQueue[i] = rebuildQueueItem(items.get(i)); - } - rebuiltQueue[items.size()] = currentItem; - - return rebuiltQueue; - } - - /** - * Given a queue item, it returns an identical item except that the {@code itemId} has been - * cleared. - */ - public static MediaQueueItem rebuildQueueItem(MediaQueueItem item) { - return new MediaQueueItem.Builder(item).clearItemId().build(); - } -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/widgets/IMiniController.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/widgets/IMiniController.java deleted file mode 100644 index a1c409e58..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/widgets/IMiniController.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.widgets; - -import com.google.android.gms.cast.MediaInfo; -import com.google.android.gms.cast.MediaQueueItem; -import com.google.android.gms.cast.MediaStatus; -import com.google.android.libraries.cast.companionlibrary.widgets.MiniController.OnMiniControllerChangedListener; - -import android.graphics.Bitmap; -import android.net.Uri; - -/** - * An interface to abstract {@link MiniController} so that other components can also control the - * MiniControllers. Clients should code against this interface when they want to control the - * provided {@link MiniController} or other custom implementations. - */ -public interface IMiniController { - - /** - * Sets the uri for the album art - */ - void setIcon(Uri uri); - - /** - * Sets the bitmap for the album art - */ - void setIcon(Bitmap bitmap); - - /** - * Sets the title - */ - void setTitle(String title); - - /** - * Sets the subtitle - */ - void setSubtitle(String subtitle); - - /** - * Sets the playback state, and the idleReason (this is only reliable when the state is idle). - * Values that can be passed to this method are from {@link MediaStatus} - */ - void setPlaybackStatus(int state, int idleReason); - - /** - * Sets whether this component should be visible or hidden. - */ - void setVisibility(int visibility); - - /** - * Returns the visibility state of this widget - */ - boolean isVisible(); - - /** - * Assigns a {@link OnMiniControllerChangedListener} listener to be notified of the changes in - * the mini controller - */ - void setOnMiniControllerChangedListener(OnMiniControllerChangedListener listener); - - /** - * Sets the type of stream. {@code streamType} can be {@link MediaInfo#STREAM_TYPE_LIVE} - * or {@link MediaInfo#STREAM_TYPE_BUFFERED} - */ - void setStreamType(int streamType); - - /** - * Sets the progress of stream. - */ - void setProgress(int progress, int duration); - - /** - * Sets the visibility of the progress indicator - */ - void setProgressVisibility(boolean visible); - - /** - * Sets whether the "upcoming" sub-component should be visible or not - */ - void setUpcomingVisibility(boolean visible); - - /** - * Sets the upcoming item, which can be {@code null}. - */ - void setUpcomingItem(MediaQueueItem item); - - /** - * Controls the visibility of the currently playing item. - */ - void setCurrentVisibility(boolean visible); - - -} diff --git a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/widgets/MiniController.java b/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/widgets/MiniController.java deleted file mode 100644 index 528764faa..000000000 --- a/CCL/src/main/java/com/google/android/libraries/cast/companionlibrary/widgets/MiniController.java +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.libraries.cast.companionlibrary.widgets; - -import com.google.android.gms.cast.MediaInfo; -import com.google.android.gms.cast.MediaMetadata; -import com.google.android.gms.cast.MediaQueueItem; -import com.google.android.gms.cast.MediaStatus; -import com.google.android.libraries.cast.companionlibrary.R; -import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.OnFailedListener; -import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException; -import com.google.android.libraries.cast.companionlibrary.utils.FetchBitmapTask; -import com.google.android.libraries.cast.companionlibrary.utils.Utils; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Handler; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; -import android.widget.TextView; - -/** - * A compound component that provides a superset of functionalities required for the global access - * requirement. This component provides an image for the album art, a play/pause button, and a - * progressbar to show the current position. When an auto-play queue is playing and pre-loading is - * set, then this component can show an additional view to inform the user of the upcoming item and - * to allow immediate playback of the next item or to stop the auto-play. - * - *

Clients can add this - * compound component to their layout xml and preferably set the {@code auto_setup} attribute to - * {@code true} to have the CCL manage the visibility and behavior of this component. Alternatively, - * clients can register this component with the instance of - * {@link VideoCastManager} by using the following pattern:
- * - *

- * mMiniController = (MiniController) findViewById(R.id.miniController);
- * mCastManager.addMiniController(mMiniController);
- * mMiniController.setOnMiniControllerChangedListener(mCastManager);
- * 
- * - * In this case, clients should remember to unregister the component themselves. - * Then the {@link VideoCastManager} will manage the behavior, including its state and metadata and - * interactions. Note that using the {@code auto_setup} attribute hand;les all of these - * automatically. - */ -public class MiniController extends RelativeLayout implements IMiniController { - - public static final int UNDEFINED_STATUS_CODE = -1; - private boolean mAutoSetup; - private VideoCastManager mCastManager; - private Handler mHandler; - protected ImageView mIcon; - protected TextView mTitle; - protected TextView mSubTitle; - protected ImageView mPlayPause; - protected ProgressBar mLoading; - private OnMiniControllerChangedListener mListener; - private Uri mIconUri; - private Drawable mPauseDrawable; - private Drawable mPlayDrawable; - private int mStreamType = MediaInfo.STREAM_TYPE_BUFFERED; - private Drawable mStopDrawable; - private FetchBitmapTask mFetchBitmapTask; - private ProgressBar mProgressBar; - private ImageView mUpcomingIcon; - private TextView mUpcomingTitle; - private View mUpcomingContainer; - private View mUpcomingPlay; - private View mUpcomingStop; - private Uri mUpcomingIconUri; - private FetchBitmapTask mFetchUpcomingBitmapTask; - private View mMainContainer; - private MediaQueueItem mUpcomingItem; - - public MiniController(Context context, AttributeSet attrs) { - super(context, attrs); - LayoutInflater inflater = LayoutInflater.from(context); - inflater.inflate(R.layout.mini_controller, this); - TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MiniController); - mAutoSetup = a.getBoolean(R.styleable.MiniController_auto_setup, false); - a.recycle(); - mPauseDrawable = getResources().getDrawable(R.drawable.ic_mini_controller_pause); - mPlayDrawable = getResources().getDrawable(R.drawable.ic_mini_controller_play); - mStopDrawable = getResources().getDrawable(R.drawable.ic_mini_controller_stop); - mHandler = new Handler(); - mCastManager = VideoCastManager.getInstance(); - loadViews(); - setUpCallbacks(); - } - - @Override - public void setVisibility(int visibility) { - super.setVisibility(visibility); - if (visibility == View.VISIBLE) { - mProgressBar.setProgress(0); - } - } - - /** - * Sets the listener that should be notified when a relevant event is fired from this - * component. - * Clients can register the {@link VideoCastManager} instance to be the default listener so it - * can control the remote media playback. - */ - @Override - public void setOnMiniControllerChangedListener(OnMiniControllerChangedListener listener) { - if (listener != null) { - this.mListener = listener; - } - } - - /** - * Removes the listener that was registered by - * {@link #setOnMiniControllerChangedListener(OnMiniControllerChangedListener)} - */ - public void removeOnMiniControllerChangedListener(OnMiniControllerChangedListener listener) { - if ((listener != null) && (mListener == listener)) { - mListener = null; - } - } - - @Override - public void setStreamType(int streamType) { - mStreamType = streamType; - } - - @Override - public void setProgress(final int progress, final int duration) { - // for live streams, we do not attempt to update the progress bar - if (mStreamType == MediaInfo.STREAM_TYPE_LIVE || mProgressBar == null) { - return; - } - mHandler.post(new Runnable() { - @Override - public void run() { - mProgressBar.setMax(duration); - mProgressBar.setProgress(progress); - } - }); - } - - @Override - public void setProgressVisibility(boolean visible) { - if (mProgressBar == null) { - return; - } - mProgressBar.setVisibility( - visible && (mStreamType != MediaInfo.STREAM_TYPE_LIVE) ? View.VISIBLE - : View.INVISIBLE); - } - - @Override - public void setUpcomingVisibility(boolean visible) { - mUpcomingContainer.setVisibility(visible ? View.VISIBLE : View.GONE); - setProgressVisibility(!visible); - } - - @Override - public void setUpcomingItem(MediaQueueItem item) { - mUpcomingItem = item; - if (item != null) { - MediaInfo mediaInfo = item.getMedia(); - if (mediaInfo != null) { - MediaMetadata metadata = mediaInfo.getMetadata(); - setUpcomingTitle(metadata.getString(MediaMetadata.KEY_TITLE)); - setUpcomingIcon(Utils.getImageUri(mediaInfo, 0)); - } - } else { - setUpcomingTitle(""); - setUpcomingIcon((Uri) null); - } - } - - @Override - public void setCurrentVisibility(boolean visible) { - mMainContainer.setVisibility(visible ? View.VISIBLE : View.GONE); - } - - private void setUpCallbacks() { - - mPlayPause.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - if (mListener != null) { - setLoadingVisibility(true); - try { - mListener.onPlayPauseClicked(v); - } catch (CastException e) { - mListener.onFailed(R.string.ccl_failed_perform_action, - UNDEFINED_STATUS_CODE); - } catch (TransientNetworkDisconnectionException e) { - mListener.onFailed(R.string.ccl_failed_no_connection_trans, - UNDEFINED_STATUS_CODE); - } catch (NoConnectionException e) { - mListener - .onFailed(R.string.ccl_failed_no_connection, UNDEFINED_STATUS_CODE); - } - } - } - }); - - mMainContainer.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - - if (mListener != null) { - setLoadingVisibility(false); - try { - mListener.onTargetActivityInvoked(mIcon.getContext()); - } catch (Exception e) { - mListener.onFailed(R.string.ccl_failed_perform_action, -1); - } - } - - } - }); - - mUpcomingPlay.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mListener != null) { - mListener.onUpcomingPlayClicked(v, mUpcomingItem); - } - } - }); - - mUpcomingStop.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mListener != null) { - mListener.onUpcomingStopClicked(v, mUpcomingItem); - } - } - }); - } - - public MiniController(Context context) { - super(context); - loadViews(); - } - - @Override - public final void setIcon(Bitmap bm) { - mIcon.setImageBitmap(bm); - } - - private void setUpcomingIcon(Bitmap bm) { - mUpcomingIcon.setImageBitmap(bm); - } - - @Override - public void setIcon(Uri uri) { - if (mIconUri != null && mIconUri.equals(uri)) { - return; - } - - mIconUri = uri; - if (mFetchBitmapTask != null) { - mFetchBitmapTask.cancel(true); - } - mFetchBitmapTask = new FetchBitmapTask() { - @Override - protected void onPostExecute(Bitmap bitmap) { - if (bitmap == null) { - bitmap = BitmapFactory.decodeResource(getResources(), - R.drawable.album_art_placeholder); - } - setIcon(bitmap); - if (this == mFetchBitmapTask) { - mFetchBitmapTask = null; - } - } - }; - - mFetchBitmapTask.execute(uri); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (mAutoSetup) { - mCastManager.addMiniController(this); - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - if (mFetchBitmapTask != null) { - mFetchBitmapTask.cancel(true); - mFetchBitmapTask = null; - } - if (mAutoSetup) { - mCastManager.removeMiniController(this); - } - } - - @Override - public void setTitle(String title) { - mTitle.setText(title); - } - - @Override - public void setSubtitle(String subtitle) { - mSubTitle.setText(subtitle); - } - - @Override - public void setPlaybackStatus(int state, int idleReason) { - switch (state) { - case MediaStatus.PLAYER_STATE_PLAYING: - mPlayPause.setVisibility(View.VISIBLE); - mPlayPause.setImageDrawable(getPauseStopDrawable()); - setLoadingVisibility(false); - break; - case MediaStatus.PLAYER_STATE_PAUSED: - mPlayPause.setVisibility(View.VISIBLE); - mPlayPause.setImageDrawable(mPlayDrawable); - setLoadingVisibility(false); - break; - case MediaStatus.PLAYER_STATE_IDLE: - switch (mStreamType) { - case MediaInfo.STREAM_TYPE_BUFFERED: - mPlayPause.setVisibility(View.INVISIBLE); - setLoadingVisibility(false); - break; - case MediaInfo.STREAM_TYPE_LIVE: - if (idleReason == MediaStatus.IDLE_REASON_CANCELED) { - mPlayPause.setVisibility(View.VISIBLE); - mPlayPause.setImageDrawable(mPlayDrawable); - setLoadingVisibility(false); - } else { - mPlayPause.setVisibility(View.INVISIBLE); - setLoadingVisibility(false); - } - break; - } - break; - case MediaStatus.PLAYER_STATE_BUFFERING: - mPlayPause.setVisibility(View.INVISIBLE); - setLoadingVisibility(true); - break; - default: - mPlayPause.setVisibility(View.INVISIBLE); - setLoadingVisibility(false); - break; - } - } - - @Override - public boolean isVisible() { - return isShown(); - } - - private void loadViews() { - mIcon = (ImageView) findViewById(R.id.icon_view); - mTitle = (TextView) findViewById(R.id.title_view); - mSubTitle = (TextView) findViewById(R.id.subtitle_view); - mPlayPause = (ImageView) findViewById(R.id.play_pause); - mLoading = (ProgressBar) findViewById(R.id.loading_view); - mMainContainer = findViewById(R.id.container_current); - mProgressBar = (ProgressBar) findViewById(R.id.progressBar); - mUpcomingIcon = (ImageView) findViewById(R.id.icon_view_upcoming); - mUpcomingTitle = (TextView) findViewById(R.id.title_view_upcoming); - mUpcomingContainer = findViewById(R.id.container_upcoming); - mUpcomingPlay = findViewById(R.id.play_upcoming); - mUpcomingStop = findViewById(R.id.stop_upcoming); - } - - private void setLoadingVisibility(boolean show) { - mLoading.setVisibility(show ? View.VISIBLE : View.GONE); - } - - private Drawable getPauseStopDrawable() { - switch (mStreamType) { - case MediaInfo.STREAM_TYPE_BUFFERED: - return mPauseDrawable; - case MediaInfo.STREAM_TYPE_LIVE: - return mStopDrawable; - default: - return mPauseDrawable; - } - } - - private void setUpcomingIcon(Uri uri) { - if (mUpcomingIconUri != null && mUpcomingIconUri.equals(uri)) { - return; - } - - mUpcomingIconUri = uri; - if (mFetchUpcomingBitmapTask != null) { - mFetchUpcomingBitmapTask.cancel(true); - } - mFetchUpcomingBitmapTask = new FetchBitmapTask() { - @Override - protected void onPostExecute(Bitmap bitmap) { - if (bitmap == null) { - bitmap = BitmapFactory.decodeResource(getResources(), - R.drawable.album_art_placeholder); - } - setUpcomingIcon(bitmap); - if (this == mFetchUpcomingBitmapTask) { - mFetchUpcomingBitmapTask = null; - } - } - }; - - mFetchUpcomingBitmapTask.execute(uri); - } - - private void setUpcomingTitle(String title) { - mUpcomingTitle.setText(title); - } - - /** - * The interface for a listener that will be called when user interacts with the - * {@link MiniController}, like clicking on the play/pause button, etc. - */ - public interface OnMiniControllerChangedListener extends OnFailedListener { - - /** - * Notification that user has clicked on the Play/Pause button - * - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws CastException - */ - void onPlayPauseClicked(View v) throws CastException, - TransientNetworkDisconnectionException, NoConnectionException; - - /** - * Notification that the user has clicked on the album art - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - void onTargetActivityInvoked(Context context) - throws TransientNetworkDisconnectionException, NoConnectionException; - - /** - * Called when the "play" button in the upcoming area is clicked. - */ - void onUpcomingPlayClicked(View v, MediaQueueItem upcomingItem); - - /** - * Called when the "stop" button in the upcoming area is clicked. - */ - void onUpcomingStopClicked(View view, MediaQueueItem upcomingItem); - - } -} diff --git a/CCL/src/main/res/drawable-hdpi-v11/ic_stat_action_democast.png b/CCL/src/main/res/drawable-hdpi-v11/ic_stat_action_democast.png deleted file mode 100644 index ee4533bcf..000000000 Binary files a/CCL/src/main/res/drawable-hdpi-v11/ic_stat_action_democast.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi-v11/ic_stat_action_notification.png b/CCL/src/main/res/drawable-hdpi-v11/ic_stat_action_notification.png deleted file mode 100644 index 72677ea3b..000000000 Binary files a/CCL/src/main/res/drawable-hdpi-v11/ic_stat_action_notification.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi-v11/ic_stat_content_remove.png b/CCL/src/main/res/drawable-hdpi-v11/ic_stat_content_remove.png deleted file mode 100644 index 4f2511b6f..000000000 Binary files a/CCL/src/main/res/drawable-hdpi-v11/ic_stat_content_remove.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/actionbar_bg.png b/CCL/src/main/res/drawable-hdpi/actionbar_bg.png deleted file mode 100644 index d44641816..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/actionbar_bg.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_close_sm_dark.png b/CCL/src/main/res/drawable-hdpi/ic_av_close_sm_dark.png deleted file mode 100644 index b4f9b1b52..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_close_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_pause.png b/CCL/src/main/res/drawable-hdpi/ic_av_pause.png deleted file mode 100644 index 854a97fa3..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_pause.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_pause_dark.png b/CCL/src/main/res/drawable-hdpi/ic_av_pause_dark.png deleted file mode 100644 index 90eeced0f..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_pause_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_pause_light.png b/CCL/src/main/res/drawable-hdpi/ic_av_pause_light.png deleted file mode 100644 index d0fecb25d..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_pause_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_pause_over_video.png b/CCL/src/main/res/drawable-hdpi/ic_av_pause_over_video.png deleted file mode 100644 index 7f375e8a7..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_pause_over_video.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_pause_over_video_large.png b/CCL/src/main/res/drawable-hdpi/ic_av_pause_over_video_large.png deleted file mode 100644 index 7644e7e98..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_pause_over_video_large.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_pause_sm_dark.png b/CCL/src/main/res/drawable-hdpi/ic_av_pause_sm_dark.png deleted file mode 100644 index e5c4b7c88..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_pause_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_play.png b/CCL/src/main/res/drawable-hdpi/ic_av_play.png deleted file mode 100644 index 47266e7cd..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_play.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_play_dark.png b/CCL/src/main/res/drawable-hdpi/ic_av_play_dark.png deleted file mode 100644 index 276680353..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_play_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_play_light.png b/CCL/src/main/res/drawable-hdpi/ic_av_play_light.png deleted file mode 100644 index 2e45a000d..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_play_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_play_over_video.png b/CCL/src/main/res/drawable-hdpi/ic_av_play_over_video.png deleted file mode 100644 index f8f0de439..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_play_over_video.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_play_over_video_large.png b/CCL/src/main/res/drawable-hdpi/ic_av_play_over_video_large.png deleted file mode 100644 index e0b946494..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_play_over_video_large.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_play_sm_dark.png b/CCL/src/main/res/drawable-hdpi/ic_av_play_sm_dark.png deleted file mode 100644 index f3b709b50..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_play_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_stop.png b/CCL/src/main/res/drawable-hdpi/ic_av_stop.png deleted file mode 100644 index c8deb0ab5..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_stop.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_stop_dark.png b/CCL/src/main/res/drawable-hdpi/ic_av_stop_dark.png deleted file mode 100644 index b5dc4c986..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_stop_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_stop_light.png b/CCL/src/main/res/drawable-hdpi/ic_av_stop_light.png deleted file mode 100644 index 9892ee3ff..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_stop_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_stop_sm_dark.png b/CCL/src/main/res/drawable-hdpi/ic_av_stop_sm_dark.png deleted file mode 100644 index b899558b9..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_stop_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_av_stop_sm_light.png b/CCL/src/main/res/drawable-hdpi/ic_av_stop_sm_light.png deleted file mode 100644 index 107531869..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_av_stop_sm_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_clear_black_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_clear_black_24dp.png deleted file mode 100644 index 1a9cd75a0..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_clear_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_clear_black_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_clear_black_48dp.png deleted file mode 100644 index 51b4401ca..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_clear_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_clear_white_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_clear_white_24dp.png deleted file mode 100644 index ceb1a1eeb..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_clear_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_clear_white_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_clear_white_48dp.png deleted file mode 100644 index 6b717e0dd..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_clear_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_blue.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_blue.png deleted file mode 100644 index 297bd8934..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_blue.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_googblue_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_googblue_24dp.png deleted file mode 100644 index 599574545..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_googblue_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_googblue_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_googblue_36dp.png deleted file mode 100644 index b8db0fad4..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_googblue_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_googblue_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_googblue_48dp.png deleted file mode 100644 index 85fe17d5e..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_googblue_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey.png deleted file mode 100644 index 1828c6fac..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey600_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey600_24dp.png deleted file mode 100644 index dca62ab59..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey600_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey600_36dp.png deleted file mode 100644 index 01f608450..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey600_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey600_48dp.png deleted file mode 100644 index 324149f6d..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white.png deleted file mode 100644 index 9b0c1cf9e..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white_24dp.png deleted file mode 100644 index b7acbad50..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white_36dp.png deleted file mode 100644 index 1a4e94f2f..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white_48dp.png deleted file mode 100644 index 514c4ea36..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_closed_caption_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_device_access_volume_muted.png b/CCL/src/main/res/drawable-hdpi/ic_device_access_volume_muted.png deleted file mode 100644 index d1caae052..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_device_access_volume_muted.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_device_access_volume_on.png b/CCL/src/main/res/drawable-hdpi/ic_device_access_volume_on.png deleted file mode 100644 index ace4bbee8..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_device_access_volume_on.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_drag_updown_grey_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_drag_updown_grey_24dp.png deleted file mode 100644 index 6a6f4e86e..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_drag_updown_grey_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_drag_updown_white_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_drag_updown_white_24dp.png deleted file mode 100644 index 42564eccb..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_drag_updown_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_expand_list.png b/CCL/src/main/res/drawable-hdpi/ic_expand_list.png deleted file mode 100644 index 7b8e11f03..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_expand_list.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_black_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_black_24dp.png deleted file mode 100644 index 3539b4ef1..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_black_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_black_36dp.png deleted file mode 100644 index fb4967bcb..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_black_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_black_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_black_48dp.png deleted file mode 100644 index bb707eab9..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_circle_grey_64dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_circle_grey_64dp.png deleted file mode 100644 index 37784162e..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_circle_grey_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_circle_grey_80dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_circle_grey_80dp.png deleted file mode 100644 index cd04a64a8..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_circle_grey_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_circle_white_64dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_circle_white_64dp.png deleted file mode 100644 index 1875f2093..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_circle_white_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_circle_white_80dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_circle_white_80dp.png deleted file mode 100644 index cb0097291..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_grey600_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_grey600_24dp.png deleted file mode 100644 index cfd97d5de..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_grey600_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_grey600_36dp.png deleted file mode 100644 index dde9bb25c..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_grey600_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_grey600_48dp.png deleted file mode 100644 index aeb13ebc4..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_white_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_white_24dp.png deleted file mode 100644 index 4d2ea05c4..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_pause_white_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_pause_white_48dp.png deleted file mode 100644 index 7192ad487..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_pause_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_black_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_arrow_black_24dp.png deleted file mode 100644 index e9c288c99..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_black_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_arrow_black_48dp.png deleted file mode 100644 index 5345ee3c4..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_googblue_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_arrow_googblue_36dp.png deleted file mode 100644 index f0fd209b6..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_googblue_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_grey600_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_arrow_grey600_24dp.png deleted file mode 100644 index 9e9464e2c..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_grey600_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_arrow_grey600_36dp.png deleted file mode 100644 index cd0e433d5..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_grey600_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_arrow_grey600_48dp.png deleted file mode 100644 index 06485234a..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png deleted file mode 100644 index 57c9fa546..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_white_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_arrow_white_36dp.png deleted file mode 100644 index 29adeed05..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_white_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_arrow_white_48dp.png deleted file mode 100644 index 547ef30aa..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_arrow_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_circle_grey_64dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_circle_grey_64dp.png deleted file mode 100644 index 7776fdb71..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_circle_grey_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_circle_grey_80dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_circle_grey_80dp.png deleted file mode 100644 index b4ff088eb..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_circle_grey_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_circle_white_64dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_circle_white_64dp.png deleted file mode 100644 index 7450b95a8..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_circle_white_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_play_circle_white_80dp.png b/CCL/src/main/res/drawable-hdpi/ic_play_circle_white_80dp.png deleted file mode 100644 index 035c0c046..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_play_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_playlist_black_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_playlist_black_24dp.png deleted file mode 100644 index 6f7099b6e..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_playlist_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_playlist_grey_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_playlist_grey_24dp.png deleted file mode 100644 index 3e3c4f7f4..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_playlist_grey_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_playlist_white_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_playlist_white_24dp.png deleted file mode 100644 index 798328c6d..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_playlist_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_remove_circle_white_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_remove_circle_white_24dp.png deleted file mode 100644 index 284d71309..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_remove_circle_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_repeat_one_grey600_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_repeat_one_grey600_36dp.png deleted file mode 100644 index b0f359095..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_repeat_one_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_repeat_one_white_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_repeat_one_white_36dp.png deleted file mode 100644 index 689e8ffd8..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_repeat_one_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_repeat_white_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_repeat_white_36dp.png deleted file mode 100644 index 8dbcc999a..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_repeat_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_shuffle_grey600_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_shuffle_grey600_36dp.png deleted file mode 100644 index af61e8384..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_shuffle_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_shuffle_white_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_shuffle_white_36dp.png deleted file mode 100644 index 12bf72b25..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_shuffle_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_skip_next_grey300_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_skip_next_grey300_48dp.png deleted file mode 100644 index c9abc7970..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_skip_next_grey300_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_skip_next_grey600_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_skip_next_grey600_48dp.png deleted file mode 100644 index 21bce8b88..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_skip_next_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_skip_next_white_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_skip_next_white_36dp.png deleted file mode 100644 index 9cc4bf9f3..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_skip_next_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_skip_next_white_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_skip_next_white_48dp.png deleted file mode 100644 index 3ee6d756e..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_skip_next_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_skip_previous_grey300_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_skip_previous_grey300_48dp.png deleted file mode 100644 index cf068693c..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_skip_previous_grey300_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_skip_previous_grey600_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_skip_previous_grey600_48dp.png deleted file mode 100644 index 4ae7dd589..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_skip_previous_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_skip_previous_white_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_skip_previous_white_36dp.png deleted file mode 100644 index da1c1c958..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_skip_previous_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_skip_previous_white_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_skip_previous_white_48dp.png deleted file mode 100644 index 1181ec926..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_skip_previous_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stat_action_democast.png b/CCL/src/main/res/drawable-hdpi/ic_stat_action_democast.png deleted file mode 100644 index 95ee5e511..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stat_action_democast.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stat_action_notification.png b/CCL/src/main/res/drawable-hdpi/ic_stat_action_notification.png deleted file mode 100644 index 32266acc0..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stat_action_notification.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stat_content_remove.png b/CCL/src/main/res/drawable-hdpi/ic_stat_content_remove.png deleted file mode 100644 index 29fdf59d3..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stat_content_remove.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stop_black_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_stop_black_36dp.png deleted file mode 100644 index f41a0f198..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stop_black_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stop_circle_white_80dp.png b/CCL/src/main/res/drawable-hdpi/ic_stop_circle_white_80dp.png deleted file mode 100644 index e2e04739a..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stop_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stop_grey600_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_stop_grey600_24dp.png deleted file mode 100644 index f2ac9b2e4..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stop_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stop_grey600_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_stop_grey600_36dp.png deleted file mode 100644 index ff4a2bdaa..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stop_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stop_grey600_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_stop_grey600_48dp.png deleted file mode 100644 index 42773b37d..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stop_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stop_white_18dp.png b/CCL/src/main/res/drawable-hdpi/ic_stop_white_18dp.png deleted file mode 100644 index 3bacfbcd6..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stop_white_18dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stop_white_24dp.png b/CCL/src/main/res/drawable-hdpi/ic_stop_white_24dp.png deleted file mode 100644 index dfff26cee..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stop_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stop_white_36dp.png b/CCL/src/main/res/drawable-hdpi/ic_stop_white_36dp.png deleted file mode 100644 index 266214dd9..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stop_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/ic_stop_white_48dp.png b/CCL/src/main/res/drawable-hdpi/ic_stop_white_48dp.png deleted file mode 100644 index 801d34111..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/ic_stop_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/mini_bg.png b/CCL/src/main/res/drawable-hdpi/mini_bg.png deleted file mode 100644 index d12a7b1c1..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/mini_bg.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-hdpi/mini_bg_shadow.png b/CCL/src/main/res/drawable-hdpi/mini_bg_shadow.png deleted file mode 100644 index 78b505e1a..000000000 Binary files a/CCL/src/main/res/drawable-hdpi/mini_bg_shadow.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi-v11/ic_stat_action_democast.png b/CCL/src/main/res/drawable-mdpi-v11/ic_stat_action_democast.png deleted file mode 100644 index 1d775f99a..000000000 Binary files a/CCL/src/main/res/drawable-mdpi-v11/ic_stat_action_democast.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi-v11/ic_stat_action_notification.png b/CCL/src/main/res/drawable-mdpi-v11/ic_stat_action_notification.png deleted file mode 100644 index fdf76add2..000000000 Binary files a/CCL/src/main/res/drawable-mdpi-v11/ic_stat_action_notification.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi-v11/ic_stat_content_remove.png b/CCL/src/main/res/drawable-mdpi-v11/ic_stat_content_remove.png deleted file mode 100644 index 4a94cf4cc..000000000 Binary files a/CCL/src/main/res/drawable-mdpi-v11/ic_stat_content_remove.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_close_sm_dark.png b/CCL/src/main/res/drawable-mdpi/ic_av_close_sm_dark.png deleted file mode 100644 index 99d28ac00..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_close_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_pause.png b/CCL/src/main/res/drawable-mdpi/ic_av_pause.png deleted file mode 100644 index 27399677f..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_pause.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_pause_dark.png b/CCL/src/main/res/drawable-mdpi/ic_av_pause_dark.png deleted file mode 100644 index c443134f3..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_pause_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_pause_light.png b/CCL/src/main/res/drawable-mdpi/ic_av_pause_light.png deleted file mode 100644 index 60e49d26e..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_pause_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_pause_over_video.png b/CCL/src/main/res/drawable-mdpi/ic_av_pause_over_video.png deleted file mode 100644 index 0a98ddda8..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_pause_over_video.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_pause_over_video_large.png b/CCL/src/main/res/drawable-mdpi/ic_av_pause_over_video_large.png deleted file mode 100644 index 570297ec8..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_pause_over_video_large.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_pause_sm_dark.png b/CCL/src/main/res/drawable-mdpi/ic_av_pause_sm_dark.png deleted file mode 100644 index bd0f4b04d..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_pause_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_play.png b/CCL/src/main/res/drawable-mdpi/ic_av_play.png deleted file mode 100644 index 944304ad3..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_play.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_play_dark.png b/CCL/src/main/res/drawable-mdpi/ic_av_play_dark.png deleted file mode 100644 index 4c3a9a6f7..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_play_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_play_light.png b/CCL/src/main/res/drawable-mdpi/ic_av_play_light.png deleted file mode 100644 index 4c447195b..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_play_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_play_over_video.png b/CCL/src/main/res/drawable-mdpi/ic_av_play_over_video.png deleted file mode 100644 index 2ffac8158..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_play_over_video.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_play_over_video_large.png b/CCL/src/main/res/drawable-mdpi/ic_av_play_over_video_large.png deleted file mode 100644 index d7b329684..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_play_over_video_large.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_play_sm_dark.png b/CCL/src/main/res/drawable-mdpi/ic_av_play_sm_dark.png deleted file mode 100644 index 856562b97..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_play_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_stop.png b/CCL/src/main/res/drawable-mdpi/ic_av_stop.png deleted file mode 100644 index cc3e9dfc9..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_stop.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_stop_dark.png b/CCL/src/main/res/drawable-mdpi/ic_av_stop_dark.png deleted file mode 100644 index 96aad2400..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_stop_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_stop_light.png b/CCL/src/main/res/drawable-mdpi/ic_av_stop_light.png deleted file mode 100644 index 2e10b4497..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_stop_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_stop_sm_dark.png b/CCL/src/main/res/drawable-mdpi/ic_av_stop_sm_dark.png deleted file mode 100644 index 96c6458cd..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_stop_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_av_stop_sm_light.png b/CCL/src/main/res/drawable-mdpi/ic_av_stop_sm_light.png deleted file mode 100644 index 4a8456866..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_av_stop_sm_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_device_access_volume_muted.png b/CCL/src/main/res/drawable-mdpi/ic_device_access_volume_muted.png deleted file mode 100644 index f37e45370..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_device_access_volume_muted.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_device_access_volume_on.png b/CCL/src/main/res/drawable-mdpi/ic_device_access_volume_on.png deleted file mode 100644 index 0a20d8a6e..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_device_access_volume_on.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_pause_black_36dp.png b/CCL/src/main/res/drawable-mdpi/ic_pause_black_36dp.png deleted file mode 100644 index 4dffa8e53..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_pause_black_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_playlist_black_24dp.png b/CCL/src/main/res/drawable-mdpi/ic_playlist_black_24dp.png deleted file mode 100644 index bde62ae01..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_playlist_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_playlist_grey_24dp.png b/CCL/src/main/res/drawable-mdpi/ic_playlist_grey_24dp.png deleted file mode 100644 index 1b2f1d04f..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_playlist_grey_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_playlist_white_24dp.png b/CCL/src/main/res/drawable-mdpi/ic_playlist_white_24dp.png deleted file mode 100644 index 8cb381810..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_playlist_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_stat_action_democast.png b/CCL/src/main/res/drawable-mdpi/ic_stat_action_democast.png deleted file mode 100644 index 09843dc59..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_stat_action_democast.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_stat_action_notification.png b/CCL/src/main/res/drawable-mdpi/ic_stat_action_notification.png deleted file mode 100644 index 3aca0f3fd..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_stat_action_notification.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/ic_stat_content_remove.png b/CCL/src/main/res/drawable-mdpi/ic_stat_content_remove.png deleted file mode 100644 index 5177ed6ac..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/ic_stat_content_remove.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/mini_bg.png b/CCL/src/main/res/drawable-mdpi/mini_bg.png deleted file mode 100644 index c3e500481..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/mini_bg.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-mdpi/mini_bg_shadow.png b/CCL/src/main/res/drawable-mdpi/mini_bg_shadow.png deleted file mode 100644 index 47963bab6..000000000 Binary files a/CCL/src/main/res/drawable-mdpi/mini_bg_shadow.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-nodpi/album_art_placeholder.png b/CCL/src/main/res/drawable-nodpi/album_art_placeholder.png deleted file mode 100644 index 955c7b3de..000000000 Binary files a/CCL/src/main/res/drawable-nodpi/album_art_placeholder.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-nodpi/album_art_placeholder_large.png b/CCL/src/main/res/drawable-nodpi/album_art_placeholder_large.png deleted file mode 100644 index c1be2bb8f..000000000 Binary files a/CCL/src/main/res/drawable-nodpi/album_art_placeholder_large.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-nodpi/mini_controller_img_placeholder.png b/CCL/src/main/res/drawable-nodpi/mini_controller_img_placeholder.png deleted file mode 100644 index 1ea1f1ef6..000000000 Binary files a/CCL/src/main/res/drawable-nodpi/mini_controller_img_placeholder.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-sw600dp/ic_mini_controller_upcoming_play.xml b/CCL/src/main/res/drawable-sw600dp/ic_mini_controller_upcoming_play.xml deleted file mode 100644 index bacd9ba8c..000000000 --- a/CCL/src/main/res/drawable-sw600dp/ic_mini_controller_upcoming_play.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable-sw600dp/ic_mini_controller_upcoming_stop.xml b/CCL/src/main/res/drawable-sw600dp/ic_mini_controller_upcoming_stop.xml deleted file mode 100644 index 161148136..000000000 --- a/CCL/src/main/res/drawable-sw600dp/ic_mini_controller_upcoming_stop.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable-xhdpi-v11/ic_stat_action_democast.png b/CCL/src/main/res/drawable-xhdpi-v11/ic_stat_action_democast.png deleted file mode 100644 index ff1b1cb5a..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi-v11/ic_stat_action_democast.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi-v11/ic_stat_action_notification.png b/CCL/src/main/res/drawable-xhdpi-v11/ic_stat_action_notification.png deleted file mode 100644 index c654d6b44..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi-v11/ic_stat_action_notification.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi-v11/ic_stat_content_remove.png b/CCL/src/main/res/drawable-xhdpi-v11/ic_stat_content_remove.png deleted file mode 100644 index 318b7154a..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi-v11/ic_stat_content_remove.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/default_video.png b/CCL/src/main/res/drawable-xhdpi/default_video.png deleted file mode 100644 index 20343b715..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/default_video.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_close_sm_dark.png b/CCL/src/main/res/drawable-xhdpi/ic_av_close_sm_dark.png deleted file mode 100644 index b42224fad..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_close_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_pause.png b/CCL/src/main/res/drawable-xhdpi/ic_av_pause.png deleted file mode 100644 index d66d00a6e..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_pause.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_pause_dark.png b/CCL/src/main/res/drawable-xhdpi/ic_av_pause_dark.png deleted file mode 100644 index 2a2880d81..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_pause_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_pause_light.png b/CCL/src/main/res/drawable-xhdpi/ic_av_pause_light.png deleted file mode 100644 index 9e9c0e78c..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_pause_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_pause_over_video.png b/CCL/src/main/res/drawable-xhdpi/ic_av_pause_over_video.png deleted file mode 100644 index 2947c6c9e..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_pause_over_video.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_pause_over_video_large.png b/CCL/src/main/res/drawable-xhdpi/ic_av_pause_over_video_large.png deleted file mode 100644 index dfff5a82c..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_pause_over_video_large.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_pause_sm_dark.png b/CCL/src/main/res/drawable-xhdpi/ic_av_pause_sm_dark.png deleted file mode 100644 index 84b27911a..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_pause_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_play.png b/CCL/src/main/res/drawable-xhdpi/ic_av_play.png deleted file mode 100644 index 17321c4f2..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_play.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_play_dark.png b/CCL/src/main/res/drawable-xhdpi/ic_av_play_dark.png deleted file mode 100644 index a6bcb4b40..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_play_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_play_light.png b/CCL/src/main/res/drawable-xhdpi/ic_av_play_light.png deleted file mode 100644 index 0a0c82f76..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_play_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_play_over_video.png b/CCL/src/main/res/drawable-xhdpi/ic_av_play_over_video.png deleted file mode 100644 index e35141694..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_play_over_video.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_play_over_video_large.png b/CCL/src/main/res/drawable-xhdpi/ic_av_play_over_video_large.png deleted file mode 100644 index a36b6e812..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_play_over_video_large.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_play_sm_dark.png b/CCL/src/main/res/drawable-xhdpi/ic_av_play_sm_dark.png deleted file mode 100644 index c8d1472c0..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_play_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_stop.png b/CCL/src/main/res/drawable-xhdpi/ic_av_stop.png deleted file mode 100644 index e48c4e52f..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_stop.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_stop_dark.png b/CCL/src/main/res/drawable-xhdpi/ic_av_stop_dark.png deleted file mode 100644 index ef3e3212a..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_stop_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_stop_light.png b/CCL/src/main/res/drawable-xhdpi/ic_av_stop_light.png deleted file mode 100644 index 7c1abffd5..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_stop_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_stop_sm_dark.png b/CCL/src/main/res/drawable-xhdpi/ic_av_stop_sm_dark.png deleted file mode 100644 index d7ea0481e..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_stop_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_av_stop_sm_light.png b/CCL/src/main/res/drawable-xhdpi/ic_av_stop_sm_light.png deleted file mode 100644 index 673dd6525..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_av_stop_sm_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_clear_black_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_clear_black_24dp.png deleted file mode 100644 index 6bc437298..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_clear_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_clear_black_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_clear_black_48dp.png deleted file mode 100644 index df42feecb..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_clear_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_clear_white_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_clear_white_24dp.png deleted file mode 100644 index b7c7ffd0e..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_clear_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_clear_white_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_clear_white_48dp.png deleted file mode 100644 index 396419219..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_clear_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_blue.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_blue.png deleted file mode 100644 index 2c69a4b3c..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_blue.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_googblue_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_googblue_24dp.png deleted file mode 100644 index 3d28118f5..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_googblue_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_googblue_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_googblue_36dp.png deleted file mode 100644 index 85fe17d5e..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_googblue_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_googblue_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_googblue_48dp.png deleted file mode 100644 index ed48fb159..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_googblue_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey.png deleted file mode 100644 index ea0c36392..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey600_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey600_24dp.png deleted file mode 100644 index ee5f62d69..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey600_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey600_36dp.png deleted file mode 100644 index 324149f6d..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey600_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey600_48dp.png deleted file mode 100644 index 5108c46c3..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white.png deleted file mode 100644 index f3743f285..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white_24dp.png deleted file mode 100644 index 364d6ee0d..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white_36dp.png deleted file mode 100644 index 514c4ea36..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white_48dp.png deleted file mode 100644 index 12d280c12..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_closed_caption_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_device_access_volume_muted.png b/CCL/src/main/res/drawable-xhdpi/ic_device_access_volume_muted.png deleted file mode 100644 index 027a4cb0c..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_device_access_volume_muted.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_device_access_volume_on.png b/CCL/src/main/res/drawable-xhdpi/ic_device_access_volume_on.png deleted file mode 100644 index 0f95ee74d..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_device_access_volume_on.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_drag_updown_grey_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_drag_updown_grey_24dp.png deleted file mode 100644 index 12a30f296..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_drag_updown_grey_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_drag_updown_white_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_drag_updown_white_24dp.png deleted file mode 100644 index 51211e500..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_drag_updown_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_expand_list.png b/CCL/src/main/res/drawable-xhdpi/ic_expand_list.png deleted file mode 100644 index 2ae6240de..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_expand_list.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_black_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_black_24dp.png deleted file mode 100644 index 74068eae0..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_black_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_black_36dp.png deleted file mode 100644 index ec6617a79..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_black_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_black_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_black_48dp.png deleted file mode 100644 index 792104ff3..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_grey_64dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_grey_64dp.png deleted file mode 100644 index f6d0ecbf1..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_grey_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_grey_80dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_grey_80dp.png deleted file mode 100644 index 28c31cb3b..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_grey_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_white_64dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_white_64dp.png deleted file mode 100644 index 99323e404..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_white_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_white_80dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_white_80dp.png deleted file mode 100644 index 5503d4b3f..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_grey600_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_grey600_24dp.png deleted file mode 100644 index 6708b4161..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_grey600_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_grey600_36dp.png deleted file mode 100644 index aeb13ebc4..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_grey600_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_grey600_48dp.png deleted file mode 100644 index 239b5a869..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png deleted file mode 100644 index f49aed757..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_pause_white_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_pause_white_48dp.png deleted file mode 100644 index 660ac6585..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_pause_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_black_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_black_24dp.png deleted file mode 100644 index f208795fc..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_black_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_black_48dp.png deleted file mode 100644 index d12d49562..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_googblue_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_googblue_36dp.png deleted file mode 100644 index 462620bed..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_googblue_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_24dp.png deleted file mode 100644 index 8f6a72598..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_36dp.png deleted file mode 100644 index 06485234a..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_48dp.png deleted file mode 100644 index 4be0ef363..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png deleted file mode 100644 index a3c80e73d..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_white_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_white_36dp.png deleted file mode 100644 index 547ef30aa..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_white_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_white_48dp.png deleted file mode 100644 index be5c062b5..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_arrow_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_circle_grey_64dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_circle_grey_64dp.png deleted file mode 100644 index b16f0a0df..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_circle_grey_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_circle_grey_80dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_circle_grey_80dp.png deleted file mode 100644 index 237c56bad..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_circle_grey_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_circle_white_64dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_circle_white_64dp.png deleted file mode 100644 index b870d64bc..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_circle_white_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_play_circle_white_80dp.png b/CCL/src/main/res/drawable-xhdpi/ic_play_circle_white_80dp.png deleted file mode 100644 index d48061e68..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_play_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_playlist_black_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_playlist_black_24dp.png deleted file mode 100644 index 22405eb02..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_playlist_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_playlist_grey_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_playlist_grey_24dp.png deleted file mode 100644 index 73c9c69aa..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_playlist_grey_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_playlist_white_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_playlist_white_24dp.png deleted file mode 100644 index 45776a8bc..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_playlist_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_remove_circle_white_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_remove_circle_white_24dp.png deleted file mode 100644 index 908b9ec4e..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_remove_circle_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_repeat_grey600_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_repeat_grey600_36dp.png deleted file mode 100644 index 3b097663f..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_repeat_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_repeat_one_grey600_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_repeat_one_grey600_36dp.png deleted file mode 100644 index b1d59fac4..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_repeat_one_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_repeat_one_white_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_repeat_one_white_36dp.png deleted file mode 100644 index 60dc326cc..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_repeat_one_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_repeat_white_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_repeat_white_36dp.png deleted file mode 100644 index 418d3e9e0..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_repeat_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_shuffle_grey600_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_shuffle_grey600_36dp.png deleted file mode 100644 index f710be951..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_shuffle_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_shuffle_white_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_shuffle_white_36dp.png deleted file mode 100644 index dc8e5341b..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_shuffle_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_skip_next_grey300_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_skip_next_grey300_48dp.png deleted file mode 100644 index 2b142941e..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_skip_next_grey300_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_skip_next_grey600_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_skip_next_grey600_48dp.png deleted file mode 100644 index 65d83efdd..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_skip_next_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_skip_next_white_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_skip_next_white_36dp.png deleted file mode 100644 index 3ee6d756e..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_skip_next_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_skip_next_white_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_skip_next_white_48dp.png deleted file mode 100644 index 19c4929cc..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_skip_next_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_grey300_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_grey300_48dp.png deleted file mode 100644 index df38227b5..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_grey300_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_grey600_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_grey600_48dp.png deleted file mode 100644 index 480328269..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_white_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_white_36dp.png deleted file mode 100644 index 1181ec926..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_white_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_white_48dp.png deleted file mode 100644 index f9186c0b6..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_skip_previous_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stat_action_democast.png b/CCL/src/main/res/drawable-xhdpi/ic_stat_action_democast.png deleted file mode 100644 index 5fe191255..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stat_action_democast.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stat_action_notification.png b/CCL/src/main/res/drawable-xhdpi/ic_stat_action_notification.png deleted file mode 100644 index bb0ae81df..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stat_action_notification.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stat_content_remove.png b/CCL/src/main/res/drawable-xhdpi/ic_stat_content_remove.png deleted file mode 100644 index 40961e4cf..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stat_content_remove.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stop_black_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_stop_black_36dp.png deleted file mode 100644 index 9d6b65da7..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stop_black_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stop_circle_white_80dp.png b/CCL/src/main/res/drawable-xhdpi/ic_stop_circle_white_80dp.png deleted file mode 100644 index ab7dd3cae..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stop_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stop_grey600_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_stop_grey600_24dp.png deleted file mode 100644 index 8d71c4403..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stop_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stop_grey600_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_stop_grey600_36dp.png deleted file mode 100644 index 42773b37d..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stop_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stop_grey600_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_stop_grey600_48dp.png deleted file mode 100644 index 772600924..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stop_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stop_white_18dp.png b/CCL/src/main/res/drawable-xhdpi/ic_stop_white_18dp.png deleted file mode 100644 index dfff26cee..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stop_white_18dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stop_white_24dp.png b/CCL/src/main/res/drawable-xhdpi/ic_stop_white_24dp.png deleted file mode 100644 index 3ad2c9c4e..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stop_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stop_white_36dp.png b/CCL/src/main/res/drawable-xhdpi/ic_stop_white_36dp.png deleted file mode 100644 index 801d34111..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stop_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/ic_stop_white_48dp.png b/CCL/src/main/res/drawable-xhdpi/ic_stop_white_48dp.png deleted file mode 100644 index 523933667..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/ic_stop_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/mini_bg.png b/CCL/src/main/res/drawable-xhdpi/mini_bg.png deleted file mode 100644 index 40b751f90..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/mini_bg.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xhdpi/mini_bg_shadow.png b/CCL/src/main/res/drawable-xhdpi/mini_bg_shadow.png deleted file mode 100644 index cc4f61df6..000000000 Binary files a/CCL/src/main/res/drawable-xhdpi/mini_bg_shadow.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi-v11/ic_stat_action_democast.png b/CCL/src/main/res/drawable-xxhdpi-v11/ic_stat_action_democast.png deleted file mode 100644 index a6b25c885..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi-v11/ic_stat_action_democast.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi-v11/ic_stat_action_notification.png b/CCL/src/main/res/drawable-xxhdpi-v11/ic_stat_action_notification.png deleted file mode 100644 index 4a434826b..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi-v11/ic_stat_action_notification.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi-v11/ic_stat_content_remove.png b/CCL/src/main/res/drawable-xxhdpi-v11/ic_stat_content_remove.png deleted file mode 100644 index e60e87db3..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi-v11/ic_stat_content_remove.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_close_sm_dark.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_close_sm_dark.png deleted file mode 100644 index e58e25f9f..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_close_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_pause.png deleted file mode 100644 index f7eaf517b..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_dark.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_dark.png deleted file mode 100644 index f782aa887..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_light.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_light.png deleted file mode 100644 index a4af4ee5c..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_over_video.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_over_video.png deleted file mode 100644 index 58ef402f8..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_over_video.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_over_video_large.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_over_video_large.png deleted file mode 100644 index cc787ce83..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_over_video_large.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_sm_dark.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_sm_dark.png deleted file mode 100644 index bd03035c1..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_pause_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_play.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_play.png deleted file mode 100644 index 6c2b02189..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_play.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_play_dark.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_play_dark.png deleted file mode 100644 index 45f86da78..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_play_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_play_light.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_play_light.png deleted file mode 100644 index 7f9d25293..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_play_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_play_over_video.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_play_over_video.png deleted file mode 100644 index eebe36262..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_play_over_video.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_play_over_video_large.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_play_over_video_large.png deleted file mode 100644 index 65ca82d66..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_play_over_video_large.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_play_sm_dark.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_play_sm_dark.png deleted file mode 100644 index 97c2614d1..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_play_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_stop.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_stop.png deleted file mode 100644 index ea57edf8d..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_stop.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_dark.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_dark.png deleted file mode 100644 index a637486ec..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_light.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_light.png deleted file mode 100644 index 6edcaa548..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_sm_dark.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_sm_dark.png deleted file mode 100644 index 0a0dc3350..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_sm_dark.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_sm_light.png b/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_sm_light.png deleted file mode 100644 index 3e54758b4..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_av_stop_sm_light.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_clear_black_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_clear_black_24dp.png deleted file mode 100644 index 51b4401ca..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_clear_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_clear_black_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_clear_black_48dp.png deleted file mode 100644 index e2ee25f60..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_clear_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_clear_white_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_clear_white_24dp.png deleted file mode 100644 index 6b717e0dd..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_clear_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_clear_white_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_clear_white_48dp.png deleted file mode 100644 index 4927bc242..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_clear_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_blue.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_blue.png deleted file mode 100644 index 2a770be52..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_blue.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_googblue_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_googblue_24dp.png deleted file mode 100644 index 85fe17d5e..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_googblue_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_googblue_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_googblue_36dp.png deleted file mode 100644 index 4345d025c..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_googblue_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_googblue_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_googblue_48dp.png deleted file mode 100644 index 2bccf7f3a..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_googblue_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey.png deleted file mode 100644 index 02e68b290..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey600_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey600_24dp.png deleted file mode 100644 index 324149f6d..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey600_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey600_36dp.png deleted file mode 100644 index 774e205aa..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey600_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey600_48dp.png deleted file mode 100644 index faa153c9a..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white.png deleted file mode 100644 index 691300cfb..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white_24dp.png deleted file mode 100644 index 514c4ea36..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white_36dp.png deleted file mode 100644 index 71918a5ac..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white_48dp.png deleted file mode 100644 index c78177570..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_closed_caption_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_device_access_volume_muted.png b/CCL/src/main/res/drawable-xxhdpi/ic_device_access_volume_muted.png deleted file mode 100644 index 74518d941..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_device_access_volume_muted.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_device_access_volume_on.png b/CCL/src/main/res/drawable-xxhdpi/ic_device_access_volume_on.png deleted file mode 100644 index 8704f2b61..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_device_access_volume_on.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_drag_updown_grey_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_drag_updown_grey_24dp.png deleted file mode 100644 index 5213d3646..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_drag_updown_grey_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_drag_updown_white_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_drag_updown_white_24dp.png deleted file mode 100644 index 637f829d7..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_drag_updown_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_black_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_black_24dp.png deleted file mode 100644 index bb707eab9..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_black_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_black_36dp.png deleted file mode 100644 index a691659a7..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_black_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_black_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_black_48dp.png deleted file mode 100644 index dc63538f3..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_grey_64dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_grey_64dp.png deleted file mode 100644 index 28c31cb3b..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_grey_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_grey_80dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_grey_80dp.png deleted file mode 100644 index eb67581f2..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_grey_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_white_64dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_white_64dp.png deleted file mode 100644 index 5503d4b3f..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_white_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_white_80dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_white_80dp.png deleted file mode 100644 index dd0342bd1..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_grey600_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_grey600_24dp.png deleted file mode 100644 index aeb13ebc4..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_grey600_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_grey600_36dp.png deleted file mode 100644 index 0f4b4ed73..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_grey600_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_grey600_48dp.png deleted file mode 100644 index 78456c7cd..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png deleted file mode 100644 index 7192ad487..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_pause_white_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_pause_white_48dp.png deleted file mode 100644 index 3ea7e03e5..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_pause_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_black_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_black_24dp.png deleted file mode 100644 index 5345ee3c4..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_black_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_black_48dp.png deleted file mode 100644 index 1c57756b0..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_googblue_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_googblue_36dp.png deleted file mode 100644 index b4ee49971..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_googblue_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_24dp.png deleted file mode 100644 index 06485234a..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_36dp.png deleted file mode 100644 index aa60f481b..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_48dp.png deleted file mode 100644 index 27a0dc0a8..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png deleted file mode 100644 index 547ef30aa..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_white_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_white_36dp.png deleted file mode 100644 index 23bb1ba9f..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_white_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_white_48dp.png deleted file mode 100644 index 2745c3ab9..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_arrow_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_grey_64dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_grey_64dp.png deleted file mode 100644 index 237c56bad..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_grey_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_grey_80dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_grey_80dp.png deleted file mode 100644 index a744b17ae..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_grey_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_white_64dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_white_64dp.png deleted file mode 100644 index d48061e68..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_white_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_white_80dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_white_80dp.png deleted file mode 100644 index 368f577e3..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_play_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_playlist_black_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_playlist_black_24dp.png deleted file mode 100644 index 29b8fcfac..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_playlist_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_playlist_grey_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_playlist_grey_24dp.png deleted file mode 100644 index 1a6550f6d..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_playlist_grey_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_playlist_white_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_playlist_white_24dp.png deleted file mode 100644 index 424196689..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_playlist_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_remove_circle_white_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_remove_circle_white_24dp.png deleted file mode 100644 index 5079102d2..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_remove_circle_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_repeat_grey600_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_repeat_grey600_36dp.png deleted file mode 100644 index 8b9fa778b..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_repeat_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_repeat_one_white_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_repeat_one_white_36dp.png deleted file mode 100644 index 0303bc104..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_repeat_one_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_repeat_white_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_repeat_white_36dp.png deleted file mode 100644 index 68a633ca8..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_repeat_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_shuffle_grey600_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_shuffle_grey600_36dp.png deleted file mode 100644 index de53ec550..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_shuffle_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_shuffle_white_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_shuffle_white_36dp.png deleted file mode 100644 index fad125952..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_shuffle_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_grey300_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_grey300_48dp.png deleted file mode 100644 index 283d81821..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_grey300_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_grey600_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_grey600_48dp.png deleted file mode 100644 index 346533ff1..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_white_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_white_36dp.png deleted file mode 100644 index 4652215cc..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_white_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_white_48dp.png deleted file mode 100644 index 292811616..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_skip_next_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_grey300_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_grey300_48dp.png deleted file mode 100644 index 6209a7cd0..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_grey300_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_grey600_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_grey600_48dp.png deleted file mode 100644 index 8509af916..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_white_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_white_36dp.png deleted file mode 100644 index d66306419..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_white_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_white_48dp.png deleted file mode 100644 index 73e30477c..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_skip_previous_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stat_action_democast.png b/CCL/src/main/res/drawable-xxhdpi/ic_stat_action_democast.png deleted file mode 100644 index 4917f1ca5..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stat_action_democast.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stat_action_notification.png b/CCL/src/main/res/drawable-xxhdpi/ic_stat_action_notification.png deleted file mode 100644 index 9265e14d0..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stat_action_notification.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stat_content_remove.png b/CCL/src/main/res/drawable-xxhdpi/ic_stat_content_remove.png deleted file mode 100644 index 59c4b14a2..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stat_content_remove.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stop_black_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_stop_black_36dp.png deleted file mode 100644 index 75f47c1bf..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stop_black_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stop_circle_white_80dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_stop_circle_white_80dp.png deleted file mode 100644 index d2a6d4f7d..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stop_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stop_grey600_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_stop_grey600_24dp.png deleted file mode 100644 index 42773b37d..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stop_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stop_grey600_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_stop_grey600_36dp.png deleted file mode 100644 index 78ab5ff97..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stop_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stop_grey600_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_stop_grey600_48dp.png deleted file mode 100644 index 5ed9f7ec0..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stop_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_18dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_18dp.png deleted file mode 100644 index 266214dd9..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_18dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_24dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_24dp.png deleted file mode 100644 index 801d34111..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_36dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_36dp.png deleted file mode 100644 index adef631a0..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_48dp.png b/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_48dp.png deleted file mode 100644 index 035ca181c..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/ic_stop_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/mini_bg.png b/CCL/src/main/res/drawable-xxhdpi/mini_bg.png deleted file mode 100644 index b3bfebd11..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/mini_bg.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxhdpi/mini_bg_shadow.png b/CCL/src/main/res/drawable-xxhdpi/mini_bg_shadow.png deleted file mode 100644 index 42c53aef7..000000000 Binary files a/CCL/src/main/res/drawable-xxhdpi/mini_bg_shadow.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_googblue_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_googblue_24dp.png deleted file mode 100644 index ed48fb159..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_googblue_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_googblue_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_googblue_36dp.png deleted file mode 100644 index 2bccf7f3a..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_googblue_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_googblue_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_googblue_48dp.png deleted file mode 100644 index ef8ecfa2c..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_googblue_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_grey600_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_grey600_24dp.png deleted file mode 100644 index 5108c46c3..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_grey600_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_grey600_36dp.png deleted file mode 100644 index faa153c9a..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_grey600_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_grey600_48dp.png deleted file mode 100644 index f9b474193..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_white_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_white_24dp.png deleted file mode 100644 index 12d280c12..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_white_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_white_36dp.png deleted file mode 100644 index c78177570..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_white_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_white_48dp.png deleted file mode 100644 index e771a1991..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_closed_caption_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_drag_updown_grey_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_drag_updown_grey_24dp.png deleted file mode 100644 index 7d9a7e5c3..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_drag_updown_grey_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_drag_updown_white_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_drag_updown_white_24dp.png deleted file mode 100644 index 05cfeb2ff..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_drag_updown_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_black_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_black_24dp.png deleted file mode 100644 index 792104ff3..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_black_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_black_36dp.png deleted file mode 100644 index b492a6988..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_black_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_black_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_black_48dp.png deleted file mode 100644 index 66178aad1..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_grey_64dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_grey_64dp.png deleted file mode 100644 index 48ee94f83..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_grey_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_grey_80dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_grey_80dp.png deleted file mode 100644 index f26760e47..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_grey_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_white_64dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_white_64dp.png deleted file mode 100644 index d71bd4242..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_white_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_white_80dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_white_80dp.png deleted file mode 100644 index 60ab51cbf..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_grey600_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_grey600_24dp.png deleted file mode 100644 index 239b5a869..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_grey600_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_grey600_36dp.png deleted file mode 100644 index 78456c7cd..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_grey600_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_grey600_48dp.png deleted file mode 100644 index 9d5106865..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_white_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_white_24dp.png deleted file mode 100644 index 660ac6585..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_white_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_pause_white_48dp.png deleted file mode 100644 index 76482b1fd..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_pause_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_24dp.png deleted file mode 100644 index d12d49562..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_36dp.png deleted file mode 100644 index 1c57756b0..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_48dp.png deleted file mode 100644 index 904bbdbb0..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_googblue_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_googblue_36dp.png deleted file mode 100644 index 1d514a7f8..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_googblue_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_grey600_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_grey600_24dp.png deleted file mode 100644 index 4be0ef363..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_grey600_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_grey600_36dp.png deleted file mode 100644 index 27a0dc0a8..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_grey600_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_grey600_48dp.png deleted file mode 100644 index f17508827..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png deleted file mode 100644 index be5c062b5..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_36dp.png deleted file mode 100644 index 2745c3ab9..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_48dp.png deleted file mode 100644 index 8dbc4ea7c..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_grey_64dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_grey_64dp.png deleted file mode 100644 index fc3a77b8b..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_grey_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_grey_80dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_grey_80dp.png deleted file mode 100644 index 864b6f61d..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_grey_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_white_64dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_white_64dp.png deleted file mode 100644 index 4f612f966..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_white_64dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_white_80dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_white_80dp.png deleted file mode 100644 index 6e0070e37..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_play_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_playlist_black_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_playlist_black_24dp.png deleted file mode 100644 index 93c75058f..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_playlist_black_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_playlist_grey_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_playlist_grey_24dp.png deleted file mode 100644 index 84e3750a9..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_playlist_grey_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_playlist_white_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_playlist_white_24dp.png deleted file mode 100644 index 59e93c814..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_playlist_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_remove_circle_white_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_remove_circle_white_24dp.png deleted file mode 100644 index 0108c89e6..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_remove_circle_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_repeat_one_grey600_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_repeat_one_grey600_36dp.png deleted file mode 100644 index 20993de91..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_repeat_one_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_repeat_one_white_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_repeat_one_white_36dp.png deleted file mode 100644 index 596b55266..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_repeat_one_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_repeat_white_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_repeat_white_36dp.png deleted file mode 100644 index bf7607966..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_repeat_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_shuffle_grey600_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_shuffle_grey600_36dp.png deleted file mode 100644 index 423984530..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_shuffle_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_shuffle_white_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_shuffle_white_36dp.png deleted file mode 100644 index 540efc14f..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_shuffle_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_grey300_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_grey300_48dp.png deleted file mode 100644 index 910da2b32..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_grey300_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_grey600_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_grey600_48dp.png deleted file mode 100644 index 08b2167d1..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_white_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_white_36dp.png deleted file mode 100644 index 292811616..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_white_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_white_48dp.png deleted file mode 100644 index 5524dd776..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_next_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_grey300_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_grey300_48dp.png deleted file mode 100644 index 3f0cd2838..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_grey300_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_grey600_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_grey600_48dp.png deleted file mode 100644 index 7c2e012ab..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_white_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_white_36dp.png deleted file mode 100644 index 73e30477c..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_white_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_white_48dp.png deleted file mode 100644 index 9ecac1657..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_skip_previous_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_black_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_stop_black_36dp.png deleted file mode 100644 index eac183db7..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_black_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_circle_white_80dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_stop_circle_white_80dp.png deleted file mode 100644 index fb784ac2e..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_circle_white_80dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_grey600_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_stop_grey600_24dp.png deleted file mode 100644 index 772600924..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_grey600_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_grey600_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_stop_grey600_36dp.png deleted file mode 100644 index 5ed9f7ec0..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_grey600_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_grey600_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_stop_grey600_48dp.png deleted file mode 100644 index 337f92980..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_grey600_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_18dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_18dp.png deleted file mode 100644 index 801d34111..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_18dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_24dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_24dp.png deleted file mode 100644 index 523933667..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_24dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_36dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_36dp.png deleted file mode 100644 index 035ca181c..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_36dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_48dp.png b/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_48dp.png deleted file mode 100644 index 7221e0313..000000000 Binary files a/CCL/src/main/res/drawable-xxxhdpi/ic_stop_white_48dp.png and /dev/null differ diff --git a/CCL/src/main/res/drawable/actionbar_bg_gradient_light.xml b/CCL/src/main/res/drawable/actionbar_bg_gradient_light.xml deleted file mode 100644 index a83da822e..000000000 --- a/CCL/src/main/res/drawable/actionbar_bg_gradient_light.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - diff --git a/CCL/src/main/res/drawable/cast_player_bg_gradient_light.xml b/CCL/src/main/res/drawable/cast_player_bg_gradient_light.xml deleted file mode 100644 index 054cecf7c..000000000 --- a/CCL/src/main/res/drawable/cast_player_bg_gradient_light.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/cc.xml b/CCL/src/main/res/drawable/cc.xml deleted file mode 100644 index de5c9d7a4..000000000 --- a/CCL/src/main/res/drawable/cc.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_media_route_controller_pause.xml b/CCL/src/main/res/drawable/ic_media_route_controller_pause.xml deleted file mode 100644 index 9bed499a7..000000000 --- a/CCL/src/main/res/drawable/ic_media_route_controller_pause.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_media_route_controller_play.xml b/CCL/src/main/res/drawable/ic_media_route_controller_play.xml deleted file mode 100644 index 84b1a2ffa..000000000 --- a/CCL/src/main/res/drawable/ic_media_route_controller_play.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_media_route_controller_stop.xml b/CCL/src/main/res/drawable/ic_media_route_controller_stop.xml deleted file mode 100644 index fa172ec87..000000000 --- a/CCL/src/main/res/drawable/ic_media_route_controller_stop.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_mini_controller_pause.xml b/CCL/src/main/res/drawable/ic_mini_controller_pause.xml deleted file mode 100644 index 8cf3c28cb..000000000 --- a/CCL/src/main/res/drawable/ic_mini_controller_pause.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_mini_controller_play.xml b/CCL/src/main/res/drawable/ic_mini_controller_play.xml deleted file mode 100644 index ca367f8a2..000000000 --- a/CCL/src/main/res/drawable/ic_mini_controller_play.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_mini_controller_stop.xml b/CCL/src/main/res/drawable/ic_mini_controller_stop.xml deleted file mode 100644 index 562f43486..000000000 --- a/CCL/src/main/res/drawable/ic_mini_controller_stop.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_mini_controller_upcoming_play.xml b/CCL/src/main/res/drawable/ic_mini_controller_upcoming_play.xml deleted file mode 100644 index 07e29e5d3..000000000 --- a/CCL/src/main/res/drawable/ic_mini_controller_upcoming_play.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_mini_controller_upcoming_stop.xml b/CCL/src/main/res/drawable/ic_mini_controller_upcoming_stop.xml deleted file mode 100644 index f7e05d6d6..000000000 --- a/CCL/src/main/res/drawable/ic_mini_controller_upcoming_stop.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_notification_disconnect_24dp.xml b/CCL/src/main/res/drawable/ic_notification_disconnect_24dp.xml deleted file mode 100644 index ca04a48cd..000000000 --- a/CCL/src/main/res/drawable/ic_notification_disconnect_24dp.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_notification_pause_24dp.xml b/CCL/src/main/res/drawable/ic_notification_pause_24dp.xml deleted file mode 100644 index e1ab3b19c..000000000 --- a/CCL/src/main/res/drawable/ic_notification_pause_24dp.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_notification_pause_48dp.xml b/CCL/src/main/res/drawable/ic_notification_pause_48dp.xml deleted file mode 100644 index 05b59a611..000000000 --- a/CCL/src/main/res/drawable/ic_notification_pause_48dp.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_notification_play_24dp.xml b/CCL/src/main/res/drawable/ic_notification_play_24dp.xml deleted file mode 100644 index bea2c5af0..000000000 --- a/CCL/src/main/res/drawable/ic_notification_play_24dp.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_notification_play_48dp.xml b/CCL/src/main/res/drawable/ic_notification_play_48dp.xml deleted file mode 100644 index 715fdaf3a..000000000 --- a/CCL/src/main/res/drawable/ic_notification_play_48dp.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_notification_stop_24dp.xml b/CCL/src/main/res/drawable/ic_notification_stop_24dp.xml deleted file mode 100644 index 860a90c46..000000000 --- a/CCL/src/main/res/drawable/ic_notification_stop_24dp.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/ic_notification_stop_48dp.xml b/CCL/src/main/res/drawable/ic_notification_stop_48dp.xml deleted file mode 100644 index 338f5b7fb..000000000 --- a/CCL/src/main/res/drawable/ic_notification_stop_48dp.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/mini_gradient_light.xml b/CCL/src/main/res/drawable/mini_gradient_light.xml deleted file mode 100644 index 8e685d959..000000000 --- a/CCL/src/main/res/drawable/mini_gradient_light.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - diff --git a/CCL/src/main/res/drawable/progress_drawable.xml b/CCL/src/main/res/drawable/progress_drawable.xml deleted file mode 100644 index a7c40ed11..000000000 --- a/CCL/src/main/res/drawable/progress_drawable.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/skip_next_button.xml b/CCL/src/main/res/drawable/skip_next_button.xml deleted file mode 100644 index b7026fc0d..000000000 --- a/CCL/src/main/res/drawable/skip_next_button.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/drawable/skip_previous_button.xml b/CCL/src/main/res/drawable/skip_previous_button.xml deleted file mode 100644 index 8624acf8a..000000000 --- a/CCL/src/main/res/drawable/skip_previous_button.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/layout-land/cast_activity.xml b/CCL/src/main/res/layout-land/cast_activity.xml deleted file mode 100644 index 8bc966223..000000000 --- a/CCL/src/main/res/layout-land/cast_activity.xml +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CCL/src/main/res/layout-v10/custom_notification.xml b/CCL/src/main/res/layout-v10/custom_notification.xml deleted file mode 100644 index e238f44ed..000000000 --- a/CCL/src/main/res/layout-v10/custom_notification.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/layout-v14/custom_notification.xml b/CCL/src/main/res/layout-v14/custom_notification.xml deleted file mode 100755 index 4bb7d42e2..000000000 --- a/CCL/src/main/res/layout-v14/custom_notification.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/CCL/src/main/res/layout/cast_activity.xml b/CCL/src/main/res/layout/cast_activity.xml deleted file mode 100644 index 0769d1820..000000000 --- a/CCL/src/main/res/layout/cast_activity.xml +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CCL/src/main/res/layout/custom_media_route_controller_controls_dialog.xml b/CCL/src/main/res/layout/custom_media_route_controller_controls_dialog.xml deleted file mode 100755 index c33b6c397..000000000 --- a/CCL/src/main/res/layout/custom_media_route_controller_controls_dialog.xml +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/layout/custom_notification.xml b/CCL/src/main/res/layout/custom_notification.xml deleted file mode 100755 index 50488560d..000000000 --- a/CCL/src/main/res/layout/custom_notification.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/layout/custom_tracks_dialog_layout.xml b/CCL/src/main/res/layout/custom_tracks_dialog_layout.xml deleted file mode 100644 index ccd2b6940..000000000 --- a/CCL/src/main/res/layout/custom_tracks_dialog_layout.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/layout/mini_controller.xml b/CCL/src/main/res/layout/mini_controller.xml deleted file mode 100644 index 65cb15971..000000000 --- a/CCL/src/main/res/layout/mini_controller.xml +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/layout/tracks_row_layout.xml b/CCL/src/main/res/layout/tracks_row_layout.xml deleted file mode 100644 index faba15ae7..000000000 --- a/CCL/src/main/res/layout/tracks_row_layout.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/menu/cast_player_menu.xml b/CCL/src/main/res/menu/cast_player_menu.xml deleted file mode 100644 index 6683ca733..000000000 --- a/CCL/src/main/res/menu/cast_player_menu.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - diff --git a/CCL/src/main/res/values-af/strings.xml b/CCL/src/main/res/values-af/strings.xml deleted file mode 100755 index a82b22d75..000000000 --- a/CCL/src/main/res/values-af/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast - Companion-biblioteek - - 1.10 - - Speel op … - - Regstreeks - Kanselleer - Aan - Af - - Inligting nie beskikbaar nie - - OK - Fout - Saai tans uit - na %1$s - - Laai tans … - Geen - media-inligting beskikbaar nie - - Probeer tans - vorige sessie herstel … - - - Kon nie program begin nie - - Die - versoek om die program te begin, het verstryk! - - - Die program wat jy probeer begin, is nie op jou Chromecast-toestel beskikbaar nie - - - Kon nie die terugspeel van media begin nie - - Kon - nie die terugspeel van media stop nie - - - Kon nie die terugspeel van media laat wag nie - - \'n - Onbekende fout het voorgekom - - - Kon nie aan die toestel koppel nie - - Kon nie die volume - stel nie - - Daar is geen - verbinding met die uitsaaitoestel nie - - Geen verbinding nie - - - Verbinding is verloor met die uitsaaitoestel. Program probeer tans die verbinding herstel, - indien moontlik. Wag \'n paar sekondes en probeer dan weer. - - Kon nie die - handeling uitvoer nie - - Kon nie met die - uitsaaitoestel sinkroniseer nie - - Kon - nie media op die uitsaaitoestel laai nie - - Kon nie - na die nuwe posisie op die uitsaaitoestel soek nie - - \'n Bedienerfout - het by die ontvangerspeler voorgekom - - - Magtiging het uitgetel - - Kon nie die - onderskrifstyl opdateer nie. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-ar-rXB/strings.xml b/CCL/src/main/res/values-ar-rXB/strings.xml deleted file mode 100755 index d723902d3..000000000 --- a/CCL/src/main/res/values-ar-rXB/strings.xml +++ /dev/null @@ -1,101 +0,0 @@ - - ‏‮Cast‬‏ ‏‮Companion‬‏ - ‏‮Library‬‏ - - 1.10 - - ‏‮Play‬‏ - ‏‮on‬‏… - - ‏‮Live‬‏ - ‏‮Cancel‬‏ - ‏‮On‬‏ - ‏‮Off‬‏ - - ‏‮Information‬‏ ‏‮Not‬‏ ‏‮Available‬‏ - - ‏‮OK‬‏ - ‏‮Error‬‏ - ‏‮Casting‬‏ - ‏‮to‬‏ %1$s - - ‏‮Loading‬‏… - - ‏‮No‬‏ ‏‮media‬‏ ‏‮information‬‏ ‏‮available‬‏ - - ‏‮Attempting‬‏ - ‏‮to‬‏ ‏‮recover‬‏ ‏‮previous‬‏ ‏‮session‬‏… - - - ‏‮Failed‬‏ ‏‮to‬‏ ‏‮launch‬‏ ‏‮application‬‏ - - - ‏‮The‬‏ ‏‮request‬‏ ‏‮to‬‏ ‏‮launch‬‏ ‏‮the‬‏ ‏‮application‬‏ ‏‮has‬‏ ‏‮timed‬‏ ‏‮out‬‏! - - - ‏‮The‬‏ ‏‮application‬‏ ‏‮you‬‏ ‏‮are‬‏ ‏‮trying‬‏ ‏‮to‬‏ ‏‮launch‬‏ ‏‮is‬‏ ‏‮not‬‏ - ‏‮available‬‏ ‏‮on‬‏ ‏‮your‬‏ ‏‮Chromecast‬‏ ‏‮device‬‏ - - - ‏‮Failed‬‏ ‏‮to‬‏ ‏‮start‬‏ ‏‮the‬‏ ‏‮playback‬‏ ‏‮of‬‏ ‏‮media‬‏ - - - ‏‮Failed‬‏ ‏‮to‬‏ ‏‮stop‬‏ ‏‮the‬‏ ‏‮playback‬‏ ‏‮of‬‏ ‏‮media‬‏ - - - ‏‮Failed‬‏ ‏‮to‬‏ ‏‮pause‬‏ ‏‮the‬‏ ‏‮playback‬‏ ‏‮of‬‏ ‏‮media‬‏ - - ‏‮An‬‏ - ‏‮unknown‬‏ ‏‮error‬‏ ‏‮was‬‏ ‏‮encountered‬‏ - - - ‏‮Could‬‏ ‏‮not‬‏ ‏‮connect‬‏ ‏‮to‬‏ ‏‮the‬‏ ‏‮device‬‏ - - ‏‮Failed‬‏ ‏‮to‬‏ - ‏‮set‬‏ ‏‮the‬‏ ‏‮volume‬‏ - - ‏‮No‬‏ - ‏‮connection‬‏ ‏‮to‬‏ ‏‮the‬‏ ‏‮cast‬‏ ‏‮device‬‏ ‏‮is‬‏ ‏‮present‬‏ - - ‏‮No‬‏ ‏‮connection‬‏ - - - ‏‮Connection‬‏ ‏‮to‬‏ ‏‮the‬‏ ‏‮cast‬‏ ‏‮device‬‏ ‏‮has‬‏ ‏‮been‬‏ ‏‮lost‬‏. ‏‮Application‬‏ - ‏‮is‬‏ ‏‮trying‬‏ ‏‮to‬‏ ‏‮re‬‏-‏‮establish‬‏ ‏‮the‬‏ ‏‮connection‬‏, ‏‮if‬‏ ‏‮possible‬‏. - ‏‮Please‬‏ ‏‮wait‬‏ ‏‮for‬‏ ‏‮a‬‏ ‏‮few‬‏ ‏‮seconds‬‏ ‏‮and‬‏ ‏‮try‬‏ ‏‮again‬‏. - - ‏‮Failed‬‏ - ‏‮to‬‏ ‏‮perform‬‏ ‏‮the‬‏ ‏‮action‬‏ - - ‏‮Failed‬‏ ‏‮to‬‏ - ‏‮sync‬‏ ‏‮up‬‏ ‏‮with‬‏ ‏‮the‬‏ ‏‮cast‬‏ ‏‮device‬‏ - - - ‏‮Failed‬‏ ‏‮to‬‏ ‏‮load‬‏ ‏‮media‬‏ ‏‮on‬‏ ‏‮the‬‏ ‏‮cast‬‏ ‏‮device‬‏ - - - ‏‮Failed‬‏ ‏‮to‬‏ ‏‮seek‬‏ ‏‮to‬‏ ‏‮the‬‏ ‏‮new‬‏ ‏‮position‬‏ ‏‮on‬‏ ‏‮the‬‏ ‏‮cast‬‏ - ‏‮device‬‏ - - ‏‮Receiver‬‏ - ‏‮player‬‏ ‏‮has‬‏ ‏‮encountered‬‏ ‏‮a‬‏ ‏‮sever‬‏ ‏‮error‬‏ - - - ‏‮Authorization‬‏ ‏‮timed‬‏ ‏‮out‬‏ - - ‏‮Failed‬‏ ‏‮to‬‏ - ‏‮update‬‏ ‏‮the‬‏ ‏‮Captions‬‏ ‏‮style‬‏. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-bg/strings.xml b/CCL/src/main/res/values-bg/strings.xml deleted file mode 100755 index 8bb9e39fb..000000000 --- a/CCL/src/main/res/values-bg/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Игра на… - - На живо - Отказ - Включено - Изключено - - Няма налична информация - - OK - Грешка - Предава се към - %1$s - - Зарежда се… - Няма - налична информация за мултимедията - - Извършва се опит - за възстановяване на предишна сесия... - - - Стартирането на приложението не бе успешно - - - Заявката за стартиране на приложението изтече! - - - Приложението, което се опитвате да стартирате, не е налично на устройството ви с Chromecast - - - Стартирането на възпроизвеждането на мултимедията не бе успешно - - - Спирането на възпроизвеждането на мултимедията не бе успешно - - - Поставянето на пауза на възпроизвеждането не бе успешно - - - Възникна неизвестна грешка - - - Неуспешно свързване с устройството - - Задаването на - силата на звука не бе успешно - - Няма налична - връзка с устройството Cast - - Няма връзка - - - Връзката с устройството Cast бе изгубена. Приложението се опитва да установи повторно - връзка, ако е възможно. Моля, изчакайте няколко секунди и опитайте отново. - - Действието не - бе успешно - - Синхронизирането с - устройството Cast не бе успешно - - - Зареждането на мултимедия на устройството с Cast не бе успешно - - - Неуспешно действие на устройството Cast - - Плейърът - приемник се натъкна на сървърна грешка - - - Упълномощаването изтече - - Актуализирането на стила - на субтитрите не бе успешно. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-ca/strings.xml b/CCL/src/main/res/values-ca/strings.xml deleted file mode 100755 index 8c249da97..000000000 --- a/CCL/src/main/res/values-ca/strings.xml +++ /dev/null @@ -1,99 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reprodueix - a… - - En directe - Cancel·la - Activa - Desactiva - - Informació no disponible - - D\'acord - Error - S\'està - emetent a %1$s - - S’està carregant… - - No - hi ha informació disponible sobre mitjans. - - S\'està provant de - recuperar la sessió anterior… - - - No s\'ha pogut iniciar l\'aplicació. - - - S\'ha esgotat el temps d\'espera de la sol·licitud per iniciar l\'aplicació. - - - L\'aplicació que proveu d\'iniciar no està disponible al vostre dispositiu Chromecast. - - No - s\'ha pogut iniciar la reproducció dels mitjans. - - No - s\'ha pogut aturar la reproducció dels mitjans. - - - No s\'ha pogut pausar la reproducció dels mitjans. - - S\'ha - produït un problema desconegut. - - - No s\'ha pogut establir la connexió amb el dispositiu. - - No s\'ha pogut - configurar el volum. - - No hi ha cap - connexió disponible per al dispositiu d\'emissió. - - No hi ha connexió. - - - S\'ha perdut la connexió amb el dispositiu d\'emissió. L\'aplicació està provant de - recuperar-la, si és possible. Espereu un moment i torneu-ho a provar. - - No s\'ha pogut - executar l\'acció. - - No s\'ha pogut fer la - sincronització amb el dispositiu d\'emissió. - - No - s\'han pogut carregar els mitjans locals al dispositiu d\'emissió. - - No s\'ha - pogut trobar una posició nova al dispositiu d\'emissió. - - El reproductor - receptor ha detectat un error del servidor. - - - S\'ha esgotat el temps d\'espera de l\'autorització. - - No s\'ha pogut - actualitzar l\'estil dels subtítols. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-da/strings.xml b/CCL/src/main/res/values-da/strings.xml deleted file mode 100755 index 163a54262..000000000 --- a/CCL/src/main/res/values-da/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Afspil på… - - Live - Annuller - Til - Fra - - Oplysningerne er ikke tilgængelige - - OK - Fejl - Caster til - %1$s - - Indlæser… - Der - er ingen tilgængelige medieoplysninger - - Vi forsøger at - gendanne den forrige session… - - - Appen kunne ikke indlæses - - Der - opstod timeout under forsøget på at indlæse appen - - - Den app, du forsøger at indlæse, er ikke tilgængelig på din Chromecast-enhed - - - Medieafspilningen kunne ikke startes - - - Medieafspilningen kunne ikke stoppes - - - Medieafspilningen kunne ikke sættes på pause - - Der - opstod en ukendt fejl - - - Der kunne ikke oprettes forbindelse til enheden - - Lydstyrken kunne - ikke indstilles - - Der er ingen - forbindelse til Cast-enheden - - Der er ingen forbindelse - - - Forbindelsen til Cast-enheden blev afbrudt. Appen forsøger at oprette forbindelse igen. Vent - et par sekunder, og prøv igen. - - Handlingen - kunne ikke udføres - - Synkronisering med - Cast-enheden mislykkedes - - - Medieindlæsning i Cast-enheden mislykkedes - - Søgning - til den nye position på Cast-enheden mislykkedes - - - Modtagerafspilleren stødte på en serverfejl - - - Der opstod timeout under forsøget på godkendelse - - Tekstdesignet kunne ikke - opdateres. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-de-rAT/strings.xml b/CCL/src/main/res/values-de-rAT/strings.xml deleted file mode 100755 index 1edb50f59..000000000 --- a/CCL/src/main/res/values-de-rAT/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Wiedergeben - auf... - - Live - Abbrechen - An - Aus - - Informationen nicht verfügbar - - OK - Fehler - Übertragung an - %1$s - - Wird geladen... - - Keine Medieninformationen verfügbar - - Es wird versucht, - die vorherige Sitzung wiederherzustellen... - - - Die App konnte nicht gestartet werden. - - Bei - der Anfrage zum Starten der App ist eine Zeitüberschreitung aufgetreten. - - - Die App, die Sie starten möchten, ist auf Ihrem Chromecast-Gerät nicht verfügbar. - - - Die Medienwiedergabe konnte nicht gestartet werden. - - Die - Medienwiedergabe konnte nicht angehalten werden. - - - Die Medienwiedergabe konnte nicht pausiert werden. - - Ein - unbekannter Fehler ist aufgetreten. - - - Es konnte keine Verbindung zum Gerät hergestellt werden. - - Die Lautstärke - konnte nicht eingestellt werden. - - Es besteht keine - Verbindung zum Übertragungsgerät. - - Keine Verbindung - - - Die Verbindung zum Übertragungsgerät wurde getrennt. Die App möchte die Verbindung nach - Möglichkeit wiederherstellen. Warten Sie einige Sekunden und versuchen Sie es dann erneut. - - Die Aktion - konnte nicht ausgeführt werden. - - Die Synchronisation mit - dem Übertragungsgerät konnte nicht durchgeführt werden. - - Die - Medien konnten nicht auf dem Übertragungsgerät geladen werden. - - Die neue - Position konnte auf dem Übertragungsgerät nicht festgelegt werden. - - Beim - Empfänger-Player ist ein Serverfehler aufgetreten. - - - Zeitüberschreitung bei der Autorisierung - - Der Untertitelstil konnte - nicht aktualisiert werden. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-de-rCH/strings.xml b/CCL/src/main/res/values-de-rCH/strings.xml deleted file mode 100755 index 1edb50f59..000000000 --- a/CCL/src/main/res/values-de-rCH/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Wiedergeben - auf... - - Live - Abbrechen - An - Aus - - Informationen nicht verfügbar - - OK - Fehler - Übertragung an - %1$s - - Wird geladen... - - Keine Medieninformationen verfügbar - - Es wird versucht, - die vorherige Sitzung wiederherzustellen... - - - Die App konnte nicht gestartet werden. - - Bei - der Anfrage zum Starten der App ist eine Zeitüberschreitung aufgetreten. - - - Die App, die Sie starten möchten, ist auf Ihrem Chromecast-Gerät nicht verfügbar. - - - Die Medienwiedergabe konnte nicht gestartet werden. - - Die - Medienwiedergabe konnte nicht angehalten werden. - - - Die Medienwiedergabe konnte nicht pausiert werden. - - Ein - unbekannter Fehler ist aufgetreten. - - - Es konnte keine Verbindung zum Gerät hergestellt werden. - - Die Lautstärke - konnte nicht eingestellt werden. - - Es besteht keine - Verbindung zum Übertragungsgerät. - - Keine Verbindung - - - Die Verbindung zum Übertragungsgerät wurde getrennt. Die App möchte die Verbindung nach - Möglichkeit wiederherstellen. Warten Sie einige Sekunden und versuchen Sie es dann erneut. - - Die Aktion - konnte nicht ausgeführt werden. - - Die Synchronisation mit - dem Übertragungsgerät konnte nicht durchgeführt werden. - - Die - Medien konnten nicht auf dem Übertragungsgerät geladen werden. - - Die neue - Position konnte auf dem Übertragungsgerät nicht festgelegt werden. - - Beim - Empfänger-Player ist ein Serverfehler aufgetreten. - - - Zeitüberschreitung bei der Autorisierung - - Der Untertitelstil konnte - nicht aktualisiert werden. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-de/strings.xml b/CCL/src/main/res/values-de/strings.xml deleted file mode 100755 index 1edb50f59..000000000 --- a/CCL/src/main/res/values-de/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Wiedergeben - auf... - - Live - Abbrechen - An - Aus - - Informationen nicht verfügbar - - OK - Fehler - Übertragung an - %1$s - - Wird geladen... - - Keine Medieninformationen verfügbar - - Es wird versucht, - die vorherige Sitzung wiederherzustellen... - - - Die App konnte nicht gestartet werden. - - Bei - der Anfrage zum Starten der App ist eine Zeitüberschreitung aufgetreten. - - - Die App, die Sie starten möchten, ist auf Ihrem Chromecast-Gerät nicht verfügbar. - - - Die Medienwiedergabe konnte nicht gestartet werden. - - Die - Medienwiedergabe konnte nicht angehalten werden. - - - Die Medienwiedergabe konnte nicht pausiert werden. - - Ein - unbekannter Fehler ist aufgetreten. - - - Es konnte keine Verbindung zum Gerät hergestellt werden. - - Die Lautstärke - konnte nicht eingestellt werden. - - Es besteht keine - Verbindung zum Übertragungsgerät. - - Keine Verbindung - - - Die Verbindung zum Übertragungsgerät wurde getrennt. Die App möchte die Verbindung nach - Möglichkeit wiederherstellen. Warten Sie einige Sekunden und versuchen Sie es dann erneut. - - Die Aktion - konnte nicht ausgeführt werden. - - Die Synchronisation mit - dem Übertragungsgerät konnte nicht durchgeführt werden. - - Die - Medien konnten nicht auf dem Übertragungsgerät geladen werden. - - Die neue - Position konnte auf dem Übertragungsgerät nicht festgelegt werden. - - Beim - Empfänger-Player ist ein Serverfehler aufgetreten. - - - Zeitüberschreitung bei der Autorisierung - - Der Untertitelstil konnte - nicht aktualisiert werden. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-en-rGB/strings.xml b/CCL/src/main/res/values-en-rGB/strings.xml deleted file mode 100755 index 560890ecc..000000000 --- a/CCL/src/main/res/values-en-rGB/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Play on… - - Live - Cancel - On - Off - - Information Not Available - - OK - Error - Casting to - %1$s - - Loading… - No - media information available - - Attempting to - recover previous session… - - - Failed to launch application - - The - request to launch the application has timed out! - - - The application you are trying to launch is not available on your Chromecast device - - - Failed to start the playback of media - - - Failed to stop the playback of media - - - Failed to pause the playback of media - - An - unknown error was encountered - - - Could not connect to the device - - Failed to set the - volume - - No connection to - the cast device is present - - No connection - - - Connection to the cast device has been lost. Application is trying to re-establish the - connection, if possible. Please wait for a few seconds and try again. - - Failed to - perform the action - - Failed to sync up with - the cast device - - - Failed to load media on the cast device - - Failed - to seek to the new position on the cast device - - Receiver player - has encountered a sever error - - - Authorisation timed out - - Failed to update the - Captions style. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-en-rIE/strings.xml b/CCL/src/main/res/values-en-rIE/strings.xml deleted file mode 100755 index 560890ecc..000000000 --- a/CCL/src/main/res/values-en-rIE/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Play on… - - Live - Cancel - On - Off - - Information Not Available - - OK - Error - Casting to - %1$s - - Loading… - No - media information available - - Attempting to - recover previous session… - - - Failed to launch application - - The - request to launch the application has timed out! - - - The application you are trying to launch is not available on your Chromecast device - - - Failed to start the playback of media - - - Failed to stop the playback of media - - - Failed to pause the playback of media - - An - unknown error was encountered - - - Could not connect to the device - - Failed to set the - volume - - No connection to - the cast device is present - - No connection - - - Connection to the cast device has been lost. Application is trying to re-establish the - connection, if possible. Please wait for a few seconds and try again. - - Failed to - perform the action - - Failed to sync up with - the cast device - - - Failed to load media on the cast device - - Failed - to seek to the new position on the cast device - - Receiver player - has encountered a sever error - - - Authorisation timed out - - Failed to update the - Captions style. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-en-rIN/strings.xml b/CCL/src/main/res/values-en-rIN/strings.xml deleted file mode 100755 index 560890ecc..000000000 --- a/CCL/src/main/res/values-en-rIN/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Play on… - - Live - Cancel - On - Off - - Information Not Available - - OK - Error - Casting to - %1$s - - Loading… - No - media information available - - Attempting to - recover previous session… - - - Failed to launch application - - The - request to launch the application has timed out! - - - The application you are trying to launch is not available on your Chromecast device - - - Failed to start the playback of media - - - Failed to stop the playback of media - - - Failed to pause the playback of media - - An - unknown error was encountered - - - Could not connect to the device - - Failed to set the - volume - - No connection to - the cast device is present - - No connection - - - Connection to the cast device has been lost. Application is trying to re-establish the - connection, if possible. Please wait for a few seconds and try again. - - Failed to - perform the action - - Failed to sync up with - the cast device - - - Failed to load media on the cast device - - Failed - to seek to the new position on the cast device - - Receiver player - has encountered a sever error - - - Authorisation timed out - - Failed to update the - Captions style. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-en-rSG/strings.xml b/CCL/src/main/res/values-en-rSG/strings.xml deleted file mode 100755 index 560890ecc..000000000 --- a/CCL/src/main/res/values-en-rSG/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Play on… - - Live - Cancel - On - Off - - Information Not Available - - OK - Error - Casting to - %1$s - - Loading… - No - media information available - - Attempting to - recover previous session… - - - Failed to launch application - - The - request to launch the application has timed out! - - - The application you are trying to launch is not available on your Chromecast device - - - Failed to start the playback of media - - - Failed to stop the playback of media - - - Failed to pause the playback of media - - An - unknown error was encountered - - - Could not connect to the device - - Failed to set the - volume - - No connection to - the cast device is present - - No connection - - - Connection to the cast device has been lost. Application is trying to re-establish the - connection, if possible. Please wait for a few seconds and try again. - - Failed to - perform the action - - Failed to sync up with - the cast device - - - Failed to load media on the cast device - - Failed - to seek to the new position on the cast device - - Receiver player - has encountered a sever error - - - Authorisation timed out - - Failed to update the - Captions style. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-en-rXA/strings.xml b/CCL/src/main/res/values-en-rXA/strings.xml deleted file mode 100755 index 1ab92f926..000000000 --- a/CCL/src/main/res/values-en-rXA/strings.xml +++ /dev/null @@ -1,103 +0,0 @@ - - [Çåšţ Çömþåñîöñ Ļîбŕåŕý - one two three] - - [1.10 one] - - [Þļåý öñ… - one] - - [Ļîvé one] - [Çåñçéļ one] - [Öñ one] - [Öƒƒ one] - - [Îñƒöŕmåţîöñ Ñöţ Åvåîļåбļé one two three] - - [ÖĶ one] - [Éŕŕöŕ one] - [Çåšţîñĝ ţö - ᐅ%1$sᐊ one two three] - - [Ļöåðîñĝ… one] - [Ñö - méðîå îñƒöŕmåţîöñ åvåîļåбļé one two three four five six seven] - - [Åţţémþţîñĝ ţö - ŕéçövéŕ þŕévîöûš šéššîöñ… one two three four five six seven eight] - - - [Fåîļéð ţö ļåûñçĥ åþþļîçåţîöñ one two three four five six] - - [Ţĥé - ŕéqûéšţ ţö ļåûñçĥ ţĥé åþþļîçåţîöñ ĥåš ţîméð öûţ¡ one two three four five six seven eight - nine ten eleven] - - - [Ţĥé åþþļîçåţîöñ ýöû åŕé ţŕýîñĝ ţö ļåûñçĥ îš ñöţ åvåîļåбļé öñ ýöûŕ Çĥŕöméçåšţ ðévîçé one two - three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen] - - - [Fåîļéð ţö šţåŕţ ţĥé þļåýбåçķ öƒ méðîå one two three four five six seven eight] - - - [Fåîļéð ţö šţöþ ţĥé þļåýбåçķ öƒ méðîå one two three four five six seven eight] - - - [Fåîļéð ţö þåûšé ţĥé þļåýбåçķ öƒ méðîå one two three four five six seven eight] - - [Åñ - ûñķñöŵñ éŕŕöŕ ŵåš éñçöûñţéŕéð one two three four five six seven] - - - [Çöûļð ñöţ çöññéçţ ţö ţĥé ðévîçé one two three four five six seven] - - [Fåîļéð ţö šéţ ţĥé - vöļûmé one two three four five] - - [Ñö çöññéçţîöñ ţö - ţĥé çåšţ ðévîçé îš þŕéšéñţ one two three four five six seven eight nine] - - [Ñö çöññéçţîöñ one two] - - - [Çöññéçţîöñ ţö ţĥé çåšţ ðévîçé ĥåš бééñ ļöšţ. Åþþļîçåţîöñ îš ţŕýîñĝ ţö ŕé-éšţåбļîšĥ ţĥé - çöññéçţîöñ, îƒ þöššîбļé. Þļéåšé ŵåîţ ƒöŕ å ƒéŵ šéçöñðš åñð ţŕý åĝåîñ. one two three four - five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen - eighteen nineteen twenty twentyone twentytwo twentythree] - - [Fåîļéð ţö - þéŕƒöŕm ţĥé åçţîöñ one two three four five six] - - [Fåîļéð ţö šýñç ûþ ŵîţĥ - ţĥé çåšţ ðévîçé one two three four five six seven eight] - - - [Fåîļéð ţö ļöåð méðîå öñ ţĥé çåšţ ðévîçé one two three four five six seven eight] - - [Fåîļéð - ţö šééķ ţö ţĥé ñéŵ þöšîţîöñ öñ ţĥé çåšţ ðévîçé one two three four five six seven eight nine - ten eleven] - - [Ŕéçéîvéŕ þļåýéŕ - ĥåš éñçöûñţéŕéð å šévéŕ éŕŕöŕ one two three four five six seven eight nine] - - - [Åûţĥöŕîžåţîöñ ţîméð öûţ one two three] - - [Fåîļéð ţö ûþðåţé ţĥé - Çåþţîöñš šţýļé. one two three four five six seven eight] - - \ No newline at end of file diff --git a/CCL/src/main/res/values-en-rXC/strings.xml b/CCL/src/main/res/values-en-rXC/strings.xml deleted file mode 100755 index ef2445c15..000000000 --- a/CCL/src/main/res/values-en-rXC/strings.xml +++ /dev/null @@ -1,139 +0,0 @@ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‎‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‎Cast - Companion Library‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‎‎‏‏‎‎‎‎1.10‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‎Play - on…‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎Live‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎Cancel‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎On‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎Off‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎Information - Not Available‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‏‎‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‎‏‏‏‎OK‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎Error‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‏‎‎‏‎‎‎Casting - to ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎Loading…‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‏‎‎No - media information available‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎Attempting - to recover previous session…‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎Failed - to launch application‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‎‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎The - request to launch the application has timed out!‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‎The - application you are trying to launch is not available on your Chromecast device‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎Failed - to start the playback of media‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎Failed - to stop the playback of media‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‎‎‎Failed - to pause the playback of media‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‎An - unknown error was encountered‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎Could - not connect to the device‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎Failed - to set the volume‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‏‎No - connection to the cast device is present‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎No - connection‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎Connection - to the cast device has been lost. Application is trying to re-establish the connection, if - possible. Please wait for a few seconds and try again.‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎Failed - to perform the action‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎Failed - to sync up with the cast device‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‏‎Failed - to load media on the cast device‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‎Failed - to seek to the new position on the cast device‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎Receiver - player has encountered a sever error‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‎‎Authorization - timed out‎‏‎‎‏‎ - - - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‎‎‎‎Failed - to update the Captions style.‎‏‎‎‏‎ - - \ No newline at end of file diff --git a/CCL/src/main/res/values-en-rZA/strings.xml b/CCL/src/main/res/values-en-rZA/strings.xml deleted file mode 100755 index 560890ecc..000000000 --- a/CCL/src/main/res/values-en-rZA/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Play on… - - Live - Cancel - On - Off - - Information Not Available - - OK - Error - Casting to - %1$s - - Loading… - No - media information available - - Attempting to - recover previous session… - - - Failed to launch application - - The - request to launch the application has timed out! - - - The application you are trying to launch is not available on your Chromecast device - - - Failed to start the playback of media - - - Failed to stop the playback of media - - - Failed to pause the playback of media - - An - unknown error was encountered - - - Could not connect to the device - - Failed to set the - volume - - No connection to - the cast device is present - - No connection - - - Connection to the cast device has been lost. Application is trying to re-establish the - connection, if possible. Please wait for a few seconds and try again. - - Failed to - perform the action - - Failed to sync up with - the cast device - - - Failed to load media on the cast device - - Failed - to seek to the new position on the cast device - - Receiver player - has encountered a sever error - - - Authorisation timed out - - Failed to update the - Captions style. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rAR/strings.xml b/CCL/src/main/res/values-es-rAR/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rAR/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rBO/strings.xml b/CCL/src/main/res/values-es-rBO/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rBO/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rCL/strings.xml b/CCL/src/main/res/values-es-rCL/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rCL/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rCO/strings.xml b/CCL/src/main/res/values-es-rCO/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rCO/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rCR/strings.xml b/CCL/src/main/res/values-es-rCR/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rCR/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rDO/strings.xml b/CCL/src/main/res/values-es-rDO/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rDO/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rEC/strings.xml b/CCL/src/main/res/values-es-rEC/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rEC/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rES/strings.xml b/CCL/src/main/res/values-es-rES/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rES/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rGT/strings.xml b/CCL/src/main/res/values-es-rGT/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rGT/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rHN/strings.xml b/CCL/src/main/res/values-es-rHN/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rHN/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rMX/strings.xml b/CCL/src/main/res/values-es-rMX/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rMX/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rNI/strings.xml b/CCL/src/main/res/values-es-rNI/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rNI/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rPA/strings.xml b/CCL/src/main/res/values-es-rPA/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rPA/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rPE/strings.xml b/CCL/src/main/res/values-es-rPE/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rPE/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rPR/strings.xml b/CCL/src/main/res/values-es-rPR/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rPR/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rPY/strings.xml b/CCL/src/main/res/values-es-rPY/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rPY/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rSV/strings.xml b/CCL/src/main/res/values-es-rSV/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rSV/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rUS/strings.xml b/CCL/src/main/res/values-es-rUS/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rUS/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rUY/strings.xml b/CCL/src/main/res/values-es-rUY/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rUY/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es-rVE/strings.xml b/CCL/src/main/res/values-es-rVE/strings.xml deleted file mode 100755 index 69b9b2302..000000000 --- a/CCL/src/main/res/values-es-rVE/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproducir - en… - - En vivo - Cancelar - Activado - Desactivado - La - información no está disponible. - - Aceptar - Error - Transmitir a - %1$s - - Cargando… - La - información de medios no está disponible. - - Intentando - recuperar la sesión anterior... - - - Error al iniciar la aplicación - - El - tiempo para solicitar el inicio de la aplicación se agotó. - - - La aplicación que intenta iniciar no está disponible en su dispositivo Chromecast. - - - Error al iniciar la reproducción de medios - - - Error al finalizar la reproducción de medios - - - Error al pausar la reproducción de medios - - Se - detectó un error desconocido. - - - No se pudo establecer la conexión con el dispositivo. - - Error al definir - el volumen - - No hay conexión - con el dispositivo de transmisión. - - Sin conexión - - - Se perdió la conexión con el dispositivo de transmisión. La aplicación está intentando - restablecer la conexión. Espere unos segundos e inténtelo nuevamente. - - Error al - realizar la acción - - Error al sincronizar - con el dispositivo de transmisión - - - Error al cargar los medios en el dispositivo de transmisión - - Error al - buscar la nueva posición en el dispositivo de transmisión - - El reproductor - que recibe la transmisión detectó un error del servidor. - - El - tiempo para la autorización se agotó. - - Error al actualizar el - estilo de los subtítulos - - \ No newline at end of file diff --git a/CCL/src/main/res/values-es/strings.xml b/CCL/src/main/res/values-es/strings.xml deleted file mode 100755 index 6ac42c1f1..000000000 --- a/CCL/src/main/res/values-es/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Jugar en… - - En directo - Cancelar - Activar - Desactivar - La - información no está disponible - - Aceptar - Error - Transmitiendo - a %1$s - - Cargando… - No - hay información de medios disponible - - Intentando - recuperar la sesión anterior… - - - No se ha podido ejecutar la aplicación - - Se - ha agotado el tiempo de espera para solicitar la ejecución de la aplicación - - - La aplicación que estás intentando ejecutar no está disponible en tu dispositivo Chromecast - - No - se ha podido iniciar la reproducción de los medios - - No - se ha podido detener la reproducción de los medios - - - No se ha podido pausar la reproducción de los medios - - Se ha - detectado un error desconocido - - - No se ha podido conectar con el dispositivo. - - No se ha podido - establecer el volumen - - No hay ninguna - conexión al dispositivo de transmisión - - Sin conexión - - - Se ha perdido la conexión al dispositivo de transmisión. La aplicación está intentando - volver a establecer la conexión, si es posible. Espera unos segundos e inténtalo de nuevo. - - No se ha - podido llevar a cabo la acción - - No se ha podido - sincronizar con el dispositivo de transmisión - - No - se han podido cargar los medios en el dispositivo de transmisión - - No se ha - podido buscar la nueva posición en el dispositivo de transmisión - - El reproductor - receptor ha detectado un error del servidor - - Se - ha agotado el tiempo de espera de autorización - - No se ha podido - actualizar el estilo de los subtítulos. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-et/strings.xml b/CCL/src/main/res/values-et/strings.xml deleted file mode 100755 index 2ad53c12d..000000000 --- a/CCL/src/main/res/values-et/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Casti lisaseadmete - kogu - - 1.10 - - Esita seadmes - … - - Aktiivne - Tühista - Sees - Väljas - - Teave pole saadaval - - OK - Viga - Ülekandmine - seadmesse %1$s - - Laadimine … - - Meediateave pole saadaval - - Proovitakse - taastada eelmist seanssi … - - - Rakenduse käivitamine ebaõnnestus - - - Rakenduse käivitamise taotlus on aegunud. - - - Rakendus, mida püüate käivitada, pole Chromecasti seadmes saadaval - - - Meedia taasesituse alustamine ebaõnnestus - - - Meedia taasesituse peatamine ebaõnnestus - - - Meedia taasesituse peatamine ebaõnnestus - - Ilmnes - tundmatu viga - - - Seadmega ei õnnestunud ühendust luua - - Helitugevuse - määramine ebaõnnestus - - Ühendus - ülekandeseadmega puudub - - Ühendus puudub - - - Ühendus ülekandeseadmega on katkenud. Rakendus püüab võimaluse korral ühendust uuesti luua. - Oodake mõni sekund ja proovige uuesti. - - Toimingu - tegemine ebaõnnestus - - Ülekandeseadmega - sünkroonimine ebaõnnestus - - - Meediat ei õnnestunud ülekandeseadmesse laadida - - - Ülekandeseadme uue positsiooni tuvastamine ebaõnnestus - - Vastuvõtvas - pleieris ilmnes serveri viga - - - Autoriseerimine on aegunud - - Tiitrite stiili - värskendamine ebaõnnestus. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-fi/strings.xml b/CCL/src/main/res/values-fi/strings.xml deleted file mode 100755 index 15b5b0419..000000000 --- a/CCL/src/main/res/values-fi/strings.xml +++ /dev/null @@ -1,96 +0,0 @@ - - Suoratoistokirjasto - - 1.10 - - Toista... - - Suora - Peruuta - Päällä - Ei päällä - - Tiedot eivät ole saatavana - - OK - Virhe - - Suoratoistetaan laitteeseen %1$s - - Ladataan… - - Mediatiedot eivät ole käytettävissä - - Edellistä istuntoa - yritetään palauttaa... - - - Sovelluksen käynnistäminen epäonnistui - - - Sovelluksen käynnistyspyyntö aikakatkaistiin! - - - Sovellus, jota yrität käynnistää, ei ole käytettävissä Chromecast-laitteessasi - - - Median toiston aloitus epäonnistui - - - Median toiston pysäytys epäonnistui - - - Median toiston keskeytys epäonnistui - - - Tuntematon virhe ilmeni - - - Laitteeseen ei saatu yhteyttä - - Äänenvoimakkuuden - asettaminen epäonnistui - - - Suoratoistolaitteeseen ei ole yhteyttä - - Ei yhteyttä - - - Yhteys suoratoistolaitteeseen menetettiin. Sovellus yrittää muodostaa yhteyden uudelleen. - Odota muutama sekunti ja yritä uudelleen. - - Toiminto - epäonnistui - - Synkronointi - suoratoistolaitteen kanssa epäonnistui - - - Median lataaminen suoratoistolaitteeseen epäonnistui - - Uuden - paikan hakeminen suoratoistolaitteessa epäonnistui - - Vakava virhe - vastaanottimen soittimessa - - - Valtuutus aikakatkaistiin - - Tekstityksen tyylin - päivittäminen epäonnistui. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-fil/strings.xml b/CCL/src/main/res/values-fil/strings.xml deleted file mode 100755 index 440f7048a..000000000 --- a/CCL/src/main/res/values-fil/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - I-play sa - ... - - Live - Kanselahin - I-on - I-off - - Hindi Available ang Impormasyon - - OK - Error - Nagka-cast sa - %1$s - - Naglo-load… - - Walang available na impormasyon ng media - - Sinusubukang - i-recover ang nakaraang session... - - - Hindi nailunsad ang application - - - Nag-timeout ang kahilingan upang ilunsad ang application! - - - Hindi available sa iyong Chromecast device ang application na sinusubukan mong ilunsad - - - Hindi nasimulan ang pag-playback ng media - - - Hindi nahinto ang pag-playback ng media - - - Hindi na-pause ang pag-playback ng media - - - Nagkaroon ng hindi kilalang error - - - Hindi makakonekta sa device - - Hindi naitakda ang - volume - - Walang nakitang - koneksyon sa cast device - - Walang koneksyon - - - Nawala ang koneksyon sa cast device. Sinusubukan ng application na makagawa muli ng - koneksyon, kung maaari. Mangyaring maghintay ng ilang segundo at subukang muli. - - Hindi nagawa - ang pagkilos - - Hindi nakapag-sync sa - cast device - - - Hindi na-load ang media sa cast device - - Hindi - nahanap ang bagong posisyon sa cast device - - Nagkaroon ng - error sa server ang receiver player - - - Nag-time out ang pagpapahintulot - - Hindi na-update ang - estilo ng Mga Caption. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-fr-rCA/strings.xml b/CCL/src/main/res/values-fr-rCA/strings.xml deleted file mode 100755 index d50003e24..000000000 --- a/CCL/src/main/res/values-fr-rCA/strings.xml +++ /dev/null @@ -1,99 +0,0 @@ - - Bibliothèque de - compagnon Cast - - 1.10 - - Visionner - sur… - - En temps réel - Annuler - Activée - Désactivée - - Information non disponible - - OK - Erreur - Diffusion sur - %1$s en cours - - Chargement en cours… - - - Aucune information sur le média disponible - - Tentative de - récupération de la session précédente… - - - Échec de l\'ouverture de l\'application - - La - demande d\'ouverture de l\'application a expiré! - - - L\'application que vous tentez d\'ouvrir n\'est pas disponible sur votre appareil Chromecast - - - Échec du lancement de la lecture du média - - - Échec de l\'arrêt de la lecture du média - - - Échec de la mise sur pause de la lecture du média - - Une - erreur inconnue est survenue - - - Impossible de se connecter à l\'appareil - - Échec de réglage - du volume - - Aucune connexion à - l\'appareil Cast - - Aucune connexion - - - Perte de la connexion à l\'appareil Cast. L\'application tente de rétablir la connexion si - cela est possible. Veuillez attendre quelques secondes, puis réessayer. - - Impossible - d\'effectuer cette action - - Échec de la - synchronisation avec l\'appareil Cast - - - Échec du chargement de contenu sur l\'appareil Cast - - Échec de - recherche d\'une nouvelle position dans l\'appareil Cast - - Le - lecteur-récepteur a rencontré une erreur grave - - - L\'autorisation est échue - - Échec de la mise à jour - du style des sous-titres. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-fr-rCH/strings.xml b/CCL/src/main/res/values-fr-rCH/strings.xml deleted file mode 100755 index 92d8666cc..000000000 --- a/CCL/src/main/res/values-fr-rCH/strings.xml +++ /dev/null @@ -1,99 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Lire sur… - - Disponible en ligne - Annuler - Activer - Désactiver - - Informations non disponibles. - - OK - Erreur - Cast vers %1$s - en cours... - - Chargement en cours… - - - Aucune information sur le média disponible. - - Tentative de - récupération de la session précédente en cours… - - - Impossible de lancer l\'application. - - La - demande de lancement de l\'application a expiré. - - - L\'application que vous essayez de lancer n\'est pas disponible sur votre appareil - Chromecast. - - - Impossible de lancer la lecture du média. - - - Impossible d\'arrêter la lecture du média. - - - Impossible de mettre sur pause la lecture du média. - - Une - erreur inconnue a été détectée. - - - Connexion impossible à l\'appareil. - - Impossible de - régler le volume. - - Aucune connexion à - l\'appareil Cast n\'est disponible. - - Aucune connexion. - - - La connexion à l\'appareil Cast a été perdue. L\'application essaye à nouveau d\'établir une - connexion, si possible. Veuillez patienter quelques secondes et réessayer. - - Impossible - d\'effectuer l\'action. - - Impossible d\'effectuer - la synchronisation avec l\'appareil Cast. - - - Impossible de charger le média sur l\'appareil Cast. - - - Impossible de rechercher la nouvelle position sur l\'appareil Cast. - - Le lecteur de - l\'appareil de réception a rencontré une erreur de serveur. - - - Expiration de l\'autorisation - - Impossible de mettre à - jour le style des sous-titres. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-fr/strings.xml b/CCL/src/main/res/values-fr/strings.xml deleted file mode 100755 index 92d8666cc..000000000 --- a/CCL/src/main/res/values-fr/strings.xml +++ /dev/null @@ -1,99 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Lire sur… - - Disponible en ligne - Annuler - Activer - Désactiver - - Informations non disponibles. - - OK - Erreur - Cast vers %1$s - en cours... - - Chargement en cours… - - - Aucune information sur le média disponible. - - Tentative de - récupération de la session précédente en cours… - - - Impossible de lancer l\'application. - - La - demande de lancement de l\'application a expiré. - - - L\'application que vous essayez de lancer n\'est pas disponible sur votre appareil - Chromecast. - - - Impossible de lancer la lecture du média. - - - Impossible d\'arrêter la lecture du média. - - - Impossible de mettre sur pause la lecture du média. - - Une - erreur inconnue a été détectée. - - - Connexion impossible à l\'appareil. - - Impossible de - régler le volume. - - Aucune connexion à - l\'appareil Cast n\'est disponible. - - Aucune connexion. - - - La connexion à l\'appareil Cast a été perdue. L\'application essaye à nouveau d\'établir une - connexion, si possible. Veuillez patienter quelques secondes et réessayer. - - Impossible - d\'effectuer l\'action. - - Impossible d\'effectuer - la synchronisation avec l\'appareil Cast. - - - Impossible de charger le média sur l\'appareil Cast. - - - Impossible de rechercher la nouvelle position sur l\'appareil Cast. - - Le lecteur de - l\'appareil de réception a rencontré une erreur de serveur. - - - Expiration de l\'autorisation - - Impossible de mettre à - jour le style des sous-titres. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-gsw/strings.xml b/CCL/src/main/res/values-gsw/strings.xml deleted file mode 100755 index 1edb50f59..000000000 --- a/CCL/src/main/res/values-gsw/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Wiedergeben - auf... - - Live - Abbrechen - An - Aus - - Informationen nicht verfügbar - - OK - Fehler - Übertragung an - %1$s - - Wird geladen... - - Keine Medieninformationen verfügbar - - Es wird versucht, - die vorherige Sitzung wiederherzustellen... - - - Die App konnte nicht gestartet werden. - - Bei - der Anfrage zum Starten der App ist eine Zeitüberschreitung aufgetreten. - - - Die App, die Sie starten möchten, ist auf Ihrem Chromecast-Gerät nicht verfügbar. - - - Die Medienwiedergabe konnte nicht gestartet werden. - - Die - Medienwiedergabe konnte nicht angehalten werden. - - - Die Medienwiedergabe konnte nicht pausiert werden. - - Ein - unbekannter Fehler ist aufgetreten. - - - Es konnte keine Verbindung zum Gerät hergestellt werden. - - Die Lautstärke - konnte nicht eingestellt werden. - - Es besteht keine - Verbindung zum Übertragungsgerät. - - Keine Verbindung - - - Die Verbindung zum Übertragungsgerät wurde getrennt. Die App möchte die Verbindung nach - Möglichkeit wiederherstellen. Warten Sie einige Sekunden und versuchen Sie es dann erneut. - - Die Aktion - konnte nicht ausgeführt werden. - - Die Synchronisation mit - dem Übertragungsgerät konnte nicht durchgeführt werden. - - Die - Medien konnten nicht auf dem Übertragungsgerät geladen werden. - - Die neue - Position konnte auf dem Übertragungsgerät nicht festgelegt werden. - - Beim - Empfänger-Player ist ein Serverfehler aufgetreten. - - - Zeitüberschreitung bei der Autorisierung - - Der Untertitelstil konnte - nicht aktualisiert werden. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-hr/strings.xml b/CCL/src/main/res/values-hr/strings.xml deleted file mode 100755 index a8c6d518a..000000000 --- a/CCL/src/main/res/values-hr/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Popratna biblioteka za - emitiranje - - 1.10 - - Pokreni na… - - Uživo - Odustani - Uključeno - Isključeno - - Podaci nisu dostupni - - U redu - Pogreška - Emitiranje na - uređaju %1$s - - Učitavanje… - Nema - dostupnih podataka o medijskom sadržaju - - Pokušaj vraćanja - prethodne sesije... - - - Pokretanje aplikacije nije uspjelo - - - Zahtjev za pokretanje aplikacije istekao je. - - - Aplikacija koju pokušavate pokrenuti nije dostupna na vašem Chromecast uređaju - - - Pokretanje reprodukcije medijskog sadržaja nije uspjelo - - - Zaustavljanje reprodukcije medijskog sadržaja nije uspjelo - - - Pauziranje reprodukcije medijskog sadržaja nije uspjelo - - Došlo - je do nepoznate pogreške - - - Povezivanje s uređajem nije uspjelo - - Postavljanje - glasnoće nije uspjelo - - Ne postoji veza s - uređajem za emitiranje - - Niste povezani - - - Izgubljena je veza s uređajem za emitiranje. Aplikacija pokušava ponovno uspostaviti vezu, - ako je to moguće. Pričekajte nekoliko sekundi i pokušajte ponovno. - - Izvođenje - radnje nije uspjelo - - Sinkroniziranje s - uređajem za emitiranje nije uspjelo - - - Učitavanje medijskog sadržaja na uređaj za emitiranje nije uspjelo - - Traženje - nove pozicije na uređaju za emitiranje nije uspjelo - - Došlo je do - pogreške poslužitelja u playeru prijemnika - - - Autorizacija je istekla - - Ažuriranje stila titlova - nije uspjelo. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-id/strings.xml b/CCL/src/main/res/values-id/strings.xml deleted file mode 100755 index e549f6cf3..000000000 --- a/CCL/src/main/res/values-id/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Pustaka Pendamping - Cast - - 1.10 - - Putar di... - - Langsung - Batal - Aktif - Nonaktif - - Informasi Tidak Tersedia - - Oke - Kesalahan - - Mentransmisikan ke %1$s - - Memuat… - - Informasi media tidak tersedia - - Mencoba memulihkan - sesi sebelumnya... - - - Gagal meluncurkan aplikasi - - - Waktu permintaan untuk meluncurkan aplikasi telah habis! - - - Aplikasi yang ingin dicoba diluncurkan tidak tersedia pada perangkat Chromecast Anda. - - - Gagal memulai pemutaran media - - - Gagal menghentikan pemutaran media - - - Gagal menjeda pemutaran media - - Terjadi - kesalahan yang tidak dikenal - - - Tidak dapat tersambung ke perangkat - - Gagal menetapkan - volume - - Tidak ada - sambungan ke perangkat transmisi - - Tidak ada sambungan - - - Sambungan ke perangkat transmisi terputus. Aplikasi sedang mencoba menyambungkan kembali, - jika memungkinkan. Tunggu beberapa saat dan coba lagi. - - Gagal - melakukan tindakan - - Gagal menyinkronkan - dengan perangkat transmisi - - - Gagal memuat media pada perangkat transmisi - - Gagal - mencari posisi baru pada perangkat transmisi - - Pemutar penerima - mengalami kesalahan sever - - - Waktu otorisasi telah habis - - Gagal memperbarui gaya - Teks. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-in/strings.xml b/CCL/src/main/res/values-in/strings.xml deleted file mode 100755 index e549f6cf3..000000000 --- a/CCL/src/main/res/values-in/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Pustaka Pendamping - Cast - - 1.10 - - Putar di... - - Langsung - Batal - Aktif - Nonaktif - - Informasi Tidak Tersedia - - Oke - Kesalahan - - Mentransmisikan ke %1$s - - Memuat… - - Informasi media tidak tersedia - - Mencoba memulihkan - sesi sebelumnya... - - - Gagal meluncurkan aplikasi - - - Waktu permintaan untuk meluncurkan aplikasi telah habis! - - - Aplikasi yang ingin dicoba diluncurkan tidak tersedia pada perangkat Chromecast Anda. - - - Gagal memulai pemutaran media - - - Gagal menghentikan pemutaran media - - - Gagal menjeda pemutaran media - - Terjadi - kesalahan yang tidak dikenal - - - Tidak dapat tersambung ke perangkat - - Gagal menetapkan - volume - - Tidak ada - sambungan ke perangkat transmisi - - Tidak ada sambungan - - - Sambungan ke perangkat transmisi terputus. Aplikasi sedang mencoba menyambungkan kembali, - jika memungkinkan. Tunggu beberapa saat dan coba lagi. - - Gagal - melakukan tindakan - - Gagal menyinkronkan - dengan perangkat transmisi - - - Gagal memuat media pada perangkat transmisi - - Gagal - mencari posisi baru pada perangkat transmisi - - Pemutar penerima - mengalami kesalahan sever - - - Waktu otorisasi telah habis - - Gagal memperbarui gaya - Teks. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-it/strings.xml b/CCL/src/main/res/values-it/strings.xml deleted file mode 100755 index a7d761d8f..000000000 --- a/CCL/src/main/res/values-it/strings.xml +++ /dev/null @@ -1,100 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Riproduci - su… - - Live - Annulla - Attivo - Non attivo - - Informazione non disponibile - - OK - Errore - Trasmissione - su %1$s in corso - - Caricamento in corso… - - - Nessuna informazione disponibile sul file multimediale - - Tentativo di - recupero della sessione precedente in corso... - - - Impossibile avviare l\'applicazione - - La - richiesta di avvio dell\'applicazione è scaduta. - - - L\'applicazione che stai tentando di avviare non è disponibile sul tuo dispositivo - Chromecast - - - Impossibile avviare la riproduzione del file multimediale - - - Impossibile interrompere la riproduzione del file multimediale - - - Impossibile mettere in pausa la riproduzione del file multimediale - - Si è - verificato un errore sconosciuto - - - Connessione al dispositivo non riuscita - - Impossibile - impostare il volume - - Non è presente - alcuna connessione al dispositivo di trasmissione - - Nessuna connessione - - - La connessione al dispositivo di trasmissione è stata persa. L\'applicazione sta tentando di - ristabilire la connessione, se possibile. Attendi qualche secondo e riprova. - - Impossibile - eseguire l\'azione - - Impossibile eseguire la - sincronizzazione con il dispositivo di trasmissione - - - Impossibile caricare il file multimediale sul dispositivo di trasmissione - - - Impossibile cercare la nuova posizione sul dispositivo di trasmissione - - Il giocatore - ricevente ha riscontrato un errore del server - - - Autorizzazione scaduta - - Impossibile caricare lo - stile dei sottotitoli. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-ja/strings.xml b/CCL/src/main/res/values-ja/strings.xml deleted file mode 100755 index b80aa3339..000000000 --- a/CCL/src/main/res/values-ja/strings.xml +++ /dev/null @@ -1,92 +0,0 @@ - - Cast Companion - Library - - 1.10 - - 次の端末で再生… - - ライブ - キャンセル - オン - オフ - - ご利用可能な情報はありません - - OK - エラー - - %1$sにキャストしています - - 読み込んでいます… - - ご利用可能なメディア情報はありません - - - 前回のセッションを復元しようとしています… - - - アプリの起動に失敗しました - - - アプリの起動リクエストがタイムアウトになりました。 - - - 起動しようとしているアプリはChromecastデバイスではご利用いただけません - - - メディアの再生の開始に失敗しました - - - メディアの再生の停止に失敗しました - - - メディアの再生の一時停止に失敗しました - - - 不明なエラーが発生しました - - - デバイスに接続できませんでした - - 音量の設定に失敗しました - - - キャストデバイスへの接続が検出されません - - 接続なし - - - キャストデバイスへの接続が切断されました。アプリは可能な限り接続の再確立を試みます。数秒ほどお待ちになってからもう一度お試しください。 - - 操作の実行に失敗しました - - キャストデバイスとの同期に失敗しました - - - キャストデバイス上のメディアの読み込みに失敗しました - - - キャストデバイス上で新しい位置が見つかりませんでした - - - レシーバプレーヤーの稼働中にサーバーエラーが発生しました - - - 承認がタイムアウトになりました - - 字幕スタイルの更新に失敗しました - - \ No newline at end of file diff --git a/CCL/src/main/res/values-ko/strings.xml b/CCL/src/main/res/values-ko/strings.xml deleted file mode 100755 index 5e3c20e23..000000000 --- a/CCL/src/main/res/values-ko/strings.xml +++ /dev/null @@ -1,2 +0,0 @@ - -2.6재생할 기기...실시간취소사용사용 안함정보 사용 불가일시중지재생연결 해제없음확인오류%1$s(으)로 전송로드 중...미디어 정보가 없습니다.애플리케이션을 실행하지 못했습니다.애플리케이션 실행 요청 제한 시간이 초과되었습니다.실행하려는 애플리케이션은 전송 기기에서 지원되지 않습니다.미디어 재생을 시작하지 못했습니다.미디어 재생을 중지하지 못했습니다.미디어 재생을 일시중지하지 못했습니다.기기에 연결할 수 없습니다.볼륨을 설정하지 못했습니다.전송 기기에 연결되지 않았습니다.연결되지 않았습니다.전송 기기와의 연결이 끊어졌습니다. 애플리케이션에서 가능하면 다시 연결하려고 시도 중입니다. 잠시 기다린 후 다시 시도해 주세요.작업을 수행하지 못했습니다.전송 기기와 동기화하지 못했습니다.전송 기기에서 새 위치를 찾지 못했습니다.수신기 플레이어에서 심각한 오류가 발생했습니다.승인 제한 시간이 초과되었습니다.자막 스타일을 업데이트하지 못했습니다.다음 콘텐츠 \ No newline at end of file diff --git a/CCL/src/main/res/values-ln/strings.xml b/CCL/src/main/res/values-ln/strings.xml deleted file mode 100755 index 92d8666cc..000000000 --- a/CCL/src/main/res/values-ln/strings.xml +++ /dev/null @@ -1,99 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Lire sur… - - Disponible en ligne - Annuler - Activer - Désactiver - - Informations non disponibles. - - OK - Erreur - Cast vers %1$s - en cours... - - Chargement en cours… - - - Aucune information sur le média disponible. - - Tentative de - récupération de la session précédente en cours… - - - Impossible de lancer l\'application. - - La - demande de lancement de l\'application a expiré. - - - L\'application que vous essayez de lancer n\'est pas disponible sur votre appareil - Chromecast. - - - Impossible de lancer la lecture du média. - - - Impossible d\'arrêter la lecture du média. - - - Impossible de mettre sur pause la lecture du média. - - Une - erreur inconnue a été détectée. - - - Connexion impossible à l\'appareil. - - Impossible de - régler le volume. - - Aucune connexion à - l\'appareil Cast n\'est disponible. - - Aucune connexion. - - - La connexion à l\'appareil Cast a été perdue. L\'application essaye à nouveau d\'établir une - connexion, si possible. Veuillez patienter quelques secondes et réessayer. - - Impossible - d\'effectuer l\'action. - - Impossible d\'effectuer - la synchronisation avec l\'appareil Cast. - - - Impossible de charger le média sur l\'appareil Cast. - - - Impossible de rechercher la nouvelle position sur l\'appareil Cast. - - Le lecteur de - l\'appareil de réception a rencontré une erreur de serveur. - - - Expiration de l\'autorisation - - Impossible de mettre à - jour le style des sous-titres. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-lt/strings.xml b/CCL/src/main/res/values-lt/strings.xml deleted file mode 100755 index 5427cd020..000000000 --- a/CCL/src/main/res/values-lt/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Leisti… - - Aktyvus - Atšaukti - Įjungta - Išjungta - - Informacija nepasiekiama - - Gerai - Klaida - Perduodama į - %1$s - - Įkeliama… - - Medijos informacija nepasiekiama - - Bandoma atkurti - ankstesnį seansą… - - - Nepavyko paleisti programos - - - Baigėsi programos paleidimo užklausos skirtasis laikas! - - - Programa, kurią bandote paleisti, nepasiekiama jūsų „Chromecast“ įrenginyje - - - Nepavyko pradėti medijos atkūrimo - - - Nepavyko sustabdyti medijos atkūrimo - - - Nepavyko pristabdyti medijos atkūrimo - - Aptikta - nežinoma klaida - - - Nepavyko prisijungti prie įrenginio - - Nepavyko nustatyti - garsumo - - Nėra ryšio su - perdavimo įrenginiu - - Nėra ryšio - - - Prarastas ryšys su perdavimo įrenginiu. Programa bando iš naujo užmegzti ryšį, jei pavyks. - Šiek tiek palaukite ir bandykite dar kartą. - - Nepavyko - atlikti veiksmo - - Nepavyko sinchronizuoti - su perdavimo įrenginiu - - - Nepavyko įkelti medijos perdavimo įrenginyje - - Nepavyko - surasti naujos pozicijos perdavimo įrenginyje - - Gavėjo - leistuvėje pateikta serverio klaida - - - Baigėsi autorizavimo skirtasis laikas - - Nepavyko atnaujinti - antraščių stiliaus. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-lv/strings.xml b/CCL/src/main/res/values-lv/strings.xml deleted file mode 100755 index d173e4e05..000000000 --- a/CCL/src/main/res/values-lv/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Spēlēt... - - Tiešraide - Atcelt - Ieslēgt - Izslēgt - - Informācija nav pieejama. - - Labi - Kļūda - Notiek apraide - uz: %1$s - - Notiek ielāde… - - Informācija par multivides saturu nav pieejama. - - Tiek mēģināts - atjaunot iepriekšējo sesiju... - - - Neizdevās palaist lietojumprogrammu - - - Radās lietojumprogrammas palaišanas pieprasījuma noildze! - - - Lietojumprogramma, kuru mēģināt palaist, nav pieejama jūsu Chromecast ierīcē. - - - Neizdevās sākt multivides satura atskaņošanu. - - - Neizdevās pārtraukt multivides satura atskaņošanu. - - - Neizdevās apturēt multivides satura atskaņošanu. - - Radās - nezināma kļūda. - - - Nevarēja izveidot savienojumu ar ierīci. - - Neizdevās iestatīt - skaļumu. - - Nav izveidots - savienojums ar Cast ierīci. - - Nav savienojuma. - - - Tika pārtraukts savienojums ar Cast ierīci. Tiek mēģināts atkārtoti izveidot savienojumu ar - lietojumprogrammu (ja tas ir iespējams). Lūdzu, dažas sekundes uzgaidiet un pēc tam mēģiniet - vēlreiz. - - Neizdevās - veikt darbību. - - Neizdevās veikt - sinhronizāciju ar Cast ierīci. - - - Neizdevās ielādēt multivides saturu Cast ierīcē. - - - Neizdevās atrast jaunu pozīciju Cast ierīcē. - - Saņēmēja pusē - radās servera kļūda. - - - Iestājās autorizācijas noildze. - - Neizdevās atjaunināt - parakstu stilu. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-ml/strings.xml b/CCL/src/main/res/values-ml/strings.xml deleted file mode 100755 index 74da86659..000000000 --- a/CCL/src/main/res/values-ml/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - കാസ്റ്റ് സഹായ ലൈബ്രറി - - 1.10 - - പ്ലേ - ചെയ്തുകൊണ്ടേയിരിക്കുക... - - തത്സമയം - റദ്ദാക്കുക - ഓൺ ചെയ്യുക - ഓഫ് ചെയ്യുക - - വിവരം ലഭ്യമല്ല - - ശരി - പിശക് - %1$s-ലേക്ക് - കാസ്റ്റുചെയ്യുന്നു - - ലോഡുചെയ്യുന്നു... - - - മീഡിയ വിവരങ്ങളൊന്നും ലഭ്യമല്ല - - മുമ്പത്തെ സെഷൻ - വീണ്ടെടുക്കാൻ ശ്രമിക്കുന്നു… - - - ആപ്ലിക്കേഷൻ സമാരംഭിക്കുന്നത് പരാജയപ്പെട്ടു - - - ആപ്ലിക്കേഷൻ സമാരംഭിക്കുന്നതിനുള്ള അഭ്യർത്ഥനാ സമയം കഴിഞ്ഞു! - - - നിങ്ങൾ സമാരംഭിക്കാൻ ശ്രമിക്കുന്ന ആപ്ലിക്കേഷൻ നിങ്ങളുടെ Chromecast ഉപകരണത്തിൽ ലഭ്യമല്ല - - - മീഡിയ പ്ലേബാക്ക് ആരംഭിക്കുന്നത് പരാജയപ്പെട്ടു - - - മീഡിയ പ്ലേബാക്ക് നിർത്തുന്നത് പരാജയപ്പെട്ടു - - - മീഡിയ പ്ലേബാക്ക് താൽക്കാലം നിർത്തുന്നത് പരാജയപ്പെട്ടു - - ഒരു - അജ്ഞാത പിശക് സംഭവിച്ചു - - - ഉപകരണത്തിലേക്ക് ബന്ധിപ്പിക്കാൻ കഴിഞ്ഞില്ല - - വോളിയം - ക്രമീകരിക്കുന്നത് പരാജയപ്പെട്ടു - - കാസ്റ്റ് - ഉപകരണത്തിലേക്ക് നിലവിൽ കണക്ഷനൊന്നുമില്ല - - കണക്ഷനൊന്നുമില്ല - - - കാസ്റ്റ് ഉപകരണത്തിലേക്കുള്ള കണക്ഷൻ നഷ്ടമായി. സാധ്യമെങ്കിൽ, കണക്ഷൻ പുനഃസ്ഥാപിക്കുന്നതിന് - ആപ്ലിക്കേഷൻ ശ്രമിക്കുന്നു. അൽപ്പസമയം കാത്തിരുന്ന ശേഷം വീണ്ടും ശ്രമിക്കുക. - - നടപടി - നിർവഹിക്കുന്നത് പരാജയപ്പെട്ടു - - കാസ്റ്റ് ഉപകരണവുമായി - സമന്വയിപ്പിക്കുന്നത് പരാജയപ്പെട്ടു - - - കാസ്റ്റ് ഉപകരണത്തിൽ മീഡിയ ലോഡുചെയ്യുന്നത് പരാജയപ്പെട്ടു - - കാസ്റ്റ് - ഉപകരണത്തിൽ പുതിയ സ്ഥാനം തേടൽ പരാജയപ്പെട്ടു - - റിസീവർ പ്ലെയർ - ഒരു സെർവർ പിശക് നേരിട്ടു - - - ആധികാരികമാക്കൽ സമയം കഴിഞ്ഞു - - ക്യാപ്ഷൻ ശൈലി അപ്ഡേറ്റ് - ചെയ്യുന്നത് പരാജയപ്പെട്ടു. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-mo/strings.xml b/CCL/src/main/res/values-mo/strings.xml deleted file mode 100755 index e9153a23a..000000000 --- a/CCL/src/main/res/values-mo/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Redați pe… - - Live - Anulați - Activați - Dezactivați - - Informația nu este disponibilă - - OK - Eroare - Se proiectează - pe %1$s - - Se încarcă… - Nu - sunt disponibile informații media - - Se încearcă - recuperarea sesiunii anterioare… - - - Eroare la lansarea aplicației - - - Solicitarea de lansare a aplicației a expirat! - - - Aplicația pe care încercați să o lansați nu este disponibilă pe Chromecast - - - Eroare la inițierea redării conținutului media - - - Eroare la oprirea redării conținutului media - - - Eroare la întreruperea redării conținutului media - - Eroare - necunoscută - - - Nu s-a putut conecta la dispozitiv - - Eroare la setarea - volumului - - Nu există nicio - conexiune la dispozitivul de proiecție - - Nicio conexiune - - - S-a pierdut conexiunea la dispozitivul de proiecție. Aplicația încearcă să restabilească - conexiunea, dacă este posibil. Așteptați câteva secunde și încercați din nou. - - Eroare la - realizarea acțiunii - - Eroare la sincronizarea - cu dispozitivul de proiecție - - - Eroare la încărcarea conținutului media pe dispozitivul de proiecție - - Eroare - la navigarea la noua poziție pe dispozitivul de proiecție - - Playerul - receiverului a întâmpinat o eroare de server - - - Autorizarea a expirat - - Eroare la actualizarea - stilului subtitrărilor. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-nb/strings.xml b/CCL/src/main/res/values-nb/strings.xml deleted file mode 100755 index 1c30710ca..000000000 --- a/CCL/src/main/res/values-nb/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Spill på - - Direkte - Avbryt - - Av - - Informasjonen er ikke tilgjengelig - - OK - Feil - Sender til - %1$s - - Laster inn … - - Ingen medieinformasjon er tilgjengelig - - Forsøker å - gjenopprette den forrige økten … - - - Appen kunne ikke startes - - - Forespørselen om å kjøre appen ble tidsavbrutt. - - - Appen du prøver å kjøre, er ikke tilgjengelig på Chromecast-enheten din - - - Medieavspillingen mislyktes - - - Medieavspillingen kunne ikke stoppes - - - Medieavspillingen kunne ikke settes på pause - - Det har - oppstått en ukjent feil - - - Kan ikke koble til enheten - - Kan ikke stille - inn volumet - - Det finnes ingen - tilkobling til Cast-enheten - - Ingen tilkobling - - - Tilkoblingen til Cast-enheten er tapt. Appen prøver om mulig å gjenopprette tilkoblingen. - Vent noen sekunder, og prøv på nytt. - - Handlingen - kunne ikke gjennomføres - - Synkroniseringen med - Cast-enheten mislyktes - - - Mediene på Cast-enheten kunne ikke lastes inn - - Søkingen - etter ny posisjon på Cast-enheten mislyktes - - Mottakeren har - støtt på en tjenerfeil - - - Godkjenningen er utløpt - - Stilen for tekstingen - kunne ikke oppdateres. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-no/strings.xml b/CCL/src/main/res/values-no/strings.xml deleted file mode 100755 index 1c30710ca..000000000 --- a/CCL/src/main/res/values-no/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Spill på - - Direkte - Avbryt - - Av - - Informasjonen er ikke tilgjengelig - - OK - Feil - Sender til - %1$s - - Laster inn … - - Ingen medieinformasjon er tilgjengelig - - Forsøker å - gjenopprette den forrige økten … - - - Appen kunne ikke startes - - - Forespørselen om å kjøre appen ble tidsavbrutt. - - - Appen du prøver å kjøre, er ikke tilgjengelig på Chromecast-enheten din - - - Medieavspillingen mislyktes - - - Medieavspillingen kunne ikke stoppes - - - Medieavspillingen kunne ikke settes på pause - - Det har - oppstått en ukjent feil - - - Kan ikke koble til enheten - - Kan ikke stille - inn volumet - - Det finnes ingen - tilkobling til Cast-enheten - - Ingen tilkobling - - - Tilkoblingen til Cast-enheten er tapt. Appen prøver om mulig å gjenopprette tilkoblingen. - Vent noen sekunder, og prøv på nytt. - - Handlingen - kunne ikke gjennomføres - - Synkroniseringen med - Cast-enheten mislyktes - - - Mediene på Cast-enheten kunne ikke lastes inn - - Søkingen - etter ny posisjon på Cast-enheten mislyktes - - Mottakeren har - støtt på en tjenerfeil - - - Godkjenningen er utløpt - - Stilen for tekstingen - kunne ikke oppdateres. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-pl/strings.xml b/CCL/src/main/res/values-pl/strings.xml deleted file mode 100755 index caf7939d1..000000000 --- a/CCL/src/main/res/values-pl/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Odtwarzaj… - - Na żywo - Anuluj - Wł. - Wył. - - Informacje niedostępne - - OK - Błąd - Przesyłanie do - %1$s - - Wczytywanie… - Brak - dostępnych informacji o multimediach - - Próba odzyskania - poprzedniej sesji… - - - Nie udało się uruchomić aplikacji - - - Upłynął czas żądania uruchomienia aplikacji - - - Aplikacja, którą próbujesz uruchomić, jest niedostępna na Twoim urządzeniu Chromecast - - - Nie udało się uruchomić odtwarzania multimediów - - Nie - udało się zatrzymać odtwarzania multimediów - - - Nie udało się wstrzymać odtwarzania multimediów - - - Wystąpił nieznany błąd - - - Nie udało się połączyć z urządzeniem - - Nie udało się - ustawić głośności - - Brak połączenia z - urządzeniem przesyłającym - - Brak połączenia - - - Utracono połączenie z urządzeniem przesyłającym. Aplikacja podejmuje próby ponownego - nawiązania połączenia. Poczekaj kilka sekund i spróbuj ponownie. - - Nie udało się - wykonać działania - - Nie udało się - zsynchronizować z urządzeniem przesyłającym - - Nie - udało się wczytać multimediów na urządzenie przesyłające - - Nie - udało się przejść do nowej pozycji w urządzeniu przesyłającym - - W odtwarzaczu - odbiornika wystąpił błąd serwera - - - Upłynął limit czasu autoryzacji - - Nie udało się - zaktualizować stylu Napisów. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-pt-rBR/strings.xml b/CCL/src/main/res/values-pt-rBR/strings.xml deleted file mode 100755 index 259036738..000000000 --- a/CCL/src/main/res/values-pt-rBR/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Jogar em… - - Ao vivo - Cancelar - Ativar - Desativar - - Informação indisponível - - OK - Erro - Transmitindo - para %1$s - - Carregando… - - Nenhuma informação de mídia disponível - - Tentando recuperar - sessão anterior... - - - Falha ao iniciar o aplicativo - - A - solicitação para iniciar o aplicativo expirou. - - - O aplicativo que você está tentando iniciar não está disponível no seu dispositivo - Chromecast - - - Falha ao iniciar a reprodução de mídia - - - Falha ao interromper a reprodução de mídia - - - Falha ao pausar a reprodução de mídia - - Um erro - desconhecido foi encontrado - - - Não foi possível conectar ao dispositivo - - Falha ao definir o - volume - - Sem conexão com o - dispositivo de transmissão - - Sem conexão - - - A conexão com o dispositivo de transmissão foi perdida. O aplicativo está tentando - restabelecer a conexão, se possível. Aguarde alguns segundos e tente novamente. - - Falha ao - executar a ação - - Falha ao sincronizar - com o dispositivo de transmissão - - - Falha ao carregar a mídia no dispositivo de transmissão - - Falha ao - buscar a nova posição no dispositivo de transmissão - - O player de - destino encontrou um erro de servidor - - A - autorização expirou - - Falha ao atualizar o - estilo das legendas. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-pt-rPT/strings.xml b/CCL/src/main/res/values-pt-rPT/strings.xml deleted file mode 100755 index 093bf970a..000000000 --- a/CCL/src/main/res/values-pt-rPT/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Reproduzir - em… - - Em direto - Cancelar - Ligar - Desligar - - Informações não disponíveis - - OK - Erro - A transmitir - para %1$s - - A carregar… - - Informações sobre multimédia não disponíveis. - - A tentar recuperar - a sessão anterior… - - - Falha ao iniciar a aplicação. - - O - pedido de início da aplicação expirou! - - - A aplicação que está a tentar iniciar não está disponível no seu dispositivo Chromecast. - - - Falha ao iniciar a reprodução de multimédia. - - - Falha ao parar a reprodução de multimédia. - - - Falha ao colocar a reprodução de multimédia em pausa. - - Ocorreu - um erro desconhecido. - - - Não foi possível ligar ao dispositivo. - - Falha ao definir o - volume. - - Não existe ligação - ao dispositivo de transmissão. - - Sem ligação - - - Ligação ao dispositivo de transmissão perdida. A aplicação está a tentar restabelecer a - ligação, se possível. Aguarde alguns segundos e tente de novo. - - Falha ao - efetuar a ação. - - Falha ao sincronizar - com o dispositivo de transmissão. - - - Falha ao carregar multimédia no dispositivo de transmissão. - - Falha ao - avançar para a nova posição no dispositivo de transmissão. - - O dispositivo do - recetor detetou um erro de servidor. - - A - autorização expirou. - - Falha ao atualizar o - estilo das legendas. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-pt/strings.xml b/CCL/src/main/res/values-pt/strings.xml deleted file mode 100755 index 259036738..000000000 --- a/CCL/src/main/res/values-pt/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Jogar em… - - Ao vivo - Cancelar - Ativar - Desativar - - Informação indisponível - - OK - Erro - Transmitindo - para %1$s - - Carregando… - - Nenhuma informação de mídia disponível - - Tentando recuperar - sessão anterior... - - - Falha ao iniciar o aplicativo - - A - solicitação para iniciar o aplicativo expirou. - - - O aplicativo que você está tentando iniciar não está disponível no seu dispositivo - Chromecast - - - Falha ao iniciar a reprodução de mídia - - - Falha ao interromper a reprodução de mídia - - - Falha ao pausar a reprodução de mídia - - Um erro - desconhecido foi encontrado - - - Não foi possível conectar ao dispositivo - - Falha ao definir o - volume - - Sem conexão com o - dispositivo de transmissão - - Sem conexão - - - A conexão com o dispositivo de transmissão foi perdida. O aplicativo está tentando - restabelecer a conexão, se possível. Aguarde alguns segundos e tente novamente. - - Falha ao - executar a ação - - Falha ao sincronizar - com o dispositivo de transmissão - - - Falha ao carregar a mídia no dispositivo de transmissão - - Falha ao - buscar a nova posição no dispositivo de transmissão - - O player de - destino encontrou um erro de servidor - - A - autorização expirou - - Falha ao atualizar o - estilo das legendas. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-ro/strings.xml b/CCL/src/main/res/values-ro/strings.xml deleted file mode 100755 index e9153a23a..000000000 --- a/CCL/src/main/res/values-ro/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Redați pe… - - Live - Anulați - Activați - Dezactivați - - Informația nu este disponibilă - - OK - Eroare - Se proiectează - pe %1$s - - Se încarcă… - Nu - sunt disponibile informații media - - Se încearcă - recuperarea sesiunii anterioare… - - - Eroare la lansarea aplicației - - - Solicitarea de lansare a aplicației a expirat! - - - Aplicația pe care încercați să o lansați nu este disponibilă pe Chromecast - - - Eroare la inițierea redării conținutului media - - - Eroare la oprirea redării conținutului media - - - Eroare la întreruperea redării conținutului media - - Eroare - necunoscută - - - Nu s-a putut conecta la dispozitiv - - Eroare la setarea - volumului - - Nu există nicio - conexiune la dispozitivul de proiecție - - Nicio conexiune - - - S-a pierdut conexiunea la dispozitivul de proiecție. Aplicația încearcă să restabilească - conexiunea, dacă este posibil. Așteptați câteva secunde și încercați din nou. - - Eroare la - realizarea acțiunii - - Eroare la sincronizarea - cu dispozitivul de proiecție - - - Eroare la încărcarea conținutului media pe dispozitivul de proiecție - - Eroare - la navigarea la noua poziție pe dispozitivul de proiecție - - Playerul - receiverului a întâmpinat o eroare de server - - - Autorizarea a expirat - - Eroare la actualizarea - stilului subtitrărilor. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-ru/strings.xml b/CCL/src/main/res/values-ru/strings.xml deleted file mode 100755 index 3d3c8ba72..000000000 --- a/CCL/src/main/res/values-ru/strings.xml +++ /dev/null @@ -1,2 +0,0 @@ - -2.6Смотреть на устройстве...Прямой эфирОтменаВключитьВыключитьИнформация отсутствует.ПриостановитьВоспроизвестиОтключитьНетОКОшибкаПередача на устройство \"%1$s\"Загрузка…Сведения о контенте отсутствуют.Не удалось запустить приложение.Время, отведенное на запуск приложения, истекло.Приложение недоступно на этом устройстве.Не удалось начать воспроизведение.Не удалось остановить воспроизведение.Не удалось приостановить воспроизведение.Не удалось подключиться к устройству.Не удалось настроить громкость.Нет соединения с устройством.Нет соединения.Соединение прервано. Приложение пытается его восстановить. Подождите несколько секунд и попробуйте подключиться снова.Не удалось выполнить действие.Не удалось синхронизировать данные с устройством.Не удалось перейти к новому месту.У проигрывателя устройства возникла серьезная ошибка.Время, отведенное на авторизацию, истекло.Не удалось изменить стиль субтитров.След. \ No newline at end of file diff --git a/CCL/src/main/res/values-sl/strings.xml b/CCL/src/main/res/values-sl/strings.xml deleted file mode 100755 index 89fa9173d..000000000 --- a/CCL/src/main/res/values-sl/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Knjižnica Cast - Companion - - 1.10 - - Predvajaj v - … - - V živo - Prekliči - Vklopljeno - Izklopljeno - - Informacije niso na voljo - - V redu - Napaka - Predvajanje v - %1$s - - Nalaganje … - - Podatki o medijih niso na voljo - - Poskus obnovitve - prejšnje seje … - - - Zagon aplikacije ni bil uspešno izveden - - - Zahteva za zagon aplikacije je potekla. - - - Aplikacija, ki jo želite zagnati, ni na voljo v napravi Chromecast - - - Predvajanje medijev se ni uspešno začelo. - - - Predvajanje medijev ni bilo uspešno končano - - - Predvajanje medijev ni bilo uspešno zaustavljeno - - Najdena - je bila neznana napaka - - - Povezave z napravo ni bilo mogoče vzpostaviti - - Nastavitev - glasnosti ni uspela - - Z napravo za - predvajanje ni vzpostavljene povezave - - Ni povezave - - - Povezava z napravo za predvajanje je bila prekinjena. Aplikacija bo poskusila znova - vzpostaviti povezavo. Počakajte nekaj sekund, nato poskusite znova. - - Dejanje ni - bilo uspešno izvedeno - - Sinhronizacija z - napravo za predvajanje ni bila uspešno izvedena - - - Mediji niso bili uspešno naloženi v napravo za predvajanje - - Iskanje - novega položaja v napravi za predvajanje ni bilo uspešno - - Predvajalnik - sprejemnika je naletel na resno napako - - - Pooblastilo je poteklo - - Slog napisov ni bil - uspešno posodobljen. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-sv/strings.xml b/CCL/src/main/res/values-sv/strings.xml deleted file mode 100755 index 5cbc66d49..000000000 --- a/CCL/src/main/res/values-sv/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Kompletterande - Cast-bibliotek - - 1.10 - - Fortsätt - spela … - - Live - Avbryt - - Av - - Informationen är inte tillgänglig - - OK - Fel - Castar via - %1$s - - Läser in … - - Ingen medieinformation tillgänglig - - Försöker återuppta - föregående session … - - - Det gick inte att starta programmet - - - Begäran om att starta programmet tog för lång tid! - - - Programmet du försöker starta finns inte på din Chromecast-enhet - - - Det gick inte att starta uppspelning av media - - Det - gick inte att stoppa uppspelning av media - - - Det gick inte att pausa uppspelning av media - - Ett - okänt fel inträffade - - - Det gick inte att ansluta till enheten - - Det gick inte att - ställa in volymen - - Det finns ingen - anslutning till Cast-enheten - - Ingen anslutning - - - Anslutningen till Cast-enheten avbröts. Programmet försöker återupprätta anslutningen om det - är möjligt. Vänta några sekunder och försök sedan igen. - - Det gick inte - att utföra åtgärden - - Det gick inte att - synkronisera med den Cast-enheten - - Det - gick inte att läsa in media på Cast-enheten - - Det gick - inte att ställa in den nya positionen på Cast-enheten - - Ett serverfel - har inträffat på mottagarspelaren - - - Auktoriseringen tog för lång tid - - Det gick inte att - uppdatera textformatet. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-sw600dp-land/dimens.xml b/CCL/src/main/res/values-sw600dp-land/dimens.xml deleted file mode 100644 index 5fc0c2b30..000000000 --- a/CCL/src/main/res/values-sw600dp-land/dimens.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - 500dp - - diff --git a/CCL/src/main/res/values-sw600dp/dimens.xml b/CCL/src/main/res/values-sw600dp/dimens.xml deleted file mode 100644 index 1e9e044aa..000000000 --- a/CCL/src/main/res/values-sw600dp/dimens.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - 15sp - 13sp - 64dp - 64dp - 16dp - - \ No newline at end of file diff --git a/CCL/src/main/res/values-ta/strings.xml b/CCL/src/main/res/values-ta/strings.xml deleted file mode 100755 index 01b3ece26..000000000 --- a/CCL/src/main/res/values-ta/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - விளையாடவும்… - - நேரலை - ரத்துசெய் - இயக்கு - முடக்கு - - தகவல் கிடைக்கவில்லை - - சரி - பிழை - %1$s - சாதனத்திற்கு அனுப்புகிறது - - ஏற்றுகிறது… - - மீடியா தகவல் ஏதும் இல்லை - - முந்தைய அமர்வை - மீட்டெடுக்க முயற்சிக்கிறது... - - - பயன்பாட்டைத் தொடங்குவது தோல்வியுற்றது - - - பயன்பாட்டைத் தொடங்குவதற்கான கோரிக்கை நேரம் முடிந்தது! - - - நீங்கள் தொடங்க முயற்சிக்கும் பயன்பாடு, உங்கள் Chromecast சாதனத்தில் இல்லை - - - மீடியாவை இயக்கத் தொடங்குவது தோல்வியுற்றது - - - மீடியா இயக்கத்தை நிறுத்துவது தோல்வியுற்றது - - - மீடியா இயக்கத்தை இடைநிறுத்துவது தோல்வியுற்றது - - அறியாத - பிழை ஏற்பட்டது - - - சாதனத்துடன் இணைக்க முடியவில்லை - - ஒலியளவை அமைப்பது - தோல்வியுற்றது - - அனுப்பும் - சாதனத்துடன் தற்போது எந்த இணைப்பும் இல்லை - - இணைப்பு இல்லை - - - அனுப்பும் சாதனத்துடனான இணைப்பு துண்டிக்கப்பட்டது. இணைப்பை மீண்டு நிறுவ பயன்பாடு - முயற்சிக்கிறது. சில வினாடிகள் காத்திருந்து, மீண்டும் முயற்சிக்கவும். - - செயலைச் - செய்வது தோல்வியுற்றது - - அனுப்பும் சாதனத்துடன் - ஒத்திசைப்பது தோல்வியுற்றது - - - அனுப்பும் சாதனத்தில் மீடியாவை ஏற்றுவது தோல்வியுற்றது - - - அனுப்பும் சாதனத்தில் புதிய நிலைக்குச் செல்வது தோல்வியுற்றது - - ரிசீவர் - பிளேயரில் சேவையகப் பிழை ஏற்பட்டுள்ளது - - - அங்கீகரிப்பு நேரம் காலாவதி ஆனது - - தலைப்புகள் நடையைப் - புதுப்பிப்பது தோல்வியடைந்தது. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-th/strings.xml b/CCL/src/main/res/values-th/strings.xml deleted file mode 100755 index 9986f53fb..000000000 --- a/CCL/src/main/res/values-th/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - เล่นบน… - - สด - ยกเลิก - เปิด - ปิด - - ไม่มีข้อมูล - - ตกลง - ข้อผิดพลาด - ส่งไปที่ - %1$s - - กำลังโหลด… - - ไม่มีข้อมูลสื่อ - - - กำลังพยายามกู้คืนเซสชันก่อนหน้านี้… - - - เปิดแอปพลิเคชันไม่สำเร็จ - - - คำขอเปิดแอปพลิเคชันหมดเวลา - - - แอปพลิเคชันที่คุณพยายามเปิดไม่มีให้บริการบนอุปกรณ์ Chromecast ของคุณ - - - เริ่มเล่นสื่อไม่สำเร็จ - - - หยุดการเล่นสื่อไม่สำเร็จ - - - หยุดการเล่นสื่อชั่วคราวไม่สำเร็จ - - - พบข้อผิดพลาดที่ไม่รู้จัก - - - ไม่สามารถเชื่อมต่อกับอุปกรณ์ - - - ตั้งระดับเสียงไม่สำเร็จ - - - ไม่พบการเชื่อมต่อกับเครื่องส่ง - - ไม่มีการเชื่อมต่อ - - - ขาดการติดต่อกับเครื่องส่ง แอปพลิเคชันกำลังพยายามเชื่อมต่อใหม่เท่าที่ทำได้ - โปรดรอสักครู่แล้วลองอีกครั้ง - - - ดำเนินการไม่สำเร็จ - - - ซิงค์กับเครื่องส่งไม่สำเร็จ - - - โหลดสื่อบนเครื่องส่งไม่สำเร็จ - - - หาตำแหน่งใหม่บนเครื่องส่งไม่สำเร็จ - - - โปรแกรมเล่นของเครื่องรับพบปัญหาด้านเซิร์ฟเวอร์ - - - การตรวจสอบสิทธิ์หมดเวลา - - - อัปเดตสไตล์ของคำบรรยายภาพไม่สำเร็จ - - \ No newline at end of file diff --git a/CCL/src/main/res/values-tl/strings.xml b/CCL/src/main/res/values-tl/strings.xml deleted file mode 100755 index 440f7048a..000000000 --- a/CCL/src/main/res/values-tl/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Cast Companion - Library - - 1.10 - - I-play sa - ... - - Live - Kanselahin - I-on - I-off - - Hindi Available ang Impormasyon - - OK - Error - Nagka-cast sa - %1$s - - Naglo-load… - - Walang available na impormasyon ng media - - Sinusubukang - i-recover ang nakaraang session... - - - Hindi nailunsad ang application - - - Nag-timeout ang kahilingan upang ilunsad ang application! - - - Hindi available sa iyong Chromecast device ang application na sinusubukan mong ilunsad - - - Hindi nasimulan ang pag-playback ng media - - - Hindi nahinto ang pag-playback ng media - - - Hindi na-pause ang pag-playback ng media - - - Nagkaroon ng hindi kilalang error - - - Hindi makakonekta sa device - - Hindi naitakda ang - volume - - Walang nakitang - koneksyon sa cast device - - Walang koneksyon - - - Nawala ang koneksyon sa cast device. Sinusubukan ng application na makagawa muli ng - koneksyon, kung maaari. Mangyaring maghintay ng ilang segundo at subukang muli. - - Hindi nagawa - ang pagkilos - - Hindi nakapag-sync sa - cast device - - - Hindi na-load ang media sa cast device - - Hindi - nahanap ang bagong posisyon sa cast device - - Nagkaroon ng - error sa server ang receiver player - - - Nag-time out ang pagpapahintulot - - Hindi na-update ang - estilo ng Mga Caption. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-uk/strings.xml b/CCL/src/main/res/values-uk/strings.xml deleted file mode 100755 index 1da6dd35c..000000000 --- a/CCL/src/main/res/values-uk/strings.xml +++ /dev/null @@ -1,98 +0,0 @@ - - Бібліотека Cast - Companion - - 1.10 - - Відтворити - на… - - Наживо - Скасувати - Увімкнути - Вимкнути - - Інформація недоступна - - OK - Помилка - Трансляція на - пристрій %1$s - - Завантаження… - - Інформація про медіа-вміст недоступна - - Триває спроба - відновити попередній сеанс… - - - Не вдалося запустити додаток - - Час - очікування запиту на запуск додатка минув. - - - Додаток, який ви намагаєтеся запустити, недоступний на вашому пристрої Chromecast - - Не - вдалося почати відтворення медіа-вмісту - - Не - вдалося зупинити відтворення медіа-вмісту - - - Не вдалося призупинити відтворення медіа-вмісту - - Сталася - невідома помилка - - - Не вдалося підключитися до пристрою - - Не вдалося - налаштувати гучність - - Немає з’єднання з - пристроєм для трансляції - - Немає з’єднання - - - З’єднання з пристроєм для трансляції втрачено. Додаток намагається за можливості повторно - встановити з’єднання. Зачекайте кілька секунд і повторіть спробу. - - Не вдалося - виконати дію - - Не вдалося - синхронізувати з пристроєм для трансляції - - Не - вдалося завантажити медіа-вміст на пристрій для трансляції - - Не - вдалося знайти нову позицію на пристрої для трансляції - - На - програвачі-приймачі сталася помилка сервера - - - Час очікування авторизації минув - - Не вдалось оновити стиль - субтитрів. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-v11/styles.xml b/CCL/src/main/res/values-v11/styles.xml deleted file mode 100644 index 659c8540e..000000000 --- a/CCL/src/main/res/values-v11/styles.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/values-v21/styles.xml b/CCL/src/main/res/values-v21/styles.xml deleted file mode 100644 index 98b111abc..000000000 --- a/CCL/src/main/res/values-v21/styles.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/values-vi/strings.xml b/CCL/src/main/res/values-vi/strings.xml deleted file mode 100755 index 69f270b1d..000000000 --- a/CCL/src/main/res/values-vi/strings.xml +++ /dev/null @@ -1,97 +0,0 @@ - - Cast Companion - Library - - 1.10 - - Chơi trên... - - Trực tuyến - Hủy - Bật - Tắt - - Thông tin không có sẵn - - OK - Lỗi - Đang truyền - đến %1$s - - Đang tải… - - Không có sẵn thông tin truyền thông - - Đang cố gắng khôi - phục phiên trước đó... - - - Không thể chạy ứng dụng - - Yêu - cầu chạy ứng dụng đã hết thời gian! - - - Ứng dụng mà bạn đang cố gắng chạy không có trên thiết bị Chromecast - - - Không thể bắt đầu phát lại truyền thông - - - Không thể ngừng phát lại truyền thông - - - Không thể tạm dừng phát lại truyền thông - - Đã gặp - phải lỗi không xác định - - - Không thể kết nối với thiết bị - - Không thể đặt âm - lượng - - Hiện không có kết - nối với thiết bị truyền - - Không có kết nối - - - Đã mất kết nối với thiết bị truyền. Ứng dụng đang cố gắng thiết lập lại kết nối, nếu có thể. - Vui lòng đợi vài giây và thử lại. - - Không thể thực - hiện tác vụ - - Không thể đồng bộ với - thiết bị truyền - - - Không thể tải phương tiện truyền thông trên thiết bị truyền - - Không - thể tìm vị trí mới trên thiết bị truyền - - Trình phát của - người nhận đã gặp phải lỗi máy chủ - - - Hết thời gian chờ ủy quyền - - Không thể cập nhật kiểu - Phụ đề. - - \ No newline at end of file diff --git a/CCL/src/main/res/values-zh-rCN/strings.xml b/CCL/src/main/res/values-zh-rCN/strings.xml deleted file mode 100755 index e56b14b19..000000000 --- a/CCL/src/main/res/values-zh-rCN/strings.xml +++ /dev/null @@ -1,87 +0,0 @@ - - Cast Companion - Library - - 1.10 - - 播放设备… - 直播 - 取消 - 开启 - 关闭 - - 未提供信息 - - 确定 - 错误 - 正在投射到 %1$s - - 正在加载… - - 未提供媒体信息 - - 正在尝试恢复之前的会话… - - - 无法启动应用 - - - 启动应用的请求已超时! - - - 您尝试启动的应用在 Chromecast 设备上不受支持 - - - 无法开始播放媒体 - - - 无法停止播放媒体 - - - 无法暂停播放媒体 - - - 遇到未知错误 - - - 无法连接到设备 - - 无法设置音量 - - 投射设备上未显示任何连接 - - 无连接 - - - 与投射设备的连接已断开。应用正在尝试重新建立连接(如果可能)。请等待几秒钟,然后重试。 - - 无法执行操作 - - 无法与投射设备同步 - - - 无法在投射设备上加载媒体 - - - 在投射设备上未能找到新位置 - - 接收端播放器发生错误 - - - 授权已超时 - - 无法更新字幕样式。 - - \ No newline at end of file diff --git a/CCL/src/main/res/values-zh-rHK/strings.xml b/CCL/src/main/res/values-zh-rHK/strings.xml deleted file mode 100755 index eb3a71833..000000000 --- a/CCL/src/main/res/values-zh-rHK/strings.xml +++ /dev/null @@ -1,85 +0,0 @@ - - 投放裝置配對資料庫 - 1.10 - - 繼續遊戲… - 直播 - 取消 - 開啟 - 關閉 - - 無法提供資料 - - 確定 - 錯誤 - 投放到 %1$s - - 正在載入… - - 沒有可用的媒體資料 - - 正在嘗試恢復之前的工作階段… - - - 無法啟動應用程式 - - - 啟動應用程式的要求已過時! - - - 您正嘗試啟動的應用程式無法在 Chromecast 裝置上提供 - - - 無法開始媒體播放 - - - 無法停止媒體播放 - - - 無法暫停媒體播放 - - - 發生不明的錯誤 - - - 無法連接到裝置 - - 無法設定音量 - - 投放裝置沒有連線 - - 沒有連線 - - - 投放裝置的連線已中斷。應用程式正嘗試重新建立連線 (如適用)。請稍候數秒,然後再試一次。 - - 無法執行操作 - - 無法與投放裝置同步 - - - 無法在投放裝置上載入媒體 - - - 無法在投放裝置上找到新位置 - - 接收玩家發生嚴重錯誤 - - - 授權已逾時 - - 無法更新「字幕」樣式。 - - \ No newline at end of file diff --git a/CCL/src/main/res/values-zh-rTW/strings.xml b/CCL/src/main/res/values-zh-rTW/strings.xml deleted file mode 100755 index 04781564c..000000000 --- a/CCL/src/main/res/values-zh-rTW/strings.xml +++ /dev/null @@ -1,87 +0,0 @@ - - Cast Companion - Library - - 1.10 版 - - 繼續播放… - 直播 - 取消 - 開啟 - 關閉 - - 無法提供資訊 - - 確定 - 錯誤 - 投放至「%1$s」 - - 載入中… - - 沒有媒體資訊可提供 - - 正在嘗試復原上一個工作階段… - - - 無法啟動應用程式 - - - 啟動應用程式的請求已逾時! - - - 您要啟動的應用程式無法在您的 Chromecast 裝置上使用 - - - 無法開始播放媒體 - - - 無法停止播放媒體 - - - 無法暫停播放媒體 - - - 發生不明錯誤 - - - 無法與裝置連線 - - 無法設定音量 - - 目前沒有連到投放裝置的連線 - - 沒有連線 - - - 與投放裝置的連線已中斷。應用程式正在嘗試重新建立連線 (如果可能的話),請於幾秒後再試一次。 - - 無法執行動作 - - 無法與投放裝置同步處理 - - - 無法在投放裝置上載入媒體 - - - 無法在投放裝置上找到新位置 - - 接收端播放器發生伺服器錯誤 - - - 授權逾時 - - 無法更新「字幕」樣式。 - - \ No newline at end of file diff --git a/CCL/src/main/res/values-zh/strings.xml b/CCL/src/main/res/values-zh/strings.xml deleted file mode 100755 index e56b14b19..000000000 --- a/CCL/src/main/res/values-zh/strings.xml +++ /dev/null @@ -1,87 +0,0 @@ - - Cast Companion - Library - - 1.10 - - 播放设备… - 直播 - 取消 - 开启 - 关闭 - - 未提供信息 - - 确定 - 错误 - 正在投射到 %1$s - - 正在加载… - - 未提供媒体信息 - - 正在尝试恢复之前的会话… - - - 无法启动应用 - - - 启动应用的请求已超时! - - - 您尝试启动的应用在 Chromecast 设备上不受支持 - - - 无法开始播放媒体 - - - 无法停止播放媒体 - - - 无法暂停播放媒体 - - - 遇到未知错误 - - - 无法连接到设备 - - 无法设置音量 - - 投射设备上未显示任何连接 - - 无连接 - - - 与投射设备的连接已断开。应用正在尝试重新建立连接(如果可能)。请等待几秒钟,然后重试。 - - 无法执行操作 - - 无法与投射设备同步 - - - 无法在投射设备上加载媒体 - - - 在投射设备上未能找到新位置 - - 接收端播放器发生错误 - - - 授权已超时 - - 无法更新字幕样式。 - - \ No newline at end of file diff --git a/CCL/src/main/res/values/arrays.xml b/CCL/src/main/res/values/arrays.xml deleted file mode 100644 index f63d145ef..000000000 --- a/CCL/src/main/res/values/arrays.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - Very Small - Small - Normal - Large - Very Large - - - - San-serif - Serif - Monospace - - - - 25% - 50% - 75% - 100% - - - - None - Outline - Drop Shadow - - - - White - Black - Red - Yellow - Green - Cyan - Blue - Magenta - - - - - 0.5 - 0.75 - 1.0 - 1.5 - 2.0 - - - - FONT_FAMILY_SANS_SERIF - FONT_FAMILY_SERIF - FONT_FAMILY_MONOSPACED_SANS_SERIF - - - - 3F - 80 - BF - FF - - - - EDGE_TYPE_NONE - EDGE_TYPE_OUTLINE - EDGE_TYPE_DROP_SHADOW - - - - #FFFFFF - #000000 - #FF0000 - #FFFF00 - #00FF00 - #00FFFF - #0000FF - #FF00FF - - - \ No newline at end of file diff --git a/CCL/src/main/res/values/captions.xml b/CCL/src/main/res/values/captions.xml deleted file mode 100644 index 76236fcef..000000000 --- a/CCL/src/main/res/values/captions.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - Caption - - Caption Availability - Text Size - Font Family - Text Color - Text Opacity - Edge Type - Edge Color - Background Color - Background Opacity - Enabled - Disabled - - - ccl_caption_enabled - ccl_caption_font_family - ccl_caption_font_scale - ccl_caption_text_color - ccl_caption_text_opacity - ccl_caption_edge_type - ccl_caption_background_color - ccl_caption_font_background_opacity - - - 1.0 - FONT_FAMILY_SERIF - #FFFFFF - FF - EDGE_TYPE_NONE - #000000 - FF - Tracks - - Subtitles - Audio - No Text Tracks Available - No Audio Tracks Available - No tracks available - - \ No newline at end of file diff --git a/CCL/src/main/res/values/colors.xml b/CCL/src/main/res/values/colors.xml deleted file mode 100644 index e96b75bfb..000000000 --- a/CCL/src/main/res/values/colors.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - #000000 - #AA000000 - #33b5e5 - - - #E5FFFFFF - #E5FFFFFF - #E5AAAAAA - #000000 - #FFFFFF - - #4285f4 - #555753 - #03A9F4 - #FFFFFF - #eeff41 - \ No newline at end of file diff --git a/CCL/src/main/res/values/dimens.xml b/CCL/src/main/res/values/dimens.xml deleted file mode 100644 index f5405d2b6..000000000 --- a/CCL/src/main/res/values/dimens.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - 15sp - 13sp - 64dp - 64dp - - - 18sp - 18sp - 75dp - - 300dp - 8dp - diff --git a/CCL/src/main/res/values/mini_controller.xml b/CCL/src/main/res/values/mini_controller.xml deleted file mode 100644 index 0261a673a..000000000 --- a/CCL/src/main/res/values/mini_controller.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/values/strings.xml b/CCL/src/main/res/values/strings.xml deleted file mode 100644 index 854fc7738..000000000 --- a/CCL/src/main/res/values/strings.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - 2.6 - Play on… - Live - Cancel - On - Off - Information Not Available - Pause - Play - Disconnect - None - - - OK - - - Error - - - Casting to %1$s - Loading… - - - No media information available - - - Failed to launch application - The request to launch the application has timed out! - The application you are trying to launch is not available on your Cast device - - - Failed to start the playback of media - Failed to stop the playback of media - Failed to pause the playback of media - - - Could not connect to the device - Failed to set the volume - No connection to the cast device is present - No connection - Connection to the cast device has been lost. Application is trying to re-establish the connection, if possible. Please wait for a few seconds and try again. - Failed to perform the action - Failed to sync up with the cast device - Failed to seek to the new position on the cast device - Receiver player has encountered a severe error - Authorization timed out - Failed to update the captions style. - Up Next - - diff --git a/CCL/src/main/res/values/styles.xml b/CCL/src/main/res/values/styles.xml deleted file mode 100644 index 8a4faca0e..000000000 --- a/CCL/src/main/res/values/styles.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/CCL/src/main/res/xml/caption_preference.xml b/CCL/src/main/res/xml/caption_preference.xml deleted file mode 100644 index 580d5bcfc..000000000 --- a/CCL/src/main/res/xml/caption_preference.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index c7a7108c0..5daee9100 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ Google Santa Tracker for Android [Google Santa Tracker app for Android][play-store] is an educational and entertaining tradition that brings joy to millions of children (and children at heart) across the world over the December holiday period. The app is a companion to the [Google Santa Tracker][santa-web] website ([repository here](https://github.com/google/santa-tracker-web)), showcasing unique platform capabilities like Android Wear watchfaces, device notifications and more. ![Analytics](https://ga-beacon.appspot.com/UA-12846745-20/santa-tracker-android/readme?pixel) -![Village Screenshot](res/village.png) ![Snowdown Screenshot](res/snowdown.png) +Village Screenshot ## Features * A beautiful materially designed village -* 6 exciting games -* 2 interactive Android Wear watchfaces (with sound!) +* Exciting games like Penguin Swim and Rocket Sleigh +* Interactive Android Wear watchfaces (with sound!) * Videos, animations and more. ## Building the app @@ -26,7 +26,7 @@ console, follow these steps: * Package name: `com.google.android.apps.santatracker.debug` * Debug signing certificate can be blank, or follow the instructions in the tooltip to find yours. - * Save the google-services.json file to the santa-tracker/ directory + * Save the `google-services.json` file to the `santa-tracker/` directory Now you should be able to plug your phone in (or fire up an emulator) and run: @@ -34,24 +34,24 @@ Now you should be able to plug your phone in (or fire up an emulator) and run: Alternatively, import the source code into Android Studio (File, Import Project). -Note: You'll need Android SDK version 23, build tools 23.0.1, and the Android Support Library to +Note: You'll need Android SDK version 24, build tools 24.0.0, and the Android Support Library to compile the project. If you're unsure about this, use Android Studio and tick the appropriate boxes in the SDK Manager. ## License -All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav -and *.ogg) are licensed under the CC-BY-NC license. All other files are +All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav +and *.ogg) are licensed under the CC-BY-NC license. All other files are licensed under the Apache 2 license. See the LICENSE file for details. - Copyright 2015 Google Inc. All rights reserved. - + Copyright 2016 Google Inc. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/build.gradle b/build.gradle index 5e5d1ab10..cd509847b 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.2' + classpath 'com.android.tools.build:gradle:2.2.2' classpath 'com.google.gms:google-services:3.0.0' } } @@ -27,8 +27,12 @@ subprojects { } ext { - tools = '23.0.1' - support = '23.4.0' + minSdkVersion = 15 + compileSdkVersion = 24 + targetSdkVersion = 24 + + tools = '24.0.0' + support = '24.2.0' supportV4 = "com.android.support:support-v4:$support" supportAnnotations = "com.android.support:support-annotations:$support" appCompat = "com.android.support:appcompat-v7:$support" @@ -41,26 +45,41 @@ ext { leanback = "com.android.support:leanback-v17:$support" multidex = 'com.android.support:multidex:1.0.0' - play = '9.2.1' + constraintLayout = 'com.android.support.constraint:constraint-layout:1.0.0-beta2' + + play = '9.8.0' playServicesAnalytics = "com.google.android.gms:play-services-analytics:$play" playServicesAppindexing = "com.google.android.gms:play-services-appindexing:$play" playServicesBase = "com.google.android.gms:play-services-base:$play" playServicesBasement = "com.google.android.gms:play-services-basement:$play" - playServicesCast = "com.google.android.gms:play-services-cast:$play" + playServicesCastFramework = "com.google.android.gms:play-services-cast-framework:$play" playServicesGames = "com.google.android.gms:play-services-games:$play" playServicesMaps = "com.google.android.gms:play-services-maps:$play" playServicesNearby = "com.google.android.gms:play-services-nearby:$play" - playServicesPlus = "com.google.android.gms:play-services-plus:$play" playServicesWearable = "com.google.android.gms:play-services-wearable:$play" + playServicesPlaces = "com.google.android.gms:play-services-places:$play" + playServicesLocation = "com.google.android.gms:play-services-location:$play" firebaseCore = "com.google.firebase:firebase-core:$play" firebaseAnalytics = "com.google.firebase:firebase-analytics:$play" firebaseAppinvite = "com.google.firebase:firebase-invites:$play" firebaseConfig = "com.google.firebase:firebase-config:$play" + firebaseCrash = "com.google.firebase:firebase-crash:$play" + firebaseStorage = "com.google.firebase:firebase-storage:$play" androidMapsUtils = 'com.google.maps.android:android-maps-utils:0.4' - seismic = "com.squareup:seismic:1.0.2" - glide = "com.github.bumptech.glide:glide:3.6.1" + leakCanary = 'com.squareup.leakcanary:leakcanary-android:1.5' + leakCanaryNoOp = 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' + + espressoCore = 'com.android.support.test.espresso:espresso-core:2.2.2' + espressoContrib = 'com.android.support.test.espresso:espresso-contrib:2.2.2' + + seismic = 'com.squareup:seismic:1.0.2' + glide = 'com.github.bumptech.glide:glide:3.6.1' + + sugarOrm = 'com.github.satyan:sugar:1.4' + + easypermissions = 'pub.devrel:easypermissions:0.2.1' } diff --git a/common/build.gradle b/common/build.gradle index 757fa6cf2..943eb1112 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 23 + compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.tools defaultConfig { - minSdkVersion 15 - targetSdkVersion 23 + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion } } @@ -14,13 +14,15 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile rootProject.ext.supportV4 + compile rootProject.ext.appCompat compile rootProject.ext.playServicesAnalytics compile rootProject.ext.playServicesBase compile rootProject.ext.playServicesBasement compile rootProject.ext.playServicesGames + compile rootProject.ext.playServicesMaps compile rootProject.ext.firebaseCore compile rootProject.ext.firebaseAnalytics compile rootProject.ext.firebaseAppinvite -} \ No newline at end of file +} diff --git a/common/src/main/AndroidManifest.xml b/common/src/main/AndroidManifest.xml index aaff8795b..fa8d5b8d4 100644 --- a/common/src/main/AndroidManifest.xml +++ b/common/src/main/AndroidManifest.xml @@ -1,3 +1,19 @@ + + diff --git a/santa-tracker/src/main/assets/Lobster-Regular.otf b/common/src/main/assets/Lobster-Regular.otf similarity index 100% rename from santa-tracker/src/main/assets/Lobster-Regular.otf rename to common/src/main/assets/Lobster-Regular.otf diff --git a/common/src/main/java/com/google/android/apps/santatracker/AudioPlayer.java b/common/src/main/java/com/google/android/apps/santatracker/AudioPlayer.java index 8b8609a00..c988cab74 100644 --- a/common/src/main/java/com/google/android/apps/santatracker/AudioPlayer.java +++ b/common/src/main/java/com/google/android/apps/santatracker/AudioPlayer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/src/main/java/com/google/android/apps/santatracker/common/NotificationConstants.java b/common/src/main/java/com/google/android/apps/santatracker/common/NotificationConstants.java index e2f02d079..bfc2823cb 100644 --- a/common/src/main/java/com/google/android/apps/santatracker/common/NotificationConstants.java +++ b/common/src/main/java/com/google/android/apps/santatracker/common/NotificationConstants.java @@ -29,9 +29,6 @@ public final class NotificationConstants { public static final int NOTIFICATION_ID = 9876435; public static final int NOTIFICATION_TAKEOFF = 1; - public static final int NOTIFICATION_NEARBY = 2; //Ex: "Santa is 3 hours away from you." - public static final int NOTIFICATION_LOCATION = 3; //Ex: "Santa is currently over Australia!" - public static final int NOTIFICATION_FACT = 4; // Santa status update or factoid public static final String TAKEOFF_PATH = "/takeoff"; public static final String KEY_NOTIFICATION_ID = "notification-id"; diff --git a/common/src/main/java/com/google/android/apps/santatracker/games/PlayGamesFragment.java b/common/src/main/java/com/google/android/apps/santatracker/games/PlayGamesFragment.java index f4a6081ed..ec38207c0 100644 --- a/common/src/main/java/com/google/android/apps/santatracker/games/PlayGamesFragment.java +++ b/common/src/main/java/com/google/android/apps/santatracker/games/PlayGamesFragment.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/src/main/java/com/google/android/apps/santatracker/games/SignInListener.java b/common/src/main/java/com/google/android/apps/santatracker/games/SignInListener.java index 66093ede0..c546f9517 100644 --- a/common/src/main/java/com/google/android/apps/santatracker/games/SignInListener.java +++ b/common/src/main/java/com/google/android/apps/santatracker/games/SignInListener.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/src/main/java/com/google/android/apps/santatracker/games/SplashActivity.java b/common/src/main/java/com/google/android/apps/santatracker/games/SplashActivity.java new file mode 100644 index 000000000..c09e3e5f7 --- /dev/null +++ b/common/src/main/java/com/google/android/apps/santatracker/games/SplashActivity.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.games; + +import android.app.UiModeManager; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Point; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.view.Display; +import android.view.Surface; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.TextView; + +import com.google.android.apps.santatracker.common.R; +import com.google.android.apps.santatracker.util.FontHelper; +import com.google.android.apps.santatracker.util.ImmersiveModeHelper; + +/** + * Splash screen for games. The splash screen rotates at runtime to match the orientation of the game + * that will be launched. This makes launching the splash screen jank-free from any orientation. + */ +public class SplashActivity extends AppCompatActivity { + + public static final int DELAY_MILLIS = 1000; + + private static final String TAG = "SplashActivity"; + private static final String EXTRA_SPLASH_IMAGE_ID = "extra_splash_image_id"; + private static final String EXTRA_SPLASH_TITLE_ID = "extra_splash_title_id"; + private static final String EXTRA_GAME_CLASS = "extra_game_class"; + private static final String EXTRA_LANDSCAPE = "extra_landscape"; + + private Handler mHandler = new Handler(); + + private Drawable mSplashImage; + private String mSplashTitle; + + /** + * Get an intent to launch a splash screen. + * @param context launching context. + * @param splashImageId resource ID for splash image. + * @param splashTitleId resource ID for splash title. + * @param isLandscape {@code true} if the game target is landscape only. + * @param classToLaunch class of the game to launch. + */ + public static Intent getIntent(Context context, + @DrawableRes int splashImageId, + @StringRes int splashTitleId, + boolean isLandscape, + Class classToLaunch) { + + Intent intent = new Intent(context, SplashActivity.class); + intent.putExtra(EXTRA_SPLASH_IMAGE_ID, splashImageId); + intent.putExtra(EXTRA_SPLASH_TITLE_ID, splashTitleId); + intent.putExtra(EXTRA_LANDSCAPE, isLandscape); + intent.putExtra(EXTRA_GAME_CLASS, classToLaunch); + + return intent; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splash); + + // Immersive mode (to hide nav). + ImmersiveModeHelper.setImmersiveSticky(getWindow()); + + // Get Views + ImageView splashImageView = (ImageView) findViewById(R.id.splash_image); + TextView splashTitleView = (TextView) findViewById(R.id.splash_title); + + // Set Image + mSplashImage = ContextCompat.getDrawable(this, getIntent().getIntExtra(EXTRA_SPLASH_IMAGE_ID, -1)); + if (mSplashImage != null) { + splashImageView.setImageDrawable(mSplashImage); + } + + // Set Title + mSplashTitle = getString(getIntent().getIntExtra(EXTRA_SPLASH_TITLE_ID, -1)); + splashTitleView.setText(mSplashTitle); + + // Make text "Lobster" font + FontHelper.makeLobster(splashTitleView); + + // Start new activity in 1000ms + final Class classToLaunch = (Class) getIntent().getSerializableExtra(EXTRA_GAME_CLASS); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + startActivity(new Intent(SplashActivity.this, classToLaunch)); + finish(); + } + }, DELAY_MILLIS); + } + + @Override + protected void onStart() { + super.onStart(); + + // Orientation + boolean gameIsLandscape = getIntent().getBooleanExtra(EXTRA_LANDSCAPE, false); + boolean isLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + int rotation = display.getRotation(); + + // Figure out how many degrees to rotate + // Landscape always wants to be at 90degrees, portrait always wants to be at 0degrees + float degreesToRotate = 0f; + if (rotation == Surface.ROTATION_0) { + degreesToRotate = gameIsLandscape && !isLandscape? 90.0f : 0.0f; + } else if (rotation == Surface.ROTATION_90) { + degreesToRotate = gameIsLandscape && isLandscape? 0f : -90f; + } else if (rotation == Surface.ROTATION_180) { + degreesToRotate = gameIsLandscape && !isLandscape? -90f : -180f; + } else if (rotation == Surface.ROTATION_270) { + degreesToRotate = gameIsLandscape && isLandscape? -180f : -270f; + } + + // On a TV, should always be 0 + if (isRunningOnTV()) { + degreesToRotate = 0f; + } + + // Rotate, if necessary + if (degreesToRotate != 0) { + Point size = new Point(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + display.getRealSize(size); + } else { + display.getSize(size); + } + int w = size.x; + int h = size.y; + + View mainLayout = findViewById(R.id.splash_layout); + mainLayout.setRotation(degreesToRotate); + mainLayout.setTranslationX((w - h) / 2); + mainLayout.setTranslationY((h - w) / 2); + + ViewGroup.LayoutParams lp = mainLayout.getLayoutParams(); + lp.height = w; + lp.width = h; + + mainLayout.requestLayout(); + } + } + + private boolean isRunningOnTV() { + UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE); + return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION; + } + + @Override + protected void onStop() { + super.onStop(); + mHandler.removeCallbacksAndMessages(null); + } +} diff --git a/common/src/main/java/com/google/android/apps/santatracker/invites/AppInvitesFragment.java b/common/src/main/java/com/google/android/apps/santatracker/invites/AppInvitesFragment.java index 7703edda3..fb78f9c26 100644 --- a/common/src/main/java/com/google/android/apps/santatracker/invites/AppInvitesFragment.java +++ b/common/src/main/java/com/google/android/apps/santatracker/invites/AppInvitesFragment.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package com.google.android.apps.santatracker.invites; +import android.app.Activity; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -44,7 +46,7 @@ public class AppInvitesFragment extends Fragment implements private static final int AUTOMANAGE_ID = 107; private static final int RC_INVITE = 9007; - private static final Uri BASE_URI = Uri.parse("http://google.com/santatracker/android/"); + public static final Uri BASE_URI = Uri.parse("https://google.com/santatracker/android/"); private GoogleApiClient mGoogleApiClient; private FirebaseAnalytics mMeasurement; @@ -127,7 +129,7 @@ public void sendGenericInvite() { MeasurementManager.recordInvitationSent(mMeasurement, "generic", uri.toString()); } - private void sendInvite(String message, Uri uri) { + public void sendInvite(String message, Uri uri) { // If the message is too long, just cut it short and add ellipses. This is something that // only occurs in some translations and we do not have a better mitigation method. The // alternative is an ugly IllegalArgumentException from the builder. @@ -147,8 +149,11 @@ private void sendInvite(String message, Uri uri) { startActivityForResult(inviteIntent, RC_INVITE); } - public void getInvite(final GetInvitationCallback callback, boolean launchDeepLink) { - AppInvite.AppInviteApi.getInvitation(mGoogleApiClient, getActivity(), launchDeepLink) + public void getInvite(final GetInvitationCallback callback, final boolean launchDeepLink) { + // Using "null, false" as arguments here to avoid a known memory leak issue in + // AppInvites. Should be fixed in Google Play services v10.4.0. + final Activity activity = getActivity(); + AppInvite.AppInviteApi.getInvitation(mGoogleApiClient, null, false) .setResultCallback(new ResultCallback() { @Override public void onResult(AppInviteInvitationResult appInviteInvitationResult) { @@ -163,6 +168,16 @@ public void onResult(AppInviteInvitationResult appInviteInvitationResult) { // Record invitation receipt event. MeasurementManager.recordInvitationReceived(mMeasurement, deepLink); + + // Launch the deep link (see above note on why we don't do this + // automatically) + if (launchDeepLink) { + try { + activity.startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "No handler for deep link", e); + } + } } } diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/AnalyticsManager.java b/common/src/main/java/com/google/android/apps/santatracker/util/AnalyticsManager.java index d2198dbbc..b1a6f5dc9 100644 --- a/common/src/main/java/com/google/android/apps/santatracker/util/AnalyticsManager.java +++ b/common/src/main/java/com/google/android/apps/santatracker/util/AnalyticsManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 Google Inc. All rights reserved. + * Copyright 2016 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -139,7 +139,8 @@ public Tracker getTracker() { } public static synchronized void initializeAnalyticsTracker(Context context) { - sAppContext = context; + // To avoid Activity life cycle related memory leaks, assigning the application context + sAppContext = context.getApplicationContext(); if (mTracker == null) { GoogleAnalytics analytics = GoogleAnalytics.getInstance(context); mTracker = analytics.newTracker(R.xml.config_analytics_tracker); diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/FontHelper.java b/common/src/main/java/com/google/android/apps/santatracker/util/FontHelper.java new file mode 100644 index 000000000..ed851289a --- /dev/null +++ b/common/src/main/java/com/google/android/apps/santatracker/util/FontHelper.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.util; + +import android.graphics.Typeface; +import android.os.Build; +import android.widget.TextView; + +/** + * Helper to apply the "Santa" font to text + */ +public class FontHelper { + + private static Typeface sTypeface; + + public static void makeLobster(TextView textView) { + makeLobster(textView, true); + } + + public static void makeLobster(TextView textView, boolean italic) { + if (sTypeface == null) { + sTypeface = Typeface.createFromAsset(textView.getContext().getAssets(), + "Lobster-Regular.otf"); + } + + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { + textView.setTypeface(sTypeface); + } else if (italic) { + textView.setTypeface(sTypeface, Typeface.ITALIC); + } else { + textView.setTypeface(sTypeface, Typeface.NORMAL); + } + } + +} diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/ImmersiveModeHelper.java b/common/src/main/java/com/google/android/apps/santatracker/util/ImmersiveModeHelper.java index aa4ba29ca..34f6ff240 100644 --- a/common/src/main/java/com/google/android/apps/santatracker/util/ImmersiveModeHelper.java +++ b/common/src/main/java/com/google/android/apps/santatracker/util/ImmersiveModeHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/MapHelper.java b/common/src/main/java/com/google/android/apps/santatracker/util/MapHelper.java new file mode 100644 index 000000000..3408ac9c5 --- /dev/null +++ b/common/src/main/java/com/google/android/apps/santatracker/util/MapHelper.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.util; + +import android.util.Log; + +import com.google.android.gms.maps.SupportMapFragment; + +public class MapHelper { + + private static final String TAG = MapHelper.class.getSimpleName(); + + /** + * Calculate a valid padding for a map's markers. Using hard coded padding can be problematic + * when device is small, so using a padding based on the size of the map view would improve results. + * + * @param supportMapFragment The map used to determine padding. + * @return A valid padding. + */ + public static int getMapPadding(SupportMapFragment supportMapFragment) { + int height = supportMapFragment.getView().getHeight(); + int width = supportMapFragment.getView().getWidth(); + double factor = 0.3; + double padding = height < width ? height * factor : width * factor; + Log.d(TAG, "padding used: " + padding); + return (int) padding; + } + +} diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/MeasurementManager.java b/common/src/main/java/com/google/android/apps/santatracker/util/MeasurementManager.java index 2e37a3928..10ea01ace 100644 --- a/common/src/main/java/com/google/android/apps/santatracker/util/MeasurementManager.java +++ b/common/src/main/java/com/google/android/apps/santatracker/util/MeasurementManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,20 @@ package com.google.android.apps.santatracker.util; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; +import com.google.android.apps.santatracker.common.BuildConfig; import com.google.firebase.analytics.FirebaseAnalytics; +import java.util.Locale; + /** Handles communication with Firebase Analytics. */ public class MeasurementManager { @@ -31,6 +38,36 @@ public class MeasurementManager { private static final String GAME_TITLE = "game_title"; private static final String TYPE_SCREEN = "type_screen"; + /** User properties **/ + private static final String BUILD_DEBUG = "BUILD_DEBUG"; + private static final String BUILD_VERSION_NAME = "BUILD_VERSION_NAME"; + private static final String DEVICE_BOARD = "DEVICE_BOARD"; + private static final String DEVICE_BRAND = "DEVICE_BRAND"; + private static final String DEVICE_LOCALE = "DEVICE_LOCALE"; + private static final String API_LEVEL = "API_LEVEL"; + + public static void recordDeviceProperties(Context context) { + FirebaseAnalytics analytics = FirebaseAnalytics.getInstance( + context.getApplicationContext()); + + // Set some user properties based on the device, this can be used for Analytics or + // for Remote Config + analytics.setUserProperty(BUILD_DEBUG, String.valueOf(BuildConfig.DEBUG)); + analytics.setUserProperty(DEVICE_BOARD, Build.BOARD); + analytics.setUserProperty(DEVICE_BRAND, Build.BRAND); + analytics.setUserProperty(DEVICE_LOCALE, Locale.getDefault().getLanguage()); + analytics.setUserProperty(API_LEVEL, String.valueOf(Build.VERSION.SDK_INT)); + + try { + // Set version name, if we can get it + PackageManager pm = context.getPackageManager(); + PackageInfo info = pm.getPackageInfo(context.getPackageName(), 0); + analytics.setUserProperty(BUILD_VERSION_NAME, info.versionName); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Could not get package info", e); + } + } + public static void recordCustomEvent(FirebaseAnalytics measurement, @NonNull String name, @NonNull String action, @@ -118,4 +155,137 @@ public static void recordGameScore(FirebaseAnalytics measurement, measurement.logEvent(FirebaseAnalytics.Event.POST_SCORE, params); } + public static void recordVillageTabClick(FirebaseAnalytics measurement, + @NonNull String tabName) { + Log.d(TAG, "recordVillageTabClick:" + tabName); + + Bundle params = new Bundle(); + params.putString("tab_name", tabName); + + measurement.logEvent("village_tab_clicked", params); + } + + public static void recordVillageSantaClick(FirebaseAnalytics measurement) { + Log.d(TAG, "recordVillageSantaClick"); + measurement.logEvent("village_santa_clicked", new Bundle()); + } + + public static void recordSwimmingEnd(FirebaseAnalytics measurement, + int numStars, + int score, + @NonNull String end_reason) { + Log.d(TAG, "recordSwimmingEnd:" + numStars + ":" + score + ":" + end_reason); + + Bundle params = new Bundle(); + params.putInt("num_stars", numStars); + params.putInt("score", score); + params.putString("end_reason", end_reason); + + // Log custom swimming event + measurement.logEvent("swimming_game_end", params); + + // Log generic game score event + recordGameScore(measurement, (long) score, null, "swimming"); + } + + public static void recordRunningEnd(FirebaseAnalytics measurement, + int numStars, + int score) { + Log.d(TAG, "recordRunningEnd:" + numStars + ":" + score); + + Bundle params = new Bundle(); + params.putInt("num_stars", numStars); + params.putInt("score", score); + + // Log custom swimming event + measurement.logEvent("running_game_end", params); + + // Log generic game score event + recordGameScore(measurement, (long) score, null, "running"); + } + + public static void recordPresentDropped(FirebaseAnalytics analytics, + boolean isLarge) { + Log.d(TAG, "recordPresentDropped:" + isLarge); + + Bundle params = new Bundle(); + if (isLarge) { + params.putString("size", "large"); + } else { + params.putString("size", "small"); + } + + analytics.logEvent("pq_present_dropped", params); + } + + public static void recordPresentsCollected(FirebaseAnalytics analytics, + int numPresents) { + Log.d(TAG, "recordPresentsCollected:" + numPresents); + + Bundle params = new Bundle(); + params.putInt("num_presents", numPresents); + + analytics.logEvent("pq_presents_collected", params); + } + + public static void recordPresentsReturned(FirebaseAnalytics analytics, + int numPresents) { + Log.d(TAG, "recordPresentsReturned:" + numPresents); + + Bundle params = new Bundle(); + params.putInt("num_presents", numPresents); + + analytics.logEvent("pq_presents_returned", params); + } + + public static void recordPresentQuestLevel(FirebaseAnalytics analytics, + int level) { + Log.d(TAG, "recordPresentQuestLevel:" + level); + + Bundle params = new Bundle(); + params.putInt("level", level); + + // Log custom event + analytics.logEvent("pq_level_unlocked", params); + + // Log standard LEVEL_UP event + Bundle params2 = new Bundle(); + params2.putLong(FirebaseAnalytics.Param.LEVEL, (long) level); + analytics.logEvent(FirebaseAnalytics.Event.LEVEL_UP, params2); + } + + public static void recordWorkshopMoved(FirebaseAnalytics analytics) { + Log.d(TAG, "recordWorkshopMoved"); + + analytics.logEvent("pq_workshop_moved", new Bundle()); + } + + public static void recordHundredMetersWalked(FirebaseAnalytics analytics) { + Log.d(TAG, "recordHundredMetersWalked"); + + analytics.logEvent("pq_hundred_meters_walked", new Bundle()); + } + + public static void recordCorrectCitySelected(FirebaseAnalytics analytics, + @NonNull String cityId, + int numIncorrectAttempts) { + Log.d(TAG, "recordCorrectCitySelected:" + cityId + ":" + numIncorrectAttempts); + + Bundle params = new Bundle(); + params.putString("city_id", cityId); + params.putInt("incorrect_attempts", numIncorrectAttempts); + + analytics.logEvent("cq_select_correct", params); + } + + public static void recordIncorrectCitySelected(FirebaseAnalytics analytics, + @NonNull String cityId) { + Log.d(TAG, "recordIncorrectCitySelected:" + cityId); + + Bundle params = new Bundle(); + params.putString("city_id", cityId); + + analytics.logEvent("cq_select_incorrect", params); + } + } diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/NetworkHelper.java b/common/src/main/java/com/google/android/apps/santatracker/util/NetworkHelper.java new file mode 100644 index 000000000..954e6eb8d --- /dev/null +++ b/common/src/main/java/com/google/android/apps/santatracker/util/NetworkHelper.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.util; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * Utility class to check network state. + */ +public class NetworkHelper { + + public static boolean hasNetwork(Context context) { + ConnectivityManager cm = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + + NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); + return activeNetwork != null && activeNetwork.isConnectedOrConnecting(); + } + +} diff --git a/common/src/main/res/drawable-hdpi/btn_pause_purple.png b/common/src/main/res/drawable-hdpi/btn_pause_purple.png new file mode 100644 index 000000000..105b8564a Binary files /dev/null and b/common/src/main/res/drawable-hdpi/btn_pause_purple.png differ diff --git a/common/src/main/res/drawable-hdpi/btn_play_yellow.png b/common/src/main/res/drawable-hdpi/btn_play_yellow.png new file mode 100644 index 000000000..064eb5588 Binary files /dev/null and b/common/src/main/res/drawable-hdpi/btn_play_yellow.png differ diff --git a/common/src/main/res/drawable-hdpi/common_btn_close.png b/common/src/main/res/drawable-hdpi/common_btn_close.png new file mode 100644 index 000000000..a0b76e74c Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_close.png differ diff --git a/common/src/main/res/drawable-hdpi/common_btn_edit.png b/common/src/main/res/drawable-hdpi/common_btn_edit.png new file mode 100644 index 000000000..6ba43ba1b Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_edit.png differ diff --git a/common/src/main/res/drawable-hdpi/common_btn_pause.png b/common/src/main/res/drawable-hdpi/common_btn_pause.png new file mode 100644 index 000000000..105b8564a Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_pause.png differ diff --git a/common/src/main/res/drawable-hdpi/common_btn_play.png b/common/src/main/res/drawable-hdpi/common_btn_play.png new file mode 100644 index 000000000..064eb5588 Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_play.png differ diff --git a/common/src/main/res/drawable-hdpi/common_btn_save.png b/common/src/main/res/drawable-hdpi/common_btn_save.png new file mode 100644 index 000000000..7c1d0594f Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_save.png differ diff --git a/common/src/main/res/drawable-hdpi/common_btn_share.png b/common/src/main/res/drawable-hdpi/common_btn_share.png new file mode 100644 index 000000000..431b96e0a Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_share.png differ diff --git a/common/src/main/res/drawable-hdpi/common_btn_speaker_off.png b/common/src/main/res/drawable-hdpi/common_btn_speaker_off.png new file mode 100644 index 000000000..4fe6eb6ad Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_speaker_off.png differ diff --git a/common/src/main/res/drawable-hdpi/common_btn_speaker_on.png b/common/src/main/res/drawable-hdpi/common_btn_speaker_on.png new file mode 100644 index 000000000..c267ec2e8 Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_speaker_on.png differ diff --git a/common/src/main/res/drawable-hdpi/games_share.png b/common/src/main/res/drawable-hdpi/games_share.png index 1c693a867..039333e99 100644 Binary files a/common/src/main/res/drawable-hdpi/games_share.png and b/common/src/main/res/drawable-hdpi/games_share.png differ diff --git a/common/src/main/res/drawable-hdpi/games_share_pressed.png b/common/src/main/res/drawable-hdpi/games_share_pressed.png index d96b26981..a29c497bb 100644 Binary files a/common/src/main/res/drawable-hdpi/games_share_pressed.png and b/common/src/main/res/drawable-hdpi/games_share_pressed.png differ diff --git a/common/src/main/res/drawable-hdpi/icon_check.png b/common/src/main/res/drawable-hdpi/icon_check.png new file mode 100644 index 000000000..03cf81f7a Binary files /dev/null and b/common/src/main/res/drawable-hdpi/icon_check.png differ diff --git a/common/src/main/res/drawable-hdpi/icon_close.png b/common/src/main/res/drawable-hdpi/icon_close.png new file mode 100644 index 000000000..20081783b Binary files /dev/null and b/common/src/main/res/drawable-hdpi/icon_close.png differ diff --git a/common/src/main/res/drawable-hdpi/icon_edit.png b/common/src/main/res/drawable-hdpi/icon_edit.png new file mode 100644 index 000000000..05d07b175 Binary files /dev/null and b/common/src/main/res/drawable-hdpi/icon_edit.png differ diff --git a/common/src/main/res/drawable-hdpi/icon_pause.png b/common/src/main/res/drawable-hdpi/icon_pause.png new file mode 100644 index 000000000..8b0d2ca30 Binary files /dev/null and b/common/src/main/res/drawable-hdpi/icon_pause.png differ diff --git a/common/src/main/res/drawable-hdpi/icon_play.png b/common/src/main/res/drawable-hdpi/icon_play.png new file mode 100644 index 000000000..43693e3b6 Binary files /dev/null and b/common/src/main/res/drawable-hdpi/icon_play.png differ diff --git a/common/src/main/res/drawable-hdpi/icon_play_again.png b/common/src/main/res/drawable-hdpi/icon_play_again.png new file mode 100644 index 000000000..8f7ac0b38 Binary files /dev/null and b/common/src/main/res/drawable-hdpi/icon_play_again.png differ diff --git a/common/src/main/res/drawable-hdpi/icon_speaker_off.png b/common/src/main/res/drawable-hdpi/icon_speaker_off.png new file mode 100644 index 000000000..1b6248b35 Binary files /dev/null and b/common/src/main/res/drawable-hdpi/icon_speaker_off.png differ diff --git a/common/src/main/res/drawable-hdpi/icon_speaker_on.png b/common/src/main/res/drawable-hdpi/icon_speaker_on.png new file mode 100644 index 000000000..4300b0213 Binary files /dev/null and b/common/src/main/res/drawable-hdpi/icon_speaker_on.png differ diff --git a/common/src/main/res/drawable-hdpi/signin.9.png b/common/src/main/res/drawable-hdpi/signin.9.png index 3ed145a26..3a9363dac 100644 Binary files a/common/src/main/res/drawable-hdpi/signin.9.png and b/common/src/main/res/drawable-hdpi/signin.9.png differ diff --git a/common/src/main/res/drawable-hdpi/signin_pressed.9.png b/common/src/main/res/drawable-hdpi/signin_pressed.9.png index c98185ccf..3b0270bc0 100644 Binary files a/common/src/main/res/drawable-hdpi/signin_pressed.9.png and b/common/src/main/res/drawable-hdpi/signin_pressed.9.png differ diff --git a/common/src/main/res/drawable-hdpi/winner.png b/common/src/main/res/drawable-hdpi/winner.png new file mode 100644 index 000000000..55580828d Binary files /dev/null and b/common/src/main/res/drawable-hdpi/winner.png differ diff --git a/common/src/main/res/drawable-mdpi/btn_pause_purple.png b/common/src/main/res/drawable-mdpi/btn_pause_purple.png new file mode 100644 index 000000000..47e4529bf Binary files /dev/null and b/common/src/main/res/drawable-mdpi/btn_pause_purple.png differ diff --git a/common/src/main/res/drawable-mdpi/btn_play_yellow.png b/common/src/main/res/drawable-mdpi/btn_play_yellow.png new file mode 100644 index 000000000..63c10e15f Binary files /dev/null and b/common/src/main/res/drawable-mdpi/btn_play_yellow.png differ diff --git a/common/src/main/res/drawable-mdpi/common_btn_close.png b/common/src/main/res/drawable-mdpi/common_btn_close.png new file mode 100644 index 000000000..1639c2bd0 Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_close.png differ diff --git a/common/src/main/res/drawable-mdpi/common_btn_edit.png b/common/src/main/res/drawable-mdpi/common_btn_edit.png new file mode 100644 index 000000000..743822eaf Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_edit.png differ diff --git a/common/src/main/res/drawable-mdpi/common_btn_pause.png b/common/src/main/res/drawable-mdpi/common_btn_pause.png new file mode 100644 index 000000000..47e4529bf Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_pause.png differ diff --git a/common/src/main/res/drawable-mdpi/common_btn_play.png b/common/src/main/res/drawable-mdpi/common_btn_play.png new file mode 100644 index 000000000..63c10e15f Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_play.png differ diff --git a/common/src/main/res/drawable-mdpi/common_btn_save.png b/common/src/main/res/drawable-mdpi/common_btn_save.png new file mode 100644 index 000000000..16311a666 Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_save.png differ diff --git a/common/src/main/res/drawable-mdpi/common_btn_share.png b/common/src/main/res/drawable-mdpi/common_btn_share.png new file mode 100644 index 000000000..c3b9b5095 Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_share.png differ diff --git a/common/src/main/res/drawable-mdpi/common_btn_speaker_off.png b/common/src/main/res/drawable-mdpi/common_btn_speaker_off.png new file mode 100644 index 000000000..e2697abc5 Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_speaker_off.png differ diff --git a/common/src/main/res/drawable-mdpi/common_btn_speaker_on.png b/common/src/main/res/drawable-mdpi/common_btn_speaker_on.png new file mode 100644 index 000000000..3544e14ed Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_speaker_on.png differ diff --git a/common/src/main/res/drawable-mdpi/games_share.png b/common/src/main/res/drawable-mdpi/games_share.png index f6b58b926..288d09b20 100644 Binary files a/common/src/main/res/drawable-mdpi/games_share.png and b/common/src/main/res/drawable-mdpi/games_share.png differ diff --git a/common/src/main/res/drawable-mdpi/games_share_pressed.png b/common/src/main/res/drawable-mdpi/games_share_pressed.png index 218c73df6..7bbf75abf 100644 Binary files a/common/src/main/res/drawable-mdpi/games_share_pressed.png and b/common/src/main/res/drawable-mdpi/games_share_pressed.png differ diff --git a/common/src/main/res/drawable-mdpi/icon_check.png b/common/src/main/res/drawable-mdpi/icon_check.png new file mode 100644 index 000000000..aeb664f41 Binary files /dev/null and b/common/src/main/res/drawable-mdpi/icon_check.png differ diff --git a/common/src/main/res/drawable-mdpi/icon_close.png b/common/src/main/res/drawable-mdpi/icon_close.png new file mode 100644 index 000000000..7820dbb84 Binary files /dev/null and b/common/src/main/res/drawable-mdpi/icon_close.png differ diff --git a/common/src/main/res/drawable-mdpi/icon_edit.png b/common/src/main/res/drawable-mdpi/icon_edit.png new file mode 100644 index 000000000..031ff5eea Binary files /dev/null and b/common/src/main/res/drawable-mdpi/icon_edit.png differ diff --git a/common/src/main/res/drawable-mdpi/icon_pause.png b/common/src/main/res/drawable-mdpi/icon_pause.png new file mode 100644 index 000000000..9d3e05847 Binary files /dev/null and b/common/src/main/res/drawable-mdpi/icon_pause.png differ diff --git a/common/src/main/res/drawable-mdpi/icon_play.png b/common/src/main/res/drawable-mdpi/icon_play.png new file mode 100644 index 000000000..97fb8b5fb Binary files /dev/null and b/common/src/main/res/drawable-mdpi/icon_play.png differ diff --git a/common/src/main/res/drawable-mdpi/icon_play_again.png b/common/src/main/res/drawable-mdpi/icon_play_again.png new file mode 100644 index 000000000..41a045029 Binary files /dev/null and b/common/src/main/res/drawable-mdpi/icon_play_again.png differ diff --git a/common/src/main/res/drawable-mdpi/icon_speaker_off.png b/common/src/main/res/drawable-mdpi/icon_speaker_off.png new file mode 100644 index 000000000..e3fe3f88a Binary files /dev/null and b/common/src/main/res/drawable-mdpi/icon_speaker_off.png differ diff --git a/common/src/main/res/drawable-mdpi/icon_speaker_on.png b/common/src/main/res/drawable-mdpi/icon_speaker_on.png new file mode 100644 index 000000000..e46adc348 Binary files /dev/null and b/common/src/main/res/drawable-mdpi/icon_speaker_on.png differ diff --git a/common/src/main/res/drawable-mdpi/signin.9.png b/common/src/main/res/drawable-mdpi/signin.9.png index a27c66fc7..d49906be4 100644 Binary files a/common/src/main/res/drawable-mdpi/signin.9.png and b/common/src/main/res/drawable-mdpi/signin.9.png differ diff --git a/common/src/main/res/drawable-mdpi/signin_pressed.9.png b/common/src/main/res/drawable-mdpi/signin_pressed.9.png index fe7cc979d..9371a1223 100644 Binary files a/common/src/main/res/drawable-mdpi/signin_pressed.9.png and b/common/src/main/res/drawable-mdpi/signin_pressed.9.png differ diff --git a/common/src/main/res/drawable-mdpi/winner.png b/common/src/main/res/drawable-mdpi/winner.png new file mode 100644 index 000000000..716591aaa Binary files /dev/null and b/common/src/main/res/drawable-mdpi/winner.png differ diff --git a/common/src/main/res/drawable-nodpi/icon_ribbon.png b/common/src/main/res/drawable-nodpi/icon_ribbon.png new file mode 100644 index 000000000..d80f35f8f Binary files /dev/null and b/common/src/main/res/drawable-nodpi/icon_ribbon.png differ diff --git a/common/src/main/res/drawable-nodpi/icon_ribbon_upsidedown.png b/common/src/main/res/drawable-nodpi/icon_ribbon_upsidedown.png new file mode 100644 index 000000000..5f11fc576 Binary files /dev/null and b/common/src/main/res/drawable-nodpi/icon_ribbon_upsidedown.png differ diff --git a/common/src/main/res/drawable-nodpi/icon_ribbon_upsidedown_short.png b/common/src/main/res/drawable-nodpi/icon_ribbon_upsidedown_short.png new file mode 100644 index 000000000..df7db13d2 Binary files /dev/null and b/common/src/main/res/drawable-nodpi/icon_ribbon_upsidedown_short.png differ diff --git a/common/src/main/res/drawable-nodpi/jetpack_background_day.png b/common/src/main/res/drawable-nodpi/jetpack_background_day.png new file mode 100644 index 000000000..d70876250 Binary files /dev/null and b/common/src/main/res/drawable-nodpi/jetpack_background_day.png differ diff --git a/common/src/main/res/drawable-nodpi/jetpack_background_evening.png b/common/src/main/res/drawable-nodpi/jetpack_background_evening.png new file mode 100644 index 000000000..14773e7d2 Binary files /dev/null and b/common/src/main/res/drawable-nodpi/jetpack_background_evening.png differ diff --git a/common/src/main/res/drawable-nodpi/purple_rectangle_button.png b/common/src/main/res/drawable-nodpi/purple_rectangle_button.png new file mode 100644 index 000000000..3cc1962c5 Binary files /dev/null and b/common/src/main/res/drawable-nodpi/purple_rectangle_button.png differ diff --git a/common/src/main/res/drawable-nodpi/purple_rectangle_pressed_button.png b/common/src/main/res/drawable-nodpi/purple_rectangle_pressed_button.png new file mode 100644 index 000000000..fa93739a7 Binary files /dev/null and b/common/src/main/res/drawable-nodpi/purple_rectangle_pressed_button.png differ diff --git a/common/src/main/res/drawable-sw600dp-hdpi/games_share.png b/common/src/main/res/drawable-sw600dp-hdpi/games_share.png index bf333cc96..e7e56be33 100644 Binary files a/common/src/main/res/drawable-sw600dp-hdpi/games_share.png and b/common/src/main/res/drawable-sw600dp-hdpi/games_share.png differ diff --git a/common/src/main/res/drawable-sw600dp-mdpi/games_share.png b/common/src/main/res/drawable-sw600dp-mdpi/games_share.png index 76942ac3e..c67eb993f 100644 Binary files a/common/src/main/res/drawable-sw600dp-mdpi/games_share.png and b/common/src/main/res/drawable-sw600dp-mdpi/games_share.png differ diff --git a/common/src/main/res/drawable-sw600dp-tvdpi/games_share.png b/common/src/main/res/drawable-sw600dp-tvdpi/games_share.png index 76942ac3e..c67eb993f 100644 Binary files a/common/src/main/res/drawable-sw600dp-tvdpi/games_share.png and b/common/src/main/res/drawable-sw600dp-tvdpi/games_share.png differ diff --git a/common/src/main/res/drawable-xhdpi/btn_pause_purple.png b/common/src/main/res/drawable-xhdpi/btn_pause_purple.png new file mode 100644 index 000000000..8c297f26b Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/btn_pause_purple.png differ diff --git a/common/src/main/res/drawable-xhdpi/btn_play_yellow.png b/common/src/main/res/drawable-xhdpi/btn_play_yellow.png new file mode 100644 index 000000000..cb30da1cd Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/btn_play_yellow.png differ diff --git a/common/src/main/res/drawable-xhdpi/common_btn_close.png b/common/src/main/res/drawable-xhdpi/common_btn_close.png new file mode 100644 index 000000000..d40163110 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_close.png differ diff --git a/common/src/main/res/drawable-xhdpi/common_btn_edit.png b/common/src/main/res/drawable-xhdpi/common_btn_edit.png new file mode 100644 index 000000000..2ba8e0f3f Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_edit.png differ diff --git a/common/src/main/res/drawable-xhdpi/common_btn_pause.png b/common/src/main/res/drawable-xhdpi/common_btn_pause.png new file mode 100644 index 000000000..8c297f26b Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_pause.png differ diff --git a/common/src/main/res/drawable-xhdpi/common_btn_play.png b/common/src/main/res/drawable-xhdpi/common_btn_play.png new file mode 100644 index 000000000..cb30da1cd Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_play.png differ diff --git a/common/src/main/res/drawable-xhdpi/common_btn_save.png b/common/src/main/res/drawable-xhdpi/common_btn_save.png new file mode 100644 index 000000000..97e263881 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_save.png differ diff --git a/common/src/main/res/drawable-xhdpi/common_btn_share.png b/common/src/main/res/drawable-xhdpi/common_btn_share.png new file mode 100644 index 000000000..a87025786 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_share.png differ diff --git a/common/src/main/res/drawable-xhdpi/common_btn_speaker_off.png b/common/src/main/res/drawable-xhdpi/common_btn_speaker_off.png new file mode 100644 index 000000000..8642546b3 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_speaker_off.png differ diff --git a/common/src/main/res/drawable-xhdpi/common_btn_speaker_on.png b/common/src/main/res/drawable-xhdpi/common_btn_speaker_on.png new file mode 100644 index 000000000..982a39f2f Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_speaker_on.png differ diff --git a/common/src/main/res/drawable-xhdpi/games_share.png b/common/src/main/res/drawable-xhdpi/games_share.png index 76942ac3e..33572337f 100644 Binary files a/common/src/main/res/drawable-xhdpi/games_share.png and b/common/src/main/res/drawable-xhdpi/games_share.png differ diff --git a/common/src/main/res/drawable-xhdpi/games_share_pressed.png b/common/src/main/res/drawable-xhdpi/games_share_pressed.png index bd2353d7c..84dede046 100644 Binary files a/common/src/main/res/drawable-xhdpi/games_share_pressed.png and b/common/src/main/res/drawable-xhdpi/games_share_pressed.png differ diff --git a/common/src/main/res/drawable-xhdpi/icon_check.png b/common/src/main/res/drawable-xhdpi/icon_check.png new file mode 100644 index 000000000..e5c764875 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/icon_check.png differ diff --git a/common/src/main/res/drawable-xhdpi/icon_close.png b/common/src/main/res/drawable-xhdpi/icon_close.png new file mode 100644 index 000000000..f215dc37f Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/icon_close.png differ diff --git a/common/src/main/res/drawable-xhdpi/icon_edit.png b/common/src/main/res/drawable-xhdpi/icon_edit.png new file mode 100644 index 000000000..6555e4b80 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/icon_edit.png differ diff --git a/common/src/main/res/drawable-xhdpi/icon_pause.png b/common/src/main/res/drawable-xhdpi/icon_pause.png new file mode 100644 index 000000000..8d1dff589 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/icon_pause.png differ diff --git a/common/src/main/res/drawable-xhdpi/icon_play.png b/common/src/main/res/drawable-xhdpi/icon_play.png new file mode 100644 index 000000000..46ac38ba3 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/icon_play.png differ diff --git a/common/src/main/res/drawable-xhdpi/icon_play_again.png b/common/src/main/res/drawable-xhdpi/icon_play_again.png new file mode 100644 index 000000000..d84001e7e Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/icon_play_again.png differ diff --git a/common/src/main/res/drawable-xhdpi/icon_speaker_off.png b/common/src/main/res/drawable-xhdpi/icon_speaker_off.png new file mode 100644 index 000000000..4c65966a9 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/icon_speaker_off.png differ diff --git a/common/src/main/res/drawable-xhdpi/icon_speaker_on.png b/common/src/main/res/drawable-xhdpi/icon_speaker_on.png new file mode 100644 index 000000000..ece7198ed Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/icon_speaker_on.png differ diff --git a/common/src/main/res/drawable-xhdpi/signin.9.png b/common/src/main/res/drawable-xhdpi/signin.9.png index 09c9991ed..8c042ef79 100644 Binary files a/common/src/main/res/drawable-xhdpi/signin.9.png and b/common/src/main/res/drawable-xhdpi/signin.9.png differ diff --git a/common/src/main/res/drawable-xhdpi/signin_pressed.9.png b/common/src/main/res/drawable-xhdpi/signin_pressed.9.png index 2e61874ce..1511f520b 100644 Binary files a/common/src/main/res/drawable-xhdpi/signin_pressed.9.png and b/common/src/main/res/drawable-xhdpi/signin_pressed.9.png differ diff --git a/common/src/main/res/drawable-xhdpi/winner.png b/common/src/main/res/drawable-xhdpi/winner.png new file mode 100644 index 000000000..4c7e1e9d3 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/winner.png differ diff --git a/common/src/main/res/drawable-xxhdpi/btn_pause_purple.png b/common/src/main/res/drawable-xxhdpi/btn_pause_purple.png new file mode 100644 index 000000000..b20683bfa Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/btn_pause_purple.png differ diff --git a/common/src/main/res/drawable-xxhdpi/btn_play_yellow.png b/common/src/main/res/drawable-xxhdpi/btn_play_yellow.png new file mode 100644 index 000000000..658bc1b9b Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/btn_play_yellow.png differ diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_close.png b/common/src/main/res/drawable-xxhdpi/common_btn_close.png new file mode 100644 index 000000000..188a9cedb Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_close.png differ diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_edit.png b/common/src/main/res/drawable-xxhdpi/common_btn_edit.png new file mode 100644 index 000000000..eca9f1ffa Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_edit.png differ diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_pause.png b/common/src/main/res/drawable-xxhdpi/common_btn_pause.png new file mode 100644 index 000000000..b20683bfa Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_pause.png differ diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_play.png b/common/src/main/res/drawable-xxhdpi/common_btn_play.png new file mode 100644 index 000000000..658bc1b9b Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_play.png differ diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_save.png b/common/src/main/res/drawable-xxhdpi/common_btn_save.png new file mode 100644 index 000000000..7b0e15ea9 Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_save.png differ diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_share.png b/common/src/main/res/drawable-xxhdpi/common_btn_share.png new file mode 100644 index 000000000..8a0564a01 Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_share.png differ diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_speaker_off.png b/common/src/main/res/drawable-xxhdpi/common_btn_speaker_off.png new file mode 100644 index 000000000..958d055e9 Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_speaker_off.png differ diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_speaker_on.png b/common/src/main/res/drawable-xxhdpi/common_btn_speaker_on.png new file mode 100644 index 000000000..596bb60f3 Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_speaker_on.png differ diff --git a/common/src/main/res/drawable-xxhdpi/games_share.png b/common/src/main/res/drawable-xxhdpi/games_share.png index bf333cc96..e7e56be33 100644 Binary files a/common/src/main/res/drawable-xxhdpi/games_share.png and b/common/src/main/res/drawable-xxhdpi/games_share.png differ diff --git a/common/src/main/res/drawable-xxhdpi/games_share_pressed.png b/common/src/main/res/drawable-xxhdpi/games_share_pressed.png index 363a2eb99..a0bde7735 100644 Binary files a/common/src/main/res/drawable-xxhdpi/games_share_pressed.png and b/common/src/main/res/drawable-xxhdpi/games_share_pressed.png differ diff --git a/common/src/main/res/drawable-xxhdpi/icon_check.png b/common/src/main/res/drawable-xxhdpi/icon_check.png new file mode 100644 index 000000000..317c3030e Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/icon_check.png differ diff --git a/common/src/main/res/drawable-xxhdpi/icon_close.png b/common/src/main/res/drawable-xxhdpi/icon_close.png new file mode 100644 index 000000000..9b2953798 Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/icon_close.png differ diff --git a/common/src/main/res/drawable-xxhdpi/icon_edit.png b/common/src/main/res/drawable-xxhdpi/icon_edit.png new file mode 100644 index 000000000..c5175d3ac Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/icon_edit.png differ diff --git a/common/src/main/res/drawable-xxhdpi/icon_pause.png b/common/src/main/res/drawable-xxhdpi/icon_pause.png new file mode 100644 index 000000000..bb1f2649d Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/icon_pause.png differ diff --git a/common/src/main/res/drawable-xxhdpi/icon_play.png b/common/src/main/res/drawable-xxhdpi/icon_play.png new file mode 100644 index 000000000..637d191ac Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/icon_play.png differ diff --git a/common/src/main/res/drawable-xxhdpi/icon_play_again.png b/common/src/main/res/drawable-xxhdpi/icon_play_again.png new file mode 100644 index 000000000..8406a56a6 Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/icon_play_again.png differ diff --git a/common/src/main/res/drawable-xxhdpi/icon_speaker_off.png b/common/src/main/res/drawable-xxhdpi/icon_speaker_off.png new file mode 100644 index 000000000..8d6877325 Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/icon_speaker_off.png differ diff --git a/common/src/main/res/drawable-xxhdpi/icon_speaker_on.png b/common/src/main/res/drawable-xxhdpi/icon_speaker_on.png new file mode 100644 index 000000000..98fae7465 Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/icon_speaker_on.png differ diff --git a/common/src/main/res/drawable-xxhdpi/signin.9.png b/common/src/main/res/drawable-xxhdpi/signin.9.png index 9119ae642..3735d2cc7 100644 Binary files a/common/src/main/res/drawable-xxhdpi/signin.9.png and b/common/src/main/res/drawable-xxhdpi/signin.9.png differ diff --git a/common/src/main/res/drawable-xxhdpi/signin_pressed.9.png b/common/src/main/res/drawable-xxhdpi/signin_pressed.9.png index d0dcc4446..1d20358e0 100644 Binary files a/common/src/main/res/drawable-xxhdpi/signin_pressed.9.png and b/common/src/main/res/drawable-xxhdpi/signin_pressed.9.png differ diff --git a/common/src/main/res/drawable-xxhdpi/winner.png b/common/src/main/res/drawable-xxhdpi/winner.png new file mode 100644 index 000000000..2b4431a6c Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/winner.png differ diff --git a/common/src/main/res/drawable-xxxhdpi/signin.9.png b/common/src/main/res/drawable-xxxhdpi/signin.9.png index 1ba2df724..df3c56320 100644 Binary files a/common/src/main/res/drawable-xxxhdpi/signin.9.png and b/common/src/main/res/drawable-xxxhdpi/signin.9.png differ diff --git a/common/src/main/res/drawable-xxxhdpi/signin_pressed.9.png b/common/src/main/res/drawable-xxxhdpi/signin_pressed.9.png index b728c3dd8..ab78277ae 100644 Binary files a/common/src/main/res/drawable-xxxhdpi/signin_pressed.9.png and b/common/src/main/res/drawable-xxxhdpi/signin_pressed.9.png differ diff --git a/common/src/main/res/drawable/bg_blue_rect_light.xml b/common/src/main/res/drawable/bg_blue_rect_light.xml new file mode 100644 index 000000000..ffcaa1e82 --- /dev/null +++ b/common/src/main/res/drawable/bg_blue_rect_light.xml @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/common/src/main/res/drawable/ic_cloud_off_white_48.xml b/common/src/main/res/drawable/ic_cloud_off_white_48.xml new file mode 100644 index 000000000..5ea6d393e --- /dev/null +++ b/common/src/main/res/drawable/ic_cloud_off_white_48.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/common/src/main/res/drawable/score_background.xml b/common/src/main/res/drawable/score_background.xml index 3b65eb5c9..0bd39554b 100644 --- a/common/src/main/res/drawable/score_background.xml +++ b/common/src/main/res/drawable/score_background.xml @@ -1,4 +1,20 @@ + + @@ -13,4 +29,4 @@ android:right="0dp" android:top="0dp" /> - \ No newline at end of file + diff --git a/common/src/main/res/drawable/signin_button.xml b/common/src/main/res/drawable/signin_button.xml index 8a61f764f..c8e782b18 100644 --- a/common/src/main/res/drawable/signin_button.xml +++ b/common/src/main/res/drawable/signin_button.xml @@ -1,4 +1,20 @@ + + diff --git a/common/src/main/res/layout/activity_splash.xml b/common/src/main/res/layout/activity_splash.xml new file mode 100644 index 000000000..b2d147171 --- /dev/null +++ b/common/src/main/res/layout/activity_splash.xml @@ -0,0 +1,39 @@ + + + + + + + + + + diff --git a/common/src/main/res/raw/map_style.json b/common/src/main/res/raw/map_style.json new file mode 100644 index 000000000..b6eda021d --- /dev/null +++ b/common/src/main/res/raw/map_style.json @@ -0,0 +1,268 @@ +[ + { + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "elementType":"geometry.fill", + "stylers":[ + { + "color":"#ebe4d8" + }, + { + "lightness":10 + }, + { + "visibility":"on" + } + ] + }, + { + "elementType":"labels.text.fill", + "stylers":[ + { + "color":"#999999" + } + ] + }, + { + "elementType":"labels.text.stroke", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"administrative", + "stylers":[ + { + "visibility":"on" + } + ] + }, + { + "featureType":"administrative", + "elementType":"geometry", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"administrative", + "elementType":"labels.text", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"administrative.country", + "elementType":"geometry", + "stylers":[ + { + "color":"#cecdc9" + }, + { + "visibility":"on" + } + ] + }, + { + "featureType":"administrative.country", + "elementType":"labels", + "stylers":[ + { + "color":"#666666" + }, + { + "visibility":"simplified" + } + ] + }, + { + "featureType":"administrative.locality", + "elementType":"labels", + "stylers":[ + { + "color":"#666666" + }, + { + "visibility":"simplified" + } + ] + }, + { + "featureType":"administrative.province", + "elementType":"geometry", + "stylers":[ + { + "color":"#cecdc9" + }, + { + "visibility":"on" + } + ] + }, + { + "featureType":"poi.park", + "stylers":[ + { + "visibility":"on" + } + ] + }, + { + "featureType":"poi.park", + "elementType":"geometry", + "stylers":[ + { + "color":"#95ef9e" + }, + { + "lightness":20 + } + ] + }, + { + "featureType":"poi.park", + "elementType":"labels.icon", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"poi.park", + "elementType":"labels.text.fill", + "stylers":[ + { + "color":"#719478" + } + ] + }, + { + "featureType":"poi.park", + "elementType":"labels.text.stroke", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"road", + "stylers":[ + { + "visibility":"on" + } + ] + }, + { + "featureType":"road", + "elementType":"geometry", + "stylers":[ + { + "color":"#f2f2f2" + } + ] + }, + { + "featureType":"road", + "elementType":"labels.icon", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"road", + "elementType":"labels.text.stroke", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"road.arterial", + "elementType":"labels.icon", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"road.highway", + "elementType":"labels.icon", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"road.highway.controlled_access", + "elementType":"labels.icon", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"road.local", + "elementType":"labels.icon", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"transit", + "stylers":[ + { + "visibility":"off" + } + ] + }, + { + "featureType":"water", + "stylers":[ + { + "visibility":"on" + } + ] + }, + { + "featureType":"water", + "elementType":"geometry", + "stylers":[ + { + "color":"#68d5d0" + }, + { + "lightness":25 + } + ] + }, + { + "featureType":"water", + "elementType":"labels.text", + "stylers":[ + { + "color":"#6da09d" + } + ] + } +] diff --git a/common/src/main/res/values-af/strings.xml b/common/src/main/res/values-af/strings.xml new file mode 100644 index 000000000..23cee5f16 --- /dev/null +++ b/common/src/main/res/values-af/strings.xml @@ -0,0 +1,21 @@ + + + + Terug na kaart + Terug na dorpie + Hierdie weergawe van Waar is Kersvader is verouderd. Besoek asseblief die Play Store om na die nuutste weergawe op te dateer. + diff --git a/common/src/main/res/values-af/strings_gamenames.xml b/common/src/main/res/values-af/strings_gamenames.xml index e687c26e8..1f7c23b9c 100644 --- a/common/src/main/res/values-af/strings_gamenames.xml +++ b/common/src/main/res/values-af/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Geheue - Elf-stralerpak - Snowglobe - Rocket Sleigh - Dasher Dancer - Sneeubal-speletjie - Snowdown + Gumball + Geheue + Elf-stralerpak + Rocket Sleigh + Dasher Dancer + Snowdown + Stadvasvra + Geskenksoektog diff --git a/common/src/main/res/values-af/strings_invite.xml b/common/src/main/res/values-af/strings_invite.xml index b0a98bf11..20440e569 100644 --- a/common/src/main/res/values-af/strings_invite.xml +++ b/common/src/main/res/values-af/strings_invite.xml @@ -1,4 +1,20 @@ + + Nooi jou vriende om Kersvader met Google te volg Probeer Santa Tracker en kyk hoe Kersvader om die wêreld vlieg! diff --git a/common/src/main/res/values-af/strings_jetpack.xml b/common/src/main/res/values-af/strings_jetpack.xml index 12ee9cfe6..d43ba3abb 100644 --- a/common/src/main/res/values-af/strings_jetpack.xml +++ b/common/src/main/res/values-af/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Meld aan om prestasies te ontsluit en jou telling te plaas! Speel weer - Telling + Gaan terug na kaart + TELLING + Gaan terug na kaart diff --git a/common/src/main/res/values-ar-rXB/strings.xml b/common/src/main/res/values-ar-rXB/strings.xml new file mode 100644 index 000000000..c6b0af13b --- /dev/null +++ b/common/src/main/res/values-ar-rXB/strings.xml @@ -0,0 +1,21 @@ + + + + ‏‮Back‬‏ ‏‮to‬‏ ‏‮map‬‏ + ‏‮Back‬‏ ‏‮to‬‏ ‏‮village‬‏ + ‏‮This‬‏ ‏‮version‬‏ ‏‮of‬‏ ‏‮Santa‬‏ ‏‮Tracker‬‏ ‏‮is‬‏ ‏‮out‬‏ ‏‮of‬‏ ‏‮date‬‏. ‏‮Please‬‏ ‏‮visit‬‏ ‏‮the‬‏ ‏‮Play‬‏ ‏‮Store‬‏ ‏‮to‬‏ ‏‮update‬‏ ‏‮to‬‏ ‏‮the‬‏ ‏‮latest‬‏ ‏‮version‬‏. + diff --git a/common/src/main/res/values-ar-rXB/strings_gamenames.xml b/common/src/main/res/values-ar-rXB/strings_gamenames.xml index a2152d874..3247a28d1 100644 --- a/common/src/main/res/values-ar-rXB/strings_gamenames.xml +++ b/common/src/main/res/values-ar-rXB/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - ‏‮Gumball‬‏ - ‏‮Memory‬‏ - ‏‮Elf‬‏ ‏‮Jetpack‬‏ - ‏‮Snowglobe‬‏ - ‏‮Rocket‬‏ ‏‮Sleigh‬‏ - ‏‮Dasher‬‏ ‏‮Dancer‬‏ - ‏‮Snowball‬‏ ‏‮game‬‏ - ‏‮Snowdown‬‏ + ‏‮Gumball‬‏ + ‏‮Memory‬‏ + ‏‮Elf‬‏ ‏‮Jetpack‬‏ + ‏‮Rocket‬‏ ‏‮Sleigh‬‏ + ‏‮Dasher‬‏ ‏‮Dancer‬‏ + ‏‮Snowdown‬‏ + ‏‮City‬‏ ‏‮Quiz‬‏ + ‏‮Present‬‏ ‏‮Quest‬‏ diff --git a/common/src/main/res/values-ar-rXB/strings_invite.xml b/common/src/main/res/values-ar-rXB/strings_invite.xml index 92a8c2e10..e3fc3f371 100644 --- a/common/src/main/res/values-ar-rXB/strings_invite.xml +++ b/common/src/main/res/values-ar-rXB/strings_invite.xml @@ -1,4 +1,20 @@ + + ‏‮Invite‬‏ ‏‮your‬‏ ‏‮friends‬‏ ‏‮to‬‏ ‏‮track‬‏ ‏‮Santa‬‏ ‏‮with‬‏ ‏‮Google‬‏ ‏‮Try‬‏ ‏‮Santa‬‏ ‏‮Tracker‬‏ ‏‮and‬‏ ‏‮watch‬‏ ‏‮Santa‬‏ ‏‮fly‬‏ ‏‮around‬‏ ‏‮the‬‏ ‏‮world‬‏! diff --git a/common/src/main/res/values-ar-rXB/strings_jetpack.xml b/common/src/main/res/values-ar-rXB/strings_jetpack.xml index 66fe7a59f..1894426f5 100644 --- a/common/src/main/res/values-ar-rXB/strings_jetpack.xml +++ b/common/src/main/res/values-ar-rXB/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ‏‮Sign‬‏ ‏‮in‬‏ ‏‮to‬‏ ‏‮unlock‬‏ ‏‮achievements‬‏ ‏‮and‬‏ ‏‮post‬‏ ‏‮your‬‏ ‏‮score‬‏! ‏‮Play‬‏ ‏‮Again‬‏ - ‏‮Score‬‏ + ‏‮Return‬‏ ‏‮to‬‏ ‏‮Map‬‏ + ‏‮SCORE‬‏ + ‏‮Return‬‏ ‏‮to‬‏ ‏‮map‬‏ diff --git a/common/src/main/res/values-bg/strings.xml b/common/src/main/res/values-bg/strings.xml new file mode 100644 index 000000000..39f4c0325 --- /dev/null +++ b/common/src/main/res/values-bg/strings.xml @@ -0,0 +1,21 @@ + + + + Назад към картата + Назад към селцето + Тази версия на приложението „Къде е Дядо Коледа“ не е актуална. Моля, посетете Google Play Магазин, за да актуализирате до най-новата версия. + diff --git a/common/src/main/res/values-bg/strings_gamenames.xml b/common/src/main/res/values-bg/strings_gamenames.xml index 8a7504c21..2cacbbefe 100644 --- a/common/src/main/res/values-bg/strings_gamenames.xml +++ b/common/src/main/res/values-bg/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Гъмбол - Мемори - Реактивно джудже - Snowglobe - Rocket Sleigh - Dasher Dancer - Игра „Snowball“ - Snowdown + Гъмбол + Мемори + Реактивно джудже + Rocket Sleigh + Dasher Dancer + Snowdown + Географска викторина + Търсене на подаръци diff --git a/common/src/main/res/values-bg/strings_invite.xml b/common/src/main/res/values-bg/strings_invite.xml index 9c86eb1f8..3cf4531ad 100644 --- a/common/src/main/res/values-bg/strings_invite.xml +++ b/common/src/main/res/values-bg/strings_invite.xml @@ -1,4 +1,20 @@ + + Поканете приятелите си да следят Дядо Коледа с Google Изпробвайте „Къде е Дядо Коледа“ и гледайте как белобрадият старец лети по цял свят! diff --git a/common/src/main/res/values-bg/strings_jetpack.xml b/common/src/main/res/values-bg/strings_jetpack.xml index 79e2b5099..05ca6266a 100644 --- a/common/src/main/res/values-bg/strings_jetpack.xml +++ b/common/src/main/res/values-bg/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Влезте в профила си, за да отключвате постижения и да публикувате резултата си! Нова игра - Резултат + Назад към картата + РЕЗУЛТАТ + Назад към картата diff --git a/common/src/main/res/values-ca/strings.xml b/common/src/main/res/values-ca/strings.xml new file mode 100644 index 000000000..1f82adf7c --- /dev/null +++ b/common/src/main/res/values-ca/strings.xml @@ -0,0 +1,21 @@ + + + + Torna al mapa + Torna a l\'aldea + Aquesta versió de Segueix el Pare Noel està obsoleta. Visita Play Store per actualitzar l\'aplicació a la versió més recent. + diff --git a/common/src/main/res/values-ca/strings_gamenames.xml b/common/src/main/res/values-ca/strings_gamenames.xml index 72e11737a..bd7f55d26 100644 --- a/common/src/main/res/values-ca/strings_gamenames.xml +++ b/common/src/main/res/values-ca/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - El joc Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Joc de les ciutats + Recerca de regals diff --git a/common/src/main/res/values-ca/strings_invite.xml b/common/src/main/res/values-ca/strings_invite.xml index 181621836..973f588ae 100644 --- a/common/src/main/res/values-ca/strings_invite.xml +++ b/common/src/main/res/values-ca/strings_invite.xml @@ -1,4 +1,20 @@ + + Convideu els vostres amics a seguir el Pare Noel amb Google Prova l\'aplicació Segueix el Pare Noel i mira com el Pare Noel vola per tot el món. diff --git a/common/src/main/res/values-ca/strings_jetpack.xml b/common/src/main/res/values-ca/strings_jetpack.xml index b026509f8..e821119ab 100644 --- a/common/src/main/res/values-ca/strings_jetpack.xml +++ b/common/src/main/res/values-ca/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Inicieu la sessió per desbloquejar assoliments i publicar la vostra puntuació Torna a jugar - Puntuació + Torna al mapa + PUNTUACIÓ + Torna al mapa diff --git a/common/src/main/res/values-da/strings.xml b/common/src/main/res/values-da/strings.xml new file mode 100644 index 000000000..9b28ef62d --- /dev/null +++ b/common/src/main/res/values-da/strings.xml @@ -0,0 +1,21 @@ + + + + Tilbage til kortet + Tilbage til landsbyen + Denne version af Følg julemanden er forældet. Gå til Play Butik for at opdatere til den nyeste version. + diff --git a/common/src/main/res/values-da/strings_gamenames.xml b/common/src/main/res/values-da/strings_gamenames.xml index 3fb1976ad..d5d5b9f1a 100644 --- a/common/src/main/res/values-da/strings_gamenames.xml +++ b/common/src/main/res/values-da/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snekuglespil - Raketslædespil - Julemandens rensdyr - Sneboldspil - Snowdown + Gumball + Memory + Elf Jetpack + Raketslædespil + Julemandens rensdyr + Snowdown + Kortquiz + Gavejagten diff --git a/common/src/main/res/values-da/strings_invite.xml b/common/src/main/res/values-da/strings_invite.xml index b8c78e7d9..519a6d708 100644 --- a/common/src/main/res/values-da/strings_invite.xml +++ b/common/src/main/res/values-da/strings_invite.xml @@ -1,6 +1,22 @@ + + Inviter dine venner til at følge julemanden med Google - Prøv Følg julemanden, og se julemanden flyve verden rundt! + Følg julemanden for at se ham flyve verden rundt! Jeg fik en score på %1$d, da jeg spillede %2$s-spillet sammen med nisserne i Googles Følg julemanden. Kan du slå den score? diff --git a/common/src/main/res/values-da/strings_jetpack.xml b/common/src/main/res/values-da/strings_jetpack.xml index da62d3d56..adaa28980 100644 --- a/common/src/main/res/values-da/strings_jetpack.xml +++ b/common/src/main/res/values-da/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Log ind for at låse op for resultater og indsende dine point. Spil igen - Pointtal + Tilbage til kortet + POINT + Tilbage til kortet diff --git a/common/src/main/res/values-de-rAT/strings.xml b/common/src/main/res/values-de-rAT/strings.xml new file mode 100644 index 000000000..34e7cbd5d --- /dev/null +++ b/common/src/main/res/values-de-rAT/strings.xml @@ -0,0 +1,21 @@ + + + + Zurück zur Karte + Zurück zum Dorf + Diese Version von \"Auf den Spuren des Weihnachtsmanns\" ist abgelaufen. Du kannst sie im Play Store aktualisieren. + diff --git a/common/src/main/res/values-de-rAT/strings_gamenames.xml b/common/src/main/res/values-de-rAT/strings_gamenames.xml index bc79191c0..217efc408 100644 --- a/common/src/main/res/values-de-rAT/strings_gamenames.xml +++ b/common/src/main/res/values-de-rAT/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball Game - Snowdown + Gumball + Memory + Elf Jetpack + Raketenflug + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-de-rAT/strings_invite.xml b/common/src/main/res/values-de-rAT/strings_invite.xml index 931606d08..af70d7e32 100644 --- a/common/src/main/res/values-de-rAT/strings_invite.xml +++ b/common/src/main/res/values-de-rAT/strings_invite.xml @@ -1,4 +1,20 @@ + + Freunde dazu einladen, die Reise des Weihnachtsmanns mit Google zu verfolgen Begib dich auf die Spuren des Weihnachtsmanns und verfolge ihn auf seinem Flug um die Welt! diff --git a/common/src/main/res/values-de-rAT/strings_jetpack.xml b/common/src/main/res/values-de-rAT/strings_jetpack.xml index 94ecb86e2..32a746708 100644 --- a/common/src/main/res/values-de-rAT/strings_jetpack.xml +++ b/common/src/main/res/values-de-rAT/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten! Neues Spiel - Punktzahl + Zurück zur Karte + PUNKTE + Zurück zur Karte diff --git a/common/src/main/res/values-de-rCH/strings.xml b/common/src/main/res/values-de-rCH/strings.xml new file mode 100644 index 000000000..34e7cbd5d --- /dev/null +++ b/common/src/main/res/values-de-rCH/strings.xml @@ -0,0 +1,21 @@ + + + + Zurück zur Karte + Zurück zum Dorf + Diese Version von \"Auf den Spuren des Weihnachtsmanns\" ist abgelaufen. Du kannst sie im Play Store aktualisieren. + diff --git a/common/src/main/res/values-de-rCH/strings_gamenames.xml b/common/src/main/res/values-de-rCH/strings_gamenames.xml index bc79191c0..217efc408 100644 --- a/common/src/main/res/values-de-rCH/strings_gamenames.xml +++ b/common/src/main/res/values-de-rCH/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball Game - Snowdown + Gumball + Memory + Elf Jetpack + Raketenflug + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-de-rCH/strings_invite.xml b/common/src/main/res/values-de-rCH/strings_invite.xml index 931606d08..af70d7e32 100644 --- a/common/src/main/res/values-de-rCH/strings_invite.xml +++ b/common/src/main/res/values-de-rCH/strings_invite.xml @@ -1,4 +1,20 @@ + + Freunde dazu einladen, die Reise des Weihnachtsmanns mit Google zu verfolgen Begib dich auf die Spuren des Weihnachtsmanns und verfolge ihn auf seinem Flug um die Welt! diff --git a/common/src/main/res/values-de-rCH/strings_jetpack.xml b/common/src/main/res/values-de-rCH/strings_jetpack.xml index 94ecb86e2..32a746708 100644 --- a/common/src/main/res/values-de-rCH/strings_jetpack.xml +++ b/common/src/main/res/values-de-rCH/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten! Neues Spiel - Punktzahl + Zurück zur Karte + PUNKTE + Zurück zur Karte diff --git a/common/src/main/res/values-de/strings.xml b/common/src/main/res/values-de/strings.xml new file mode 100644 index 000000000..34e7cbd5d --- /dev/null +++ b/common/src/main/res/values-de/strings.xml @@ -0,0 +1,21 @@ + + + + Zurück zur Karte + Zurück zum Dorf + Diese Version von \"Auf den Spuren des Weihnachtsmanns\" ist abgelaufen. Du kannst sie im Play Store aktualisieren. + diff --git a/common/src/main/res/values-de/strings_gamenames.xml b/common/src/main/res/values-de/strings_gamenames.xml index bc79191c0..217efc408 100644 --- a/common/src/main/res/values-de/strings_gamenames.xml +++ b/common/src/main/res/values-de/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball Game - Snowdown + Gumball + Memory + Elf Jetpack + Raketenflug + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-de/strings_invite.xml b/common/src/main/res/values-de/strings_invite.xml index 600b50fbd..af70d7e32 100644 --- a/common/src/main/res/values-de/strings_invite.xml +++ b/common/src/main/res/values-de/strings_invite.xml @@ -1,6 +1,22 @@ + + Freunde dazu einladen, die Reise des Weihnachtsmanns mit Google zu verfolgen Begib dich auf die Spuren des Weihnachtsmanns und verfolge ihn auf seinem Flug um die Welt! - Ich habe in Google Santa Tracker das Spiel %2$s mit den Wichteln gespielt und %1$d Punkte erreicht. Schaffst du das auch? - \ No newline at end of file + Ich habe in \"Auf den Spuren des Weihnachtsmanns\" von Google das Spiel %2$s mit den Wichteln gespielt und %1$d Punkte erreicht. Schaffst du das auch? + diff --git a/common/src/main/res/values-de/strings_jetpack.xml b/common/src/main/res/values-de/strings_jetpack.xml index 94ecb86e2..32a746708 100644 --- a/common/src/main/res/values-de/strings_jetpack.xml +++ b/common/src/main/res/values-de/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten! Neues Spiel - Punktzahl + Zurück zur Karte + PUNKTE + Zurück zur Karte diff --git a/common/src/main/res/values-en-rGB/strings.xml b/common/src/main/res/values-en-rGB/strings.xml new file mode 100644 index 000000000..e84feda05 --- /dev/null +++ b/common/src/main/res/values-en-rGB/strings.xml @@ -0,0 +1,21 @@ + + + + Back to map + Back to village + This version of Santa Tracker is out of date. Please visit the Play Store to update to the latest version. + diff --git a/common/src/main/res/values-en-rGB/strings_gamenames.xml b/common/src/main/res/values-en-rGB/strings_gamenames.xml index 02d7c389b..21d77d782 100644 --- a/common/src/main/res/values-en-rGB/strings_gamenames.xml +++ b/common/src/main/res/values-en-rGB/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-en-rGB/strings_invite.xml b/common/src/main/res/values-en-rGB/strings_invite.xml index 5408f2b79..b358cf80c 100644 --- a/common/src/main/res/values-en-rGB/strings_invite.xml +++ b/common/src/main/res/values-en-rGB/strings_invite.xml @@ -1,4 +1,20 @@ + + Invite your friends to track Santa with Google Try Santa Tracker and watch Santa fly around the world! diff --git a/common/src/main/res/values-en-rGB/strings_jetpack.xml b/common/src/main/res/values-en-rGB/strings_jetpack.xml index 428344416..7d3ff2361 100644 --- a/common/src/main/res/values-en-rGB/strings_jetpack.xml +++ b/common/src/main/res/values-en-rGB/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Sign in to unlock achievements and post your score! Play Again - Score + Return to Map + SCORE + Return to map diff --git a/common/src/main/res/values-en-rIE/strings.xml b/common/src/main/res/values-en-rIE/strings.xml new file mode 100644 index 000000000..e84feda05 --- /dev/null +++ b/common/src/main/res/values-en-rIE/strings.xml @@ -0,0 +1,21 @@ + + + + Back to map + Back to village + This version of Santa Tracker is out of date. Please visit the Play Store to update to the latest version. + diff --git a/common/src/main/res/values-en-rIE/strings_gamenames.xml b/common/src/main/res/values-en-rIE/strings_gamenames.xml index 02d7c389b..21d77d782 100644 --- a/common/src/main/res/values-en-rIE/strings_gamenames.xml +++ b/common/src/main/res/values-en-rIE/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-en-rIE/strings_invite.xml b/common/src/main/res/values-en-rIE/strings_invite.xml index 5408f2b79..b358cf80c 100644 --- a/common/src/main/res/values-en-rIE/strings_invite.xml +++ b/common/src/main/res/values-en-rIE/strings_invite.xml @@ -1,4 +1,20 @@ + + Invite your friends to track Santa with Google Try Santa Tracker and watch Santa fly around the world! diff --git a/common/src/main/res/values-en-rIE/strings_jetpack.xml b/common/src/main/res/values-en-rIE/strings_jetpack.xml index 428344416..7d3ff2361 100644 --- a/common/src/main/res/values-en-rIE/strings_jetpack.xml +++ b/common/src/main/res/values-en-rIE/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Sign in to unlock achievements and post your score! Play Again - Score + Return to Map + SCORE + Return to map diff --git a/common/src/main/res/values-en-rIN/strings.xml b/common/src/main/res/values-en-rIN/strings.xml new file mode 100644 index 000000000..e84feda05 --- /dev/null +++ b/common/src/main/res/values-en-rIN/strings.xml @@ -0,0 +1,21 @@ + + + + Back to map + Back to village + This version of Santa Tracker is out of date. Please visit the Play Store to update to the latest version. + diff --git a/common/src/main/res/values-en-rIN/strings_gamenames.xml b/common/src/main/res/values-en-rIN/strings_gamenames.xml index 02d7c389b..21d77d782 100644 --- a/common/src/main/res/values-en-rIN/strings_gamenames.xml +++ b/common/src/main/res/values-en-rIN/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-en-rIN/strings_invite.xml b/common/src/main/res/values-en-rIN/strings_invite.xml index 5408f2b79..b358cf80c 100644 --- a/common/src/main/res/values-en-rIN/strings_invite.xml +++ b/common/src/main/res/values-en-rIN/strings_invite.xml @@ -1,4 +1,20 @@ + + Invite your friends to track Santa with Google Try Santa Tracker and watch Santa fly around the world! diff --git a/common/src/main/res/values-en-rIN/strings_jetpack.xml b/common/src/main/res/values-en-rIN/strings_jetpack.xml index 428344416..7d3ff2361 100644 --- a/common/src/main/res/values-en-rIN/strings_jetpack.xml +++ b/common/src/main/res/values-en-rIN/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Sign in to unlock achievements and post your score! Play Again - Score + Return to Map + SCORE + Return to map diff --git a/common/src/main/res/values-en-rSG/strings.xml b/common/src/main/res/values-en-rSG/strings.xml new file mode 100644 index 000000000..e84feda05 --- /dev/null +++ b/common/src/main/res/values-en-rSG/strings.xml @@ -0,0 +1,21 @@ + + + + Back to map + Back to village + This version of Santa Tracker is out of date. Please visit the Play Store to update to the latest version. + diff --git a/common/src/main/res/values-en-rSG/strings_gamenames.xml b/common/src/main/res/values-en-rSG/strings_gamenames.xml index 02d7c389b..21d77d782 100644 --- a/common/src/main/res/values-en-rSG/strings_gamenames.xml +++ b/common/src/main/res/values-en-rSG/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-en-rSG/strings_invite.xml b/common/src/main/res/values-en-rSG/strings_invite.xml index 5408f2b79..b358cf80c 100644 --- a/common/src/main/res/values-en-rSG/strings_invite.xml +++ b/common/src/main/res/values-en-rSG/strings_invite.xml @@ -1,4 +1,20 @@ + + Invite your friends to track Santa with Google Try Santa Tracker and watch Santa fly around the world! diff --git a/common/src/main/res/values-en-rSG/strings_jetpack.xml b/common/src/main/res/values-en-rSG/strings_jetpack.xml index 428344416..7d3ff2361 100644 --- a/common/src/main/res/values-en-rSG/strings_jetpack.xml +++ b/common/src/main/res/values-en-rSG/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Sign in to unlock achievements and post your score! Play Again - Score + Return to Map + SCORE + Return to map diff --git a/common/src/main/res/values-en-rXA/strings.xml b/common/src/main/res/values-en-rXA/strings.xml new file mode 100644 index 000000000..004660d19 --- /dev/null +++ b/common/src/main/res/values-en-rXA/strings.xml @@ -0,0 +1,21 @@ + + + + [Бåçķ ţö måþ one two] + [Бåçķ ţö vîļļåĝé one two] + [Ţĥîš véŕšîöñ öƒ Šåñţå Ţŕåçķéŕ îš öûţ öƒ ðåţé. Þļéåšé vîšîţ ţĥé Þļåý Šţöŕé ţö ûþðåţé ţö ţĥé ļåţéšţ véŕšîöñ. one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen] + diff --git a/common/src/main/res/values-en-rXA/strings_gamenames.xml b/common/src/main/res/values-en-rXA/strings_gamenames.xml index 785f7e120..229b9c206 100644 --- a/common/src/main/res/values-en-rXA/strings_gamenames.xml +++ b/common/src/main/res/values-en-rXA/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - [Ĝûmбåļļ one] - [Mémöŕý one] - [Éļƒ Ĵéţþåçķ one two] - [Šñöŵĝļöбé one two] - [Ŕöçķéţ Šļéîĝĥ one two] - [Ðåšĥéŕ Ðåñçéŕ one two] - [Šñöŵбåļļ ĝåmé one two] - [Šñöŵðöŵñ one] + [Ĝûmбåļļ one] + [Mémöŕý one] + [Éļƒ Ĵéţþåçķ one two] + [Ŕöçķéţ Šļéîĝĥ one two] + [Ðåšĥéŕ Ðåñçéŕ one two] + [Šñöŵðöŵñ one] + [Çîţý Qûîž one two] + [Þŕéšéñţ Qûéšţ one two] diff --git a/common/src/main/res/values-en-rXA/strings_invite.xml b/common/src/main/res/values-en-rXA/strings_invite.xml index f38662bd2..573e30158 100644 --- a/common/src/main/res/values-en-rXA/strings_invite.xml +++ b/common/src/main/res/values-en-rXA/strings_invite.xml @@ -1,4 +1,20 @@ + + [Îñvîţé ýöûŕ ƒŕîéñðš ţö ţŕåçķ Šåñţå ŵîţĥ Ĝööĝļé one two three four five six seven eight nine ten] [Ţŕý Šåñţå Ţŕåçķéŕ åñð ŵåţçĥ Šåñţå ƒļý åŕöûñð ţĥé ŵöŕļð¡ one two three four five six seven eight nine ten eleven] diff --git a/common/src/main/res/values-en-rXA/strings_jetpack.xml b/common/src/main/res/values-en-rXA/strings_jetpack.xml index 44c302cb8..93bbc04af 100644 --- a/common/src/main/res/values-en-rXA/strings_jetpack.xml +++ b/common/src/main/res/values-en-rXA/strings_jetpack.xml @@ -1,6 +1,24 @@ + + [Šîĝñ îñ ţö ûñļöçķ åçĥîévéméñţš åñð þöšţ ýöûŕ šçöŕé¡ one two three four five six seven eight nine ten eleven] [Þļåý Åĝåîñ one two] - [Šçöŕé one] + [Ŕéţûŕñ ţö Måþ one two] + [ŠÇÖŔÉ one] + [Ŕéţûŕñ ţö måþ one two] diff --git a/common/src/main/res/values-en-rXC/strings.xml b/common/src/main/res/values-en-rXC/strings.xml new file mode 100644 index 000000000..a175c1642 --- /dev/null +++ b/common/src/main/res/values-en-rXC/strings.xml @@ -0,0 +1,21 @@ + + + + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‎‎‎‎‏‏‎‎Back to map‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‎‎‏‎Back to village‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‎‏‏‎‏‎‏‏‎‎This version of Santa Tracker is out of date. Please visit the Play Store to update to the latest version.‎‏‎‎‏‎ + diff --git a/common/src/main/res/values-en-rXC/strings_gamenames.xml b/common/src/main/res/values-en-rXC/strings_gamenames.xml index c19c7710e..9e64dafac 100644 --- a/common/src/main/res/values-en-rXC/strings_gamenames.xml +++ b/common/src/main/res/values-en-rXC/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‎Gumball‎‏‎‎‏‎ - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎Memory‎‏‎‎‏‎ - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‎‎Elf Jetpack‎‏‎‎‏‎ - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎Snowglobe‎‏‎‎‏‎ - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎Rocket Sleigh‎‏‎‎‏‎ - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‏‏‏‎‎‎Dasher Dancer‎‏‎‎‏‎ - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‏‏‎‎Snowball game‎‏‎‎‏‎ - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‎‏‎Snowdown‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‎Gumball‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎Memory‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‎‎Elf Jetpack‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎Rocket Sleigh‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‏‏‏‎‎‎Dasher Dancer‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‎‏‎Snowdown‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎City Quiz‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎Present Quest‎‏‎‎‏‎ diff --git a/common/src/main/res/values-en-rXC/strings_invite.xml b/common/src/main/res/values-en-rXC/strings_invite.xml index 7191414d5..61c3d8a0a 100644 --- a/common/src/main/res/values-en-rXC/strings_invite.xml +++ b/common/src/main/res/values-en-rXC/strings_invite.xml @@ -1,4 +1,20 @@ + + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‏‎Invite your friends to track Santa with Google‎‏‎‎‏‎ ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎Try Santa Tracker and watch Santa fly around the world!‎‏‎‎‏‎ diff --git a/common/src/main/res/values-en-rXC/strings_jetpack.xml b/common/src/main/res/values-en-rXC/strings_jetpack.xml index 8ea177340..953a20328 100644 --- a/common/src/main/res/values-en-rXC/strings_jetpack.xml +++ b/common/src/main/res/values-en-rXC/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎Sign in to unlock achievements and post your score!‎‏‎‎‏‎ ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎Play Again‎‏‎‎‏‎ - ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎Score‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎Return to Map‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎‏‎‎‏‎‎‎‎‎SCORE‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‎‏‏‎‎‏‎Return to map‎‏‎‎‏‎ diff --git a/common/src/main/res/values-en-rZA/strings.xml b/common/src/main/res/values-en-rZA/strings.xml new file mode 100644 index 000000000..e84feda05 --- /dev/null +++ b/common/src/main/res/values-en-rZA/strings.xml @@ -0,0 +1,21 @@ + + + + Back to map + Back to village + This version of Santa Tracker is out of date. Please visit the Play Store to update to the latest version. + diff --git a/common/src/main/res/values-en-rZA/strings_gamenames.xml b/common/src/main/res/values-en-rZA/strings_gamenames.xml index 02d7c389b..21d77d782 100644 --- a/common/src/main/res/values-en-rZA/strings_gamenames.xml +++ b/common/src/main/res/values-en-rZA/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-en-rZA/strings_invite.xml b/common/src/main/res/values-en-rZA/strings_invite.xml index 5408f2b79..b358cf80c 100644 --- a/common/src/main/res/values-en-rZA/strings_invite.xml +++ b/common/src/main/res/values-en-rZA/strings_invite.xml @@ -1,4 +1,20 @@ + + Invite your friends to track Santa with Google Try Santa Tracker and watch Santa fly around the world! diff --git a/common/src/main/res/values-en-rZA/strings_jetpack.xml b/common/src/main/res/values-en-rZA/strings_jetpack.xml index 428344416..7d3ff2361 100644 --- a/common/src/main/res/values-en-rZA/strings_jetpack.xml +++ b/common/src/main/res/values-en-rZA/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Sign in to unlock achievements and post your score! Play Again - Score + Return to Map + SCORE + Return to map diff --git a/common/src/main/res/values-es-rAR/strings.xml b/common/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rAR/strings_gamenames.xml b/common/src/main/res/values-es-rAR/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rAR/strings_gamenames.xml +++ b/common/src/main/res/values-es-rAR/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rAR/strings_invite.xml b/common/src/main/res/values-es-rAR/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rAR/strings_invite.xml +++ b/common/src/main/res/values-es-rAR/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rAR/strings_jetpack.xml b/common/src/main/res/values-es-rAR/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rAR/strings_jetpack.xml +++ b/common/src/main/res/values-es-rAR/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rBO/strings.xml b/common/src/main/res/values-es-rBO/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rBO/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rBO/strings_gamenames.xml b/common/src/main/res/values-es-rBO/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rBO/strings_gamenames.xml +++ b/common/src/main/res/values-es-rBO/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rBO/strings_invite.xml b/common/src/main/res/values-es-rBO/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rBO/strings_invite.xml +++ b/common/src/main/res/values-es-rBO/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rBO/strings_jetpack.xml b/common/src/main/res/values-es-rBO/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rBO/strings_jetpack.xml +++ b/common/src/main/res/values-es-rBO/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rCL/strings.xml b/common/src/main/res/values-es-rCL/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rCL/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rCL/strings_gamenames.xml b/common/src/main/res/values-es-rCL/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rCL/strings_gamenames.xml +++ b/common/src/main/res/values-es-rCL/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rCL/strings_invite.xml b/common/src/main/res/values-es-rCL/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rCL/strings_invite.xml +++ b/common/src/main/res/values-es-rCL/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rCL/strings_jetpack.xml b/common/src/main/res/values-es-rCL/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rCL/strings_jetpack.xml +++ b/common/src/main/res/values-es-rCL/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rCO/strings.xml b/common/src/main/res/values-es-rCO/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rCO/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rCO/strings_gamenames.xml b/common/src/main/res/values-es-rCO/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rCO/strings_gamenames.xml +++ b/common/src/main/res/values-es-rCO/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rCO/strings_invite.xml b/common/src/main/res/values-es-rCO/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rCO/strings_invite.xml +++ b/common/src/main/res/values-es-rCO/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rCO/strings_jetpack.xml b/common/src/main/res/values-es-rCO/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rCO/strings_jetpack.xml +++ b/common/src/main/res/values-es-rCO/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rCR/strings.xml b/common/src/main/res/values-es-rCR/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rCR/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rCR/strings_gamenames.xml b/common/src/main/res/values-es-rCR/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rCR/strings_gamenames.xml +++ b/common/src/main/res/values-es-rCR/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rCR/strings_invite.xml b/common/src/main/res/values-es-rCR/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rCR/strings_invite.xml +++ b/common/src/main/res/values-es-rCR/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rCR/strings_jetpack.xml b/common/src/main/res/values-es-rCR/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rCR/strings_jetpack.xml +++ b/common/src/main/res/values-es-rCR/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rDO/strings.xml b/common/src/main/res/values-es-rDO/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rDO/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rDO/strings_gamenames.xml b/common/src/main/res/values-es-rDO/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rDO/strings_gamenames.xml +++ b/common/src/main/res/values-es-rDO/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rDO/strings_invite.xml b/common/src/main/res/values-es-rDO/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rDO/strings_invite.xml +++ b/common/src/main/res/values-es-rDO/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rDO/strings_jetpack.xml b/common/src/main/res/values-es-rDO/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rDO/strings_jetpack.xml +++ b/common/src/main/res/values-es-rDO/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rEC/strings.xml b/common/src/main/res/values-es-rEC/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rEC/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rEC/strings_gamenames.xml b/common/src/main/res/values-es-rEC/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rEC/strings_gamenames.xml +++ b/common/src/main/res/values-es-rEC/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rEC/strings_invite.xml b/common/src/main/res/values-es-rEC/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rEC/strings_invite.xml +++ b/common/src/main/res/values-es-rEC/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rEC/strings_jetpack.xml b/common/src/main/res/values-es-rEC/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rEC/strings_jetpack.xml +++ b/common/src/main/res/values-es-rEC/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rES/strings_gamenames.xml b/common/src/main/res/values-es-rES/strings_gamenames.xml old mode 100755 new mode 100644 index 386cbd95f..2a370be4d --- a/common/src/main/res/values-es-rES/strings_gamenames.xml +++ b/common/src/main/res/values-es-rES/strings_gamenames.xml @@ -1,10 +1,26 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball + Gumball + Memory + Elf Jetpack + Snowglobe + Rocket Sleigh + Dasher Dancer + Snowball diff --git a/common/src/main/res/values-es-rES/strings_jetpack.xml b/common/src/main/res/values-es-rES/strings_jetpack.xml index b770d7fa7..a04a23838 100644 --- a/common/src/main/res/values-es-rES/strings_jetpack.xml +++ b/common/src/main/res/values-es-rES/strings_jetpack.xml @@ -1,5 +1,21 @@ + + - Accede a tu cuenta para desbloquear logros y publicar tu puntuación - Volver a jugar - Puntuación + Accede a tu cuenta para desbloquear logros y publicar tu puntuación + Volver a jugar + Puntuación diff --git a/common/src/main/res/values-es-rGT/strings.xml b/common/src/main/res/values-es-rGT/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rGT/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rGT/strings_gamenames.xml b/common/src/main/res/values-es-rGT/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rGT/strings_gamenames.xml +++ b/common/src/main/res/values-es-rGT/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rGT/strings_invite.xml b/common/src/main/res/values-es-rGT/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rGT/strings_invite.xml +++ b/common/src/main/res/values-es-rGT/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rGT/strings_jetpack.xml b/common/src/main/res/values-es-rGT/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rGT/strings_jetpack.xml +++ b/common/src/main/res/values-es-rGT/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rHN/strings.xml b/common/src/main/res/values-es-rHN/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rHN/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rHN/strings_gamenames.xml b/common/src/main/res/values-es-rHN/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rHN/strings_gamenames.xml +++ b/common/src/main/res/values-es-rHN/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rHN/strings_invite.xml b/common/src/main/res/values-es-rHN/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rHN/strings_invite.xml +++ b/common/src/main/res/values-es-rHN/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rHN/strings_jetpack.xml b/common/src/main/res/values-es-rHN/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rHN/strings_jetpack.xml +++ b/common/src/main/res/values-es-rHN/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rMX/strings.xml b/common/src/main/res/values-es-rMX/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rMX/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rMX/strings_gamenames.xml b/common/src/main/res/values-es-rMX/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rMX/strings_gamenames.xml +++ b/common/src/main/res/values-es-rMX/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rMX/strings_invite.xml b/common/src/main/res/values-es-rMX/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rMX/strings_invite.xml +++ b/common/src/main/res/values-es-rMX/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rMX/strings_jetpack.xml b/common/src/main/res/values-es-rMX/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rMX/strings_jetpack.xml +++ b/common/src/main/res/values-es-rMX/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rNI/strings.xml b/common/src/main/res/values-es-rNI/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rNI/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rNI/strings_gamenames.xml b/common/src/main/res/values-es-rNI/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rNI/strings_gamenames.xml +++ b/common/src/main/res/values-es-rNI/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rNI/strings_invite.xml b/common/src/main/res/values-es-rNI/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rNI/strings_invite.xml +++ b/common/src/main/res/values-es-rNI/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rNI/strings_jetpack.xml b/common/src/main/res/values-es-rNI/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rNI/strings_jetpack.xml +++ b/common/src/main/res/values-es-rNI/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rPA/strings.xml b/common/src/main/res/values-es-rPA/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rPA/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rPA/strings_gamenames.xml b/common/src/main/res/values-es-rPA/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rPA/strings_gamenames.xml +++ b/common/src/main/res/values-es-rPA/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rPA/strings_invite.xml b/common/src/main/res/values-es-rPA/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rPA/strings_invite.xml +++ b/common/src/main/res/values-es-rPA/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rPA/strings_jetpack.xml b/common/src/main/res/values-es-rPA/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rPA/strings_jetpack.xml +++ b/common/src/main/res/values-es-rPA/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rPE/strings.xml b/common/src/main/res/values-es-rPE/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rPE/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rPE/strings_gamenames.xml b/common/src/main/res/values-es-rPE/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rPE/strings_gamenames.xml +++ b/common/src/main/res/values-es-rPE/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rPE/strings_invite.xml b/common/src/main/res/values-es-rPE/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rPE/strings_invite.xml +++ b/common/src/main/res/values-es-rPE/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rPE/strings_jetpack.xml b/common/src/main/res/values-es-rPE/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rPE/strings_jetpack.xml +++ b/common/src/main/res/values-es-rPE/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rPR/strings.xml b/common/src/main/res/values-es-rPR/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rPR/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rPR/strings_gamenames.xml b/common/src/main/res/values-es-rPR/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rPR/strings_gamenames.xml +++ b/common/src/main/res/values-es-rPR/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rPR/strings_invite.xml b/common/src/main/res/values-es-rPR/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rPR/strings_invite.xml +++ b/common/src/main/res/values-es-rPR/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rPR/strings_jetpack.xml b/common/src/main/res/values-es-rPR/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rPR/strings_jetpack.xml +++ b/common/src/main/res/values-es-rPR/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rPY/strings.xml b/common/src/main/res/values-es-rPY/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rPY/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rPY/strings_gamenames.xml b/common/src/main/res/values-es-rPY/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rPY/strings_gamenames.xml +++ b/common/src/main/res/values-es-rPY/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rPY/strings_invite.xml b/common/src/main/res/values-es-rPY/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rPY/strings_invite.xml +++ b/common/src/main/res/values-es-rPY/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rPY/strings_jetpack.xml b/common/src/main/res/values-es-rPY/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rPY/strings_jetpack.xml +++ b/common/src/main/res/values-es-rPY/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rSV/strings.xml b/common/src/main/res/values-es-rSV/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rSV/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rSV/strings_gamenames.xml b/common/src/main/res/values-es-rSV/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rSV/strings_gamenames.xml +++ b/common/src/main/res/values-es-rSV/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rSV/strings_invite.xml b/common/src/main/res/values-es-rSV/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rSV/strings_invite.xml +++ b/common/src/main/res/values-es-rSV/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rSV/strings_jetpack.xml b/common/src/main/res/values-es-rSV/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rSV/strings_jetpack.xml +++ b/common/src/main/res/values-es-rSV/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rUS/strings.xml b/common/src/main/res/values-es-rUS/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rUS/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rUS/strings_gamenames.xml b/common/src/main/res/values-es-rUS/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rUS/strings_gamenames.xml +++ b/common/src/main/res/values-es-rUS/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rUS/strings_invite.xml b/common/src/main/res/values-es-rUS/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rUS/strings_invite.xml +++ b/common/src/main/res/values-es-rUS/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rUS/strings_jetpack.xml b/common/src/main/res/values-es-rUS/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rUS/strings_jetpack.xml +++ b/common/src/main/res/values-es-rUS/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rUY/strings.xml b/common/src/main/res/values-es-rUY/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rUY/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rUY/strings_gamenames.xml b/common/src/main/res/values-es-rUY/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rUY/strings_gamenames.xml +++ b/common/src/main/res/values-es-rUY/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rUY/strings_invite.xml b/common/src/main/res/values-es-rUY/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rUY/strings_invite.xml +++ b/common/src/main/res/values-es-rUY/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rUY/strings_jetpack.xml b/common/src/main/res/values-es-rUY/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rUY/strings_jetpack.xml +++ b/common/src/main/res/values-es-rUY/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es-rVE/strings.xml b/common/src/main/res/values-es-rVE/strings.xml new file mode 100644 index 000000000..86c5660de --- /dev/null +++ b/common/src/main/res/values-es-rVE/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Santa está obsoleta. Visita la Play Store para actualizarla a la última versión. + diff --git a/common/src/main/res/values-es-rVE/strings_gamenames.xml b/common/src/main/res/values-es-rVE/strings_gamenames.xml index 844aca537..f6cfd3ff4 100644 --- a/common/src/main/res/values-es-rVE/strings_gamenames.xml +++ b/common/src/main/res/values-es-rVE/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Cuestionario sobre ciudades + Busca regalos diff --git a/common/src/main/res/values-es-rVE/strings_invite.xml b/common/src/main/res/values-es-rVE/strings_invite.xml index 74d876bc9..3b0ab37e4 100644 --- a/common/src/main/res/values-es-rVE/strings_invite.xml +++ b/common/src/main/res/values-es-rVE/strings_invite.xml @@ -1,6 +1,22 @@ + + Invita a tus amigos a seguir a Santa con Google - Prueba la app de Sigue a Santa y mira cómo vuela por todo el mundo. + Prueba la app de Sigue a Santa y acompáñalo por todo el mundo. Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme? diff --git a/common/src/main/res/values-es-rVE/strings_jetpack.xml b/common/src/main/res/values-es-rVE/strings_jetpack.xml index d30a26cd7..ee29fa1b1 100644 --- a/common/src/main/res/values-es-rVE/strings_jetpack.xml +++ b/common/src/main/res/values-es-rVE/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ¡Accede para desbloquear logros y publicar tu puntuación! Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-es/strings.xml b/common/src/main/res/values-es/strings.xml new file mode 100644 index 000000000..ce6498714 --- /dev/null +++ b/common/src/main/res/values-es/strings.xml @@ -0,0 +1,21 @@ + + + + Volver al mapa + Volver a la aldea + Esta versión de Sigue a Papá Noel no es la más reciente. Ve a Play Store para actualizar la aplicación. + diff --git a/common/src/main/res/values-es/strings_gamenames.xml b/common/src/main/res/values-es/strings_gamenames.xml index 02d7c389b..7ecd33f5b 100644 --- a/common/src/main/res/values-es/strings_gamenames.xml +++ b/common/src/main/res/values-es/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Juego de las ciudades + Atrapa el regalo diff --git a/common/src/main/res/values-es/strings_invite.xml b/common/src/main/res/values-es/strings_invite.xml index b7565d9ec..693715703 100644 --- a/common/src/main/res/values-es/strings_invite.xml +++ b/common/src/main/res/values-es/strings_invite.xml @@ -1,4 +1,20 @@ + + Invita a tus amigos a seguir a Papá Noel con Google ¡Prueba Sigue a Papá Noel y acompáñalo virtualmente por todo el mundo! diff --git a/common/src/main/res/values-es/strings_jetpack.xml b/common/src/main/res/values-es/strings_jetpack.xml index 5328045ee..d6fbafc7e 100644 --- a/common/src/main/res/values-es/strings_jetpack.xml +++ b/common/src/main/res/values-es/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Inicia sesión para desbloquear logros y publicar tu puntuación. Volver a jugar - Puntuación + Volver al mapa + PUNTUACIÓN + Volver al mapa diff --git a/common/src/main/res/values-et/strings.xml b/common/src/main/res/values-et/strings.xml new file mode 100644 index 000000000..deaf5a1cd --- /dev/null +++ b/common/src/main/res/values-et/strings.xml @@ -0,0 +1,21 @@ + + + + Tagasi kaardirežiimi + Tagasi külla + See Santa Trackeri versioon on aegunud. Uusima versiooni leiate Google Play poest. + diff --git a/common/src/main/res/values-et/strings_gamenames.xml b/common/src/main/res/values-et/strings_gamenames.xml index 89f4e4405..786f4edd5 100644 --- a/common/src/main/res/values-et/strings_gamenames.xml +++ b/common/src/main/res/values-et/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Nätsupall - Mälu - Haldja rakettranits - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball\'i mäng - Snowdown + Nätsupall + Mälu + Haldja rakettranits + Rocket Sleigh + Dasher Dancer + Snowdown + Linnaviktoriin + Kingiseiklus diff --git a/common/src/main/res/values-et/strings_invite.xml b/common/src/main/res/values-et/strings_invite.xml index 215ed9f4a..32a8e61d5 100644 --- a/common/src/main/res/values-et/strings_invite.xml +++ b/common/src/main/res/values-et/strings_invite.xml @@ -1,4 +1,20 @@ + + Kutsuge sõbrad Google\'iga jõuluvana jälgima Proovige rakendust Santa Tracker ja vaadake, kuidas jõuluvana ümber maailma lendab! diff --git a/common/src/main/res/values-et/strings_jetpack.xml b/common/src/main/res/values-et/strings_jetpack.xml index ba21b662f..f16c7a499 100644 --- a/common/src/main/res/values-et/strings_jetpack.xml +++ b/common/src/main/res/values-et/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Registreeruge, et saavutusi püüda ja oma skoore postitada! Mängi uuesti - Skoor + Tagasi kaardi juurde + TULEMUS + Tagasi kaardi juurde diff --git a/common/src/main/res/values-fi/strings.xml b/common/src/main/res/values-fi/strings.xml new file mode 100644 index 000000000..26de43c46 --- /dev/null +++ b/common/src/main/res/values-fi/strings.xml @@ -0,0 +1,21 @@ + + + + Takaisin karttaan + Takaisin kylään + Tämä Joulupukin jäljittimen versio on vanhentunut. Päivitä uusimpaan versioon Play Kaupassa. + diff --git a/common/src/main/res/values-fi/strings_gamenames.xml b/common/src/main/res/values-fi/strings_gamenames.xml index 38358085d..8a0ad6dcf 100644 --- a/common/src/main/res/values-fi/strings_gamenames.xml +++ b/common/src/main/res/values-fi/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Muistipeli - Tontturakettireppu - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball-peli - Snowdown + Gumball + Muistipeli + Tontturakettireppu + Rocket Sleigh + Dasher Dancer + Snowdown + Kaupunkivisa + Lahjaseikkailu diff --git a/common/src/main/res/values-fi/strings_invite.xml b/common/src/main/res/values-fi/strings_invite.xml index d3a2abe95..d6f5a4296 100644 --- a/common/src/main/res/values-fi/strings_invite.xml +++ b/common/src/main/res/values-fi/strings_invite.xml @@ -1,4 +1,20 @@ + + Kutsu ystäväsi seuraamaan pukin matkaa Googlen kanssa Kokeile Santa Trackeria ja seuraa pukin matkaa maailman ympäri. diff --git a/common/src/main/res/values-fi/strings_jetpack.xml b/common/src/main/res/values-fi/strings_jetpack.xml index a77b95cd5..ee33dbd4f 100644 --- a/common/src/main/res/values-fi/strings_jetpack.xml +++ b/common/src/main/res/values-fi/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Kirjaudu sisään, niin voit avata saavutuksia ja julkaista tuloksesi. Pelaa uudelleen - Pisteet + Takaisin karttaan + PISTEET + Takaisin karttaan diff --git a/common/src/main/res/values-fil/strings.xml b/common/src/main/res/values-fil/strings.xml new file mode 100644 index 000000000..b79cacce8 --- /dev/null +++ b/common/src/main/res/values-fil/strings.xml @@ -0,0 +1,21 @@ + + + + Bumalik sa mapa + Bumalik sa village + Luma na ang bersyong ito ng Santa Tracker. Pakibisita ang Play Store upang makapag-update sa pinakabagong bersyon. + diff --git a/common/src/main/res/values-fil/strings_gamenames.xml b/common/src/main/res/values-fil/strings_gamenames.xml index 53e834857..21d77d782 100644 --- a/common/src/main/res/values-fil/strings_gamenames.xml +++ b/common/src/main/res/values-fil/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Larong Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-fil/strings_invite.xml b/common/src/main/res/values-fil/strings_invite.xml index ad736646d..3d5b566be 100644 --- a/common/src/main/res/values-fil/strings_invite.xml +++ b/common/src/main/res/values-fil/strings_invite.xml @@ -1,4 +1,20 @@ + + Imbitahan ang iyong mga kaibigan na subaybayan si Santa sa Google Subukan ang Santa Tracker at panoorin ang paglipad ni Santa sa buong mundo! diff --git a/common/src/main/res/values-fil/strings_jetpack.xml b/common/src/main/res/values-fil/strings_jetpack.xml index 0723cba66..2588c5142 100644 --- a/common/src/main/res/values-fil/strings_jetpack.xml +++ b/common/src/main/res/values-fil/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Mag-sign in upang mai-unlock ang mga achievement at mai-post ang iyong score! Maglaro Muli - Score + Bumalik sa Mapa + SCORE + Bumalik sa mapa diff --git a/common/src/main/res/values-fr-rCA/strings.xml b/common/src/main/res/values-fr-rCA/strings.xml new file mode 100644 index 000000000..46e217406 --- /dev/null +++ b/common/src/main/res/values-fr-rCA/strings.xml @@ -0,0 +1,21 @@ + + + + Revenir à la carte + Revenir au village + Cette version de Sur les traces du père Noël est périmée. Veuillez visiter la boutique Google Play Store pour obtenir la plus récente version. + diff --git a/common/src/main/res/values-fr-rCA/strings_gamenames.xml b/common/src/main/res/values-fr-rCA/strings_gamenames.xml index 8a261a833..8922a10b3 100644 --- a/common/src/main/res/values-fr-rCA/strings_gamenames.xml +++ b/common/src/main/res/values-fr-rCA/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Jeu Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Quiz urbain + Quête de cadeaux diff --git a/common/src/main/res/values-fr-rCA/strings_invite.xml b/common/src/main/res/values-fr-rCA/strings_invite.xml index 741c77da5..ae571783c 100644 --- a/common/src/main/res/values-fr-rCA/strings_invite.xml +++ b/common/src/main/res/values-fr-rCA/strings_invite.xml @@ -1,4 +1,20 @@ + + Invite tes amis à suivre le père Noël avec Google Essayez l\'application Sur les traces du père Noël et suivez le père Noël à travers le monde! diff --git a/common/src/main/res/values-fr-rCA/strings_jetpack.xml b/common/src/main/res/values-fr-rCA/strings_jetpack.xml index cf7a0fed6..020f4ef56 100644 --- a/common/src/main/res/values-fr-rCA/strings_jetpack.xml +++ b/common/src/main/res/values-fr-rCA/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Connectez-vous pour débloquer vos réussites et afficher votre score! Jouer de nouveau - Score + Revenir à la carte + POINTAGE + Revenir à la carte diff --git a/common/src/main/res/values-fr-rCH/strings.xml b/common/src/main/res/values-fr-rCH/strings.xml new file mode 100644 index 000000000..a28283a0d --- /dev/null +++ b/common/src/main/res/values-fr-rCH/strings.xml @@ -0,0 +1,21 @@ + + + + Retour à la carte + Retour au village + Cette version du jeu \"Sur la piste du père Noël\" est obsolète. Veuillez accéder au Play Store pour télécharger la dernière version. + diff --git a/common/src/main/res/values-fr-rCH/strings_gamenames.xml b/common/src/main/res/values-fr-rCH/strings_gamenames.xml index 97d7d7ef0..c78bd1054 100644 --- a/common/src/main/res/values-fr-rCH/strings_gamenames.xml +++ b/common/src/main/res/values-fr-rCH/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Jeu Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Le questionnaire des villes + La quête des cadeaux diff --git a/common/src/main/res/values-fr-rCH/strings_invite.xml b/common/src/main/res/values-fr-rCH/strings_invite.xml index 684b63131..a584c72ac 100644 --- a/common/src/main/res/values-fr-rCH/strings_invite.xml +++ b/common/src/main/res/values-fr-rCH/strings_invite.xml @@ -1,6 +1,22 @@ + + Invitez vos amis à suivre le père Noël avec Google - Essaie l\'application Santa Tracker pour suivre la tournée du père Noël à travers le monde ! + Essaie l\'application Sur la piste du père Noël pour suivre la tournée du père Noël à travers le monde ! J\'ai atteint un score de %1$d points au jeu %2$s avec les lutins du programme Santa Tracker de Google. Parviendras-tu à me battre ? diff --git a/common/src/main/res/values-fr-rCH/strings_jetpack.xml b/common/src/main/res/values-fr-rCH/strings_jetpack.xml index a28ff4471..b590c6fd5 100644 --- a/common/src/main/res/values-fr-rCH/strings_jetpack.xml +++ b/common/src/main/res/values-fr-rCH/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Connectez-vous pour débloquer vos exploits et publier vos scores ! Rejouer - Résultats + Revenir à la carte + SCORE + Retour à la carte diff --git a/common/src/main/res/values-fr/strings.xml b/common/src/main/res/values-fr/strings.xml new file mode 100644 index 000000000..a28283a0d --- /dev/null +++ b/common/src/main/res/values-fr/strings.xml @@ -0,0 +1,21 @@ + + + + Retour à la carte + Retour au village + Cette version du jeu \"Sur la piste du père Noël\" est obsolète. Veuillez accéder au Play Store pour télécharger la dernière version. + diff --git a/common/src/main/res/values-fr/strings_gamenames.xml b/common/src/main/res/values-fr/strings_gamenames.xml index 97d7d7ef0..c78bd1054 100644 --- a/common/src/main/res/values-fr/strings_gamenames.xml +++ b/common/src/main/res/values-fr/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Jeu Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Le questionnaire des villes + La quête des cadeaux diff --git a/common/src/main/res/values-fr/strings_invite.xml b/common/src/main/res/values-fr/strings_invite.xml index 684b63131..a584c72ac 100644 --- a/common/src/main/res/values-fr/strings_invite.xml +++ b/common/src/main/res/values-fr/strings_invite.xml @@ -1,6 +1,22 @@ + + Invitez vos amis à suivre le père Noël avec Google - Essaie l\'application Santa Tracker pour suivre la tournée du père Noël à travers le monde ! + Essaie l\'application Sur la piste du père Noël pour suivre la tournée du père Noël à travers le monde ! J\'ai atteint un score de %1$d points au jeu %2$s avec les lutins du programme Santa Tracker de Google. Parviendras-tu à me battre ? diff --git a/common/src/main/res/values-fr/strings_jetpack.xml b/common/src/main/res/values-fr/strings_jetpack.xml index a28ff4471..b590c6fd5 100644 --- a/common/src/main/res/values-fr/strings_jetpack.xml +++ b/common/src/main/res/values-fr/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Connectez-vous pour débloquer vos exploits et publier vos scores ! Rejouer - Résultats + Revenir à la carte + SCORE + Retour à la carte diff --git a/common/src/main/res/values-gsw/strings.xml b/common/src/main/res/values-gsw/strings.xml new file mode 100644 index 000000000..34e7cbd5d --- /dev/null +++ b/common/src/main/res/values-gsw/strings.xml @@ -0,0 +1,21 @@ + + + + Zurück zur Karte + Zurück zum Dorf + Diese Version von \"Auf den Spuren des Weihnachtsmanns\" ist abgelaufen. Du kannst sie im Play Store aktualisieren. + diff --git a/common/src/main/res/values-gsw/strings_gamenames.xml b/common/src/main/res/values-gsw/strings_gamenames.xml index bc79191c0..217efc408 100644 --- a/common/src/main/res/values-gsw/strings_gamenames.xml +++ b/common/src/main/res/values-gsw/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball Game - Snowdown + Gumball + Memory + Elf Jetpack + Raketenflug + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-gsw/strings_invite.xml b/common/src/main/res/values-gsw/strings_invite.xml index 931606d08..af70d7e32 100644 --- a/common/src/main/res/values-gsw/strings_invite.xml +++ b/common/src/main/res/values-gsw/strings_invite.xml @@ -1,4 +1,20 @@ + + Freunde dazu einladen, die Reise des Weihnachtsmanns mit Google zu verfolgen Begib dich auf die Spuren des Weihnachtsmanns und verfolge ihn auf seinem Flug um die Welt! diff --git a/common/src/main/res/values-gsw/strings_jetpack.xml b/common/src/main/res/values-gsw/strings_jetpack.xml index 94ecb86e2..32a746708 100644 --- a/common/src/main/res/values-gsw/strings_jetpack.xml +++ b/common/src/main/res/values-gsw/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten! Neues Spiel - Punktzahl + Zurück zur Karte + PUNKTE + Zurück zur Karte diff --git a/common/src/main/res/values-hdpi/dimens.xml b/common/src/main/res/values-hdpi/dimens.xml index 800ae1042..db5ee012d 100644 --- a/common/src/main/res/values-hdpi/dimens.xml +++ b/common/src/main/res/values-hdpi/dimens.xml @@ -1,3 +1,19 @@ + + 8dp diff --git a/common/src/main/res/values-hr/strings.xml b/common/src/main/res/values-hr/strings.xml new file mode 100644 index 000000000..28997f8ef --- /dev/null +++ b/common/src/main/res/values-hr/strings.xml @@ -0,0 +1,21 @@ + + + + Natrag na kartu + Natrag u selo + Ova verzija igre Slijedi Djeda Božićnjaka zastarjela je. Posjeti Trgovinu Play i nadogradi je na najnoviju verziju. + diff --git a/common/src/main/res/values-hr/strings_gamenames.xml b/common/src/main/res/values-hr/strings_gamenames.xml index 02b472a3f..e17a1d389 100644 --- a/common/src/main/res/values-hr/strings_gamenames.xml +++ b/common/src/main/res/values-hr/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Igra pamćenja - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Igra Snowball - Snowdown + Gumball + Igra pamćenja + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Kviz o gradovima + Lov na darove diff --git a/common/src/main/res/values-hr/strings_invite.xml b/common/src/main/res/values-hr/strings_invite.xml index ad350bc43..f34818fb3 100644 --- a/common/src/main/res/values-hr/strings_invite.xml +++ b/common/src/main/res/values-hr/strings_invite.xml @@ -1,4 +1,20 @@ + + Pozovite prijatelje i zajedno pratite Djeda Božićnjaka uz Google Isprobajte igru Slijedi Djeda Božićnjaka i pratite Djedicu u njegovu letu širom svijeta! diff --git a/common/src/main/res/values-hr/strings_jetpack.xml b/common/src/main/res/values-hr/strings_jetpack.xml index df14efe57..b158ba9f7 100644 --- a/common/src/main/res/values-hr/strings_jetpack.xml +++ b/common/src/main/res/values-hr/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Prijavite se da biste otključali uspjehe i objavili rezultat! Igraj ponovo - Rezultat + Natrag na kartu + REZULTAT + Natrag na kartu diff --git a/common/src/main/res/values-id/strings.xml b/common/src/main/res/values-id/strings.xml new file mode 100644 index 000000000..ea5473ba0 --- /dev/null +++ b/common/src/main/res/values-id/strings.xml @@ -0,0 +1,21 @@ + + + + Balik ke peta + Balik ke desa + Pelacak Sinterklas versi ini sudah usang. Kunjungi Play Store untuk update ke versi terbaru. + diff --git a/common/src/main/res/values-id/strings_gamenames.xml b/common/src/main/res/values-id/strings_gamenames.xml index c99fae438..eb1b7b3f1 100644 --- a/common/src/main/res/values-id/strings_gamenames.xml +++ b/common/src/main/res/values-id/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Game Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Kuis Tebak Kota + Cari Hadiah diff --git a/common/src/main/res/values-id/strings_invite.xml b/common/src/main/res/values-id/strings_invite.xml index 16abd10be..9622d1f36 100644 --- a/common/src/main/res/values-id/strings_invite.xml +++ b/common/src/main/res/values-id/strings_invite.xml @@ -1,4 +1,20 @@ + + Undang teman Anda untuk melacak Sinterklas dengan Google Coba Pelacak Sinterklas dan tonton Sinterklas terbang ke seluruh dunia! diff --git a/common/src/main/res/values-id/strings_jetpack.xml b/common/src/main/res/values-id/strings_jetpack.xml index ee61b829c..06f2d5567 100644 --- a/common/src/main/res/values-id/strings_jetpack.xml +++ b/common/src/main/res/values-id/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Masuk untuk membuka pencapaian dan mengeposkan skor! Main Lagi - Skor + Balik ke Peta + SKOR + Balik ke peta diff --git a/common/src/main/res/values-in/strings.xml b/common/src/main/res/values-in/strings.xml new file mode 100644 index 000000000..ea5473ba0 --- /dev/null +++ b/common/src/main/res/values-in/strings.xml @@ -0,0 +1,21 @@ + + + + Balik ke peta + Balik ke desa + Pelacak Sinterklas versi ini sudah usang. Kunjungi Play Store untuk update ke versi terbaru. + diff --git a/common/src/main/res/values-in/strings_gamenames.xml b/common/src/main/res/values-in/strings_gamenames.xml index c99fae438..eb1b7b3f1 100644 --- a/common/src/main/res/values-in/strings_gamenames.xml +++ b/common/src/main/res/values-in/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Game Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Kuis Tebak Kota + Cari Hadiah diff --git a/common/src/main/res/values-in/strings_invite.xml b/common/src/main/res/values-in/strings_invite.xml index 16abd10be..9622d1f36 100644 --- a/common/src/main/res/values-in/strings_invite.xml +++ b/common/src/main/res/values-in/strings_invite.xml @@ -1,4 +1,20 @@ + + Undang teman Anda untuk melacak Sinterklas dengan Google Coba Pelacak Sinterklas dan tonton Sinterklas terbang ke seluruh dunia! diff --git a/common/src/main/res/values-in/strings_jetpack.xml b/common/src/main/res/values-in/strings_jetpack.xml index ee61b829c..06f2d5567 100644 --- a/common/src/main/res/values-in/strings_jetpack.xml +++ b/common/src/main/res/values-in/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Masuk untuk membuka pencapaian dan mengeposkan skor! Main Lagi - Skor + Balik ke Peta + SKOR + Balik ke peta diff --git a/common/src/main/res/values-it/strings.xml b/common/src/main/res/values-it/strings.xml new file mode 100644 index 000000000..4e5a7e3ce --- /dev/null +++ b/common/src/main/res/values-it/strings.xml @@ -0,0 +1,21 @@ + + + + Torna alla mappa + Torna al villaggio + Questa versione di Segui Babbo Natale non è aggiornata. Visita il Play Store per effettuare l\'aggiornamento alla versione più recente. + diff --git a/common/src/main/res/values-it/strings_gamenames.xml b/common/src/main/res/values-it/strings_gamenames.xml index 02d7c389b..c6d403b72 100644 --- a/common/src/main/res/values-it/strings_gamenames.xml +++ b/common/src/main/res/values-it/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Pallina di gomma + Memory + Elf Jetpack + Razzo di natale + Ballo di Natale + Palle di neve + Indovina la città + Caccia ai regali diff --git a/common/src/main/res/values-it/strings_invite.xml b/common/src/main/res/values-it/strings_invite.xml index 84a1141bc..54a60f535 100644 --- a/common/src/main/res/values-it/strings_invite.xml +++ b/common/src/main/res/values-it/strings_invite.xml @@ -1,4 +1,20 @@ + + Invita i tuoi amici a seguire Babbo Natale con Google Prova l\'app Segui Babbo Natale e guardalo mentre vola intorno al mondo. diff --git a/common/src/main/res/values-it/strings_jetpack.xml b/common/src/main/res/values-it/strings_jetpack.xml index 9f2727738..412a95415 100644 --- a/common/src/main/res/values-it/strings_jetpack.xml +++ b/common/src/main/res/values-it/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Accedi per sbloccare i risultati e pubblicare il tuo punteggio. Gioca ancora - Punteggio + Torna alla mappa + PUNTEGGIO + Torna alla mappa diff --git a/common/src/main/res/values-ja/strings.xml b/common/src/main/res/values-ja/strings.xml new file mode 100644 index 000000000..63ba0d80e --- /dev/null +++ b/common/src/main/res/values-ja/strings.xml @@ -0,0 +1,21 @@ + + + + 地図に戻る + 村へ戻る + お使いの「サンタを追いかけよう」は、最新版ではありません。Google Play ストアで最新バージョンを入手してください。 + diff --git a/common/src/main/res/values-ja/strings_gamenames.xml b/common/src/main/res/values-ja/strings_gamenames.xml index 02d7c389b..8c809234b 100644 --- a/common/src/main/res/values-ja/strings_gamenames.xml +++ b/common/src/main/res/values-ja/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + 都市クイズ + プレゼント クエスト diff --git a/common/src/main/res/values-ja/strings_invite.xml b/common/src/main/res/values-ja/strings_invite.xml index 10f3862cc..beb3a0a4a 100644 --- a/common/src/main/res/values-ja/strings_invite.xml +++ b/common/src/main/res/values-ja/strings_invite.xml @@ -1,4 +1,20 @@ + + Google の「サンタを追いかけよう」に友だちを招待 「サンタを追いかけよう」で世界中を飛び回るサンタさんを見よう! diff --git a/common/src/main/res/values-ja/strings_jetpack.xml b/common/src/main/res/values-ja/strings_jetpack.xml index 05f6fb0a7..b7ce9c7c8 100644 --- a/common/src/main/res/values-ja/strings_jetpack.xml +++ b/common/src/main/res/values-ja/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ログインしたら、結果を開放してスコアを投稿しよう! もう一度プレイ + 地図に戻る スコア + 地図に戻る diff --git a/common/src/main/res/values-ko/strings.xml b/common/src/main/res/values-ko/strings.xml new file mode 100644 index 000000000..e4918e77a --- /dev/null +++ b/common/src/main/res/values-ko/strings.xml @@ -0,0 +1,21 @@ + + + + 지도로 돌아가기 + 마을로 돌아가기 + 산타 추적기의 버전이 오래되었습니다. Play 스토어를 방문하여 최신 버전으로 업데이트하세요. + diff --git a/common/src/main/res/values-ko/strings_gamenames.xml b/common/src/main/res/values-ko/strings_gamenames.xml index 2865e0004..80a3fcb53 100644 --- a/common/src/main/res/values-ko/strings_gamenames.xml +++ b/common/src/main/res/values-ko/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - 풍선껌 - 기억력 - 제트 추진 엘프 - 스노우글로브 - 로켓 썰매 - 대셔 댄서 - 눈싸움 게임 - 최후의 눈싸움 결전 + 풍선껌 + 기억력 + 제트 추진 엘프 + 로켓 썰매 + 대셔 댄서 + 최후의 눈싸움 결전 + 도시 퀴즈 + 선물 찾기 diff --git a/common/src/main/res/values-ko/strings_invite.xml b/common/src/main/res/values-ko/strings_invite.xml index a84a61ddb..56847a6c1 100644 --- a/common/src/main/res/values-ko/strings_invite.xml +++ b/common/src/main/res/values-ko/strings_invite.xml @@ -1,4 +1,20 @@ + + 친구를 초대하여 Google에서 산타 추적하기 산타 추적기를 사용해 전 세계를 도는 산타의 여정을 지켜봐 주세요. diff --git a/common/src/main/res/values-ko/strings_jetpack.xml b/common/src/main/res/values-ko/strings_jetpack.xml index 0919deb72..d6cf68636 100644 --- a/common/src/main/res/values-ko/strings_jetpack.xml +++ b/common/src/main/res/values-ko/strings_jetpack.xml @@ -1,6 +1,24 @@ + + 로그인하여 업적을 달성하고 점수를 게시해 보세요. 다시 하기 + 지도로 돌아가기 점수 + 지도로 돌아가기 diff --git a/common/src/main/res/values-ln/strings.xml b/common/src/main/res/values-ln/strings.xml new file mode 100644 index 000000000..a28283a0d --- /dev/null +++ b/common/src/main/res/values-ln/strings.xml @@ -0,0 +1,21 @@ + + + + Retour à la carte + Retour au village + Cette version du jeu \"Sur la piste du père Noël\" est obsolète. Veuillez accéder au Play Store pour télécharger la dernière version. + diff --git a/common/src/main/res/values-ln/strings_gamenames.xml b/common/src/main/res/values-ln/strings_gamenames.xml index 97d7d7ef0..c78bd1054 100644 --- a/common/src/main/res/values-ln/strings_gamenames.xml +++ b/common/src/main/res/values-ln/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Jeu Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Le questionnaire des villes + La quête des cadeaux diff --git a/common/src/main/res/values-ln/strings_invite.xml b/common/src/main/res/values-ln/strings_invite.xml index 684b63131..a584c72ac 100644 --- a/common/src/main/res/values-ln/strings_invite.xml +++ b/common/src/main/res/values-ln/strings_invite.xml @@ -1,6 +1,22 @@ + + Invitez vos amis à suivre le père Noël avec Google - Essaie l\'application Santa Tracker pour suivre la tournée du père Noël à travers le monde ! + Essaie l\'application Sur la piste du père Noël pour suivre la tournée du père Noël à travers le monde ! J\'ai atteint un score de %1$d points au jeu %2$s avec les lutins du programme Santa Tracker de Google. Parviendras-tu à me battre ? diff --git a/common/src/main/res/values-ln/strings_jetpack.xml b/common/src/main/res/values-ln/strings_jetpack.xml index a28ff4471..b590c6fd5 100644 --- a/common/src/main/res/values-ln/strings_jetpack.xml +++ b/common/src/main/res/values-ln/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Connectez-vous pour débloquer vos exploits et publier vos scores ! Rejouer - Résultats + Revenir à la carte + SCORE + Retour à la carte diff --git a/common/src/main/res/values-lt/strings.xml b/common/src/main/res/values-lt/strings.xml new file mode 100644 index 000000000..7b9732b80 --- /dev/null +++ b/common/src/main/res/values-lt/strings.xml @@ -0,0 +1,21 @@ + + + + Grįžti į žemėlapį + Grįžti į kaimą + Ši Kalėdų Senelio kelionės versija pasenusi. Apsilankykite „Play“ parduotuvėje ir atnaujinkite į naujausią versiją. + diff --git a/common/src/main/res/values-lt/strings_gamenames.xml b/common/src/main/res/values-lt/strings_gamenames.xml index 1ac5dea40..c698b0615 100644 --- a/common/src/main/res/values-lt/strings_gamenames.xml +++ b/common/src/main/res/values-lt/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Žaidimas „Snowball“ - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Miestų viktorina + Dovanų ieškynės diff --git a/common/src/main/res/values-lt/strings_invite.xml b/common/src/main/res/values-lt/strings_invite.xml index cb43cba44..3aefb3e38 100644 --- a/common/src/main/res/values-lt/strings_invite.xml +++ b/common/src/main/res/values-lt/strings_invite.xml @@ -1,4 +1,20 @@ + + Pakvieskite draugus stebėti Kalėdų Senelį „Google“ Išbandykite „Santa Tracker“ ir pamatysite, kaip Kalėdų Senelis skrenda per pasaulį! diff --git a/common/src/main/res/values-lt/strings_jetpack.xml b/common/src/main/res/values-lt/strings_jetpack.xml index ce384530a..11eb7a394 100644 --- a/common/src/main/res/values-lt/strings_jetpack.xml +++ b/common/src/main/res/values-lt/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Prisijunkite, jei norite atrakinti laimėjimus ir paskelbti savo rezultatą! Žaisti dar kartą - Rezultatas + Grįžti į žemėlapį + REZULTATAS + Grįžti į žemėlapį diff --git a/common/src/main/res/values-lv/strings.xml b/common/src/main/res/values-lv/strings.xml new file mode 100644 index 000000000..0ae5e5b53 --- /dev/null +++ b/common/src/main/res/values-lv/strings.xml @@ -0,0 +1,21 @@ + + + + Atgriezties kartē + Atgriezties ciematā + Šī lietotnes Ziemassvētku vecīša ceļojums versija ir novecojusi. Lūdzu, apmeklējiet Play veikalu, lai iegūtu jaunāko versiju. + diff --git a/common/src/main/res/values-lv/strings_gamenames.xml b/common/src/main/res/values-lv/strings_gamenames.xml index 1242da71d..33b50ef38 100644 --- a/common/src/main/res/values-lv/strings_gamenames.xml +++ b/common/src/main/res/values-lv/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball spēle - Atmiņas spēle - Elf Jetpack spēle - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Gumball spēle + Atmiņas spēle + Elf Jetpack spēle + Rocket Sleigh + Dasher Dancer + Snowdown + Pilsētu viktorīnas spēle (City Quiz) + Dāvanu meklēšanas spēle (Present Quest) diff --git a/common/src/main/res/values-lv/strings_invite.xml b/common/src/main/res/values-lv/strings_invite.xml index 8854d77bc..cb6423681 100644 --- a/common/src/main/res/values-lv/strings_invite.xml +++ b/common/src/main/res/values-lv/strings_invite.xml @@ -1,4 +1,20 @@ + + Uzaicinājums draugiem sekot Ziemassvētku vecītim pakalpojumā Google Izmēģiniet Ziemassvētku vecīša ceļojumu un skatieties, kā Ziemassvētku vecītis aplido apkārt visai pasaulei! diff --git a/common/src/main/res/values-lv/strings_jetpack.xml b/common/src/main/res/values-lv/strings_jetpack.xml index 3fed2efa9..ef7f57f82 100644 --- a/common/src/main/res/values-lv/strings_jetpack.xml +++ b/common/src/main/res/values-lv/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Pierakstieties, lai atbloķētu sasniegumus un izliktu savu rezultātu! Spēlēt vēlreiz - Rezultāts + Atgriezties kartē + REZULTĀTS + Atgriezties kartē diff --git a/common/src/main/res/values-ml/strings.xml b/common/src/main/res/values-ml/strings.xml new file mode 100644 index 000000000..6e5f8919e --- /dev/null +++ b/common/src/main/res/values-ml/strings.xml @@ -0,0 +1,21 @@ + + + + മാപ്പിലേക്ക് മടങ്ങുക + ഗ്രാമത്തിലേക്ക് മടങ്ങുക + ഈ സാന്ത ട്രാക്കർ പതിപ്പ് കാലഹരണപ്പെട്ടതാണ്. ഏറ്റവും പുതിയ പതിപ്പിലേക്ക് അപ്‌ഡേറ്റ് ചെയ്യാൻ \'പ്ലേ സ്റ്റോർ\' സന്ദർശിക്കുക. + diff --git a/common/src/main/res/values-ml/strings_gamenames.xml b/common/src/main/res/values-ml/strings_gamenames.xml index 74de7aee7..4dc58c05f 100644 --- a/common/src/main/res/values-ml/strings_gamenames.xml +++ b/common/src/main/res/values-ml/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - ഗംബോൾ - മെമ്മറി - എൽഫ് ജെറ്റ്‌പാക്ക് - സ്നോഗ്ലോബ് - റോക്കറ്റ് ഹിമവണ്ടി - ഡാഷർ ഡാൻസർ - സ്നോബോൾ ഗെയിം - സ്നോഡൗൺ + ഗംബോൾ + മെമ്മറി + എൽഫ് ജെറ്റ്‌പാക്ക് + റോക്കറ്റ് ഹിമവണ്ടി + ഡാഷർ ഡാൻസർ + സ്നോഡൗൺ + സിറ്റി ക്വിസ് + പ്രസന്റ് ക്വസ്റ്റ് diff --git a/common/src/main/res/values-ml/strings_invite.xml b/common/src/main/res/values-ml/strings_invite.xml index c54c246e9..c871f6569 100644 --- a/common/src/main/res/values-ml/strings_invite.xml +++ b/common/src/main/res/values-ml/strings_invite.xml @@ -1,4 +1,20 @@ + + Google വഴി സാന്തയെ ട്രാക്കുചെയ്യുന്നതിന് സുഹൃത്തുക്കളെ ക്ഷണിക്കുക സാന്ത ട്രാക്കർ പരീക്ഷിച്ചുകൊണ്ട് ലോകമെമ്പാടുമുള്ള സാന്തയുടെ സഞ്ചാരം കാണുക! diff --git a/common/src/main/res/values-ml/strings_jetpack.xml b/common/src/main/res/values-ml/strings_jetpack.xml index fb73aba23..911bae261 100644 --- a/common/src/main/res/values-ml/strings_jetpack.xml +++ b/common/src/main/res/values-ml/strings_jetpack.xml @@ -1,6 +1,24 @@ + + നേട്ടങ്ങൾ അൺലോക്കുചെയ്യാനും നിങ്ങളുടെ സ്കോർ പോസ്റ്റ് ചെയ്യാനും സൈൻ ഇൻ ചെയ്യുക! വീണ്ടും കളിക്കുക + മാപ്പിലേക്ക് മടങ്ങുക സ്‌കോർ + മാപ്പിലേക്ക് മടങ്ങുക diff --git a/common/src/main/res/values-mo/strings.xml b/common/src/main/res/values-mo/strings.xml new file mode 100644 index 000000000..2a02c6c70 --- /dev/null +++ b/common/src/main/res/values-mo/strings.xml @@ -0,0 +1,21 @@ + + + + Înapoi la hartă + Înapoi în sat + Această versiune a aplicației Pe urmele lui Moș Crăciun este învechită. Accesează Magazinul Google Play pentru cea mai nouă versiune. + diff --git a/common/src/main/res/values-mo/strings_gamenames.xml b/common/src/main/res/values-mo/strings_gamenames.xml index 41cc42d93..5e6af0942 100644 --- a/common/src/main/res/values-mo/strings_gamenames.xml +++ b/common/src/main/res/values-mo/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Jocul Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Sania-rachetă + Dansează cu Dasher + Bulgăreală + Găsește orașul + În căutarea cadourilor diff --git a/common/src/main/res/values-mo/strings_invite.xml b/common/src/main/res/values-mo/strings_invite.xml index 2fa2ba7f3..85b2be76b 100644 --- a/common/src/main/res/values-mo/strings_invite.xml +++ b/common/src/main/res/values-mo/strings_invite.xml @@ -1,6 +1,22 @@ + + - Invitați-vă prietenii să-l urmărească pe Moș Crăciun cu Google - Încercați Pe urmele lui Moș Crăciun și urmăriți-l pe Moș Crăciun cum călătorește în întreaga lume! - Am obținut un scor de %1$d jucând %2$s cu elfii, în Pe urmele lui Moș Crăciun de la Google. Mă puteți întrece? + Invită-ți prietenii să-l urmărească pe Moș Crăciun cu Google + Joacă Pe urmele lui Moș Crăciun și vezi pe unde călătorește Moș Crăciun în întreaga lume! + Am obținut un scor de %1$d jucând %2$s cu elfii, în Pe urmele lui Moș Crăciun de la Google. Mă poți întrece? diff --git a/common/src/main/res/values-mo/strings_jetpack.xml b/common/src/main/res/values-mo/strings_jetpack.xml index 909e54286..8da1aad5e 100644 --- a/common/src/main/res/values-mo/strings_jetpack.xml +++ b/common/src/main/res/values-mo/strings_jetpack.xml @@ -1,6 +1,24 @@ + + - Conectați-vă pentru a debloca realizările și pentru a vă posta scorul! - Jucați din nou - Scor + Conectează-te pentru a debloca realizările și pentru a-ți posta scorul! + Joacă din nou + Înapoi la hartă + SCOR + Înapoi la hartă diff --git a/common/src/main/res/values-nb/strings.xml b/common/src/main/res/values-nb/strings.xml new file mode 100644 index 000000000..b90aa3de2 --- /dev/null +++ b/common/src/main/res/values-nb/strings.xml @@ -0,0 +1,21 @@ + + + + Tilbake til kartet + Tilbake til landsbyen + Denne versjonen av Følg julenissen er utdatert. Gå til Play-butikken for å oppdatere til den nyeste versjonen. + diff --git a/common/src/main/res/values-nb/strings_gamenames.xml b/common/src/main/res/values-nb/strings_gamenames.xml index 02d7c389b..7059d7d4f 100644 --- a/common/src/main/res/values-nb/strings_gamenames.xml +++ b/common/src/main/res/values-nb/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Rulledrops + Memory + Elf Jetpack + Rakettsleden + Nissedans + Snøballkrig + Byquiz + Gavejakt diff --git a/common/src/main/res/values-nb/strings_invite.xml b/common/src/main/res/values-nb/strings_invite.xml index 06fb2db7a..e0c854846 100644 --- a/common/src/main/res/values-nb/strings_invite.xml +++ b/common/src/main/res/values-nb/strings_invite.xml @@ -1,6 +1,22 @@ + + - Inviter vennene dine til å følge julenissen med Google + Inviter vennene dine til å følge nissen med Google Følg julenissen, og se julenissen fly verden rundt! Jeg fikk %1$d poeng i %2$s-spillet med alvene i Følg julenissen fra Google. Kan du slå det? diff --git a/common/src/main/res/values-nb/strings_jetpack.xml b/common/src/main/res/values-nb/strings_jetpack.xml index 23283e7ef..f704c1c69 100644 --- a/common/src/main/res/values-nb/strings_jetpack.xml +++ b/common/src/main/res/values-nb/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Logg på for å låse opp prestasjoner og legge ut poengsummen din. Spill igjen - Poeng + Gå tilbake til kartet + POENG + Gå tilbake til kartet diff --git a/common/src/main/res/values-no/strings.xml b/common/src/main/res/values-no/strings.xml new file mode 100644 index 000000000..b90aa3de2 --- /dev/null +++ b/common/src/main/res/values-no/strings.xml @@ -0,0 +1,21 @@ + + + + Tilbake til kartet + Tilbake til landsbyen + Denne versjonen av Følg julenissen er utdatert. Gå til Play-butikken for å oppdatere til den nyeste versjonen. + diff --git a/common/src/main/res/values-no/strings_gamenames.xml b/common/src/main/res/values-no/strings_gamenames.xml index 02d7c389b..7059d7d4f 100644 --- a/common/src/main/res/values-no/strings_gamenames.xml +++ b/common/src/main/res/values-no/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Rulledrops + Memory + Elf Jetpack + Rakettsleden + Nissedans + Snøballkrig + Byquiz + Gavejakt diff --git a/common/src/main/res/values-no/strings_invite.xml b/common/src/main/res/values-no/strings_invite.xml index 06fb2db7a..e0c854846 100644 --- a/common/src/main/res/values-no/strings_invite.xml +++ b/common/src/main/res/values-no/strings_invite.xml @@ -1,6 +1,22 @@ + + - Inviter vennene dine til å følge julenissen med Google + Inviter vennene dine til å følge nissen med Google Følg julenissen, og se julenissen fly verden rundt! Jeg fikk %1$d poeng i %2$s-spillet med alvene i Følg julenissen fra Google. Kan du slå det? diff --git a/common/src/main/res/values-no/strings_jetpack.xml b/common/src/main/res/values-no/strings_jetpack.xml index 23283e7ef..f704c1c69 100644 --- a/common/src/main/res/values-no/strings_jetpack.xml +++ b/common/src/main/res/values-no/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Logg på for å låse opp prestasjoner og legge ut poengsummen din. Spill igjen - Poeng + Gå tilbake til kartet + POENG + Gå tilbake til kartet diff --git a/common/src/main/res/values-pl/strings.xml b/common/src/main/res/values-pl/strings.xml new file mode 100644 index 000000000..a4f308079 --- /dev/null +++ b/common/src/main/res/values-pl/strings.xml @@ -0,0 +1,21 @@ + + + + Wróć do mapy + Wróć do wioski + Ta wersja Trasy Świętego Mikołaja jest nieaktualna. Odwiedź Sklep Google Play, aby pobrać najnowszą wersję. + diff --git a/common/src/main/res/values-pl/strings_gamenames.xml b/common/src/main/res/values-pl/strings_gamenames.xml index 5104d6966..6757bfcd9 100644 --- a/common/src/main/res/values-pl/strings_gamenames.xml +++ b/common/src/main/res/values-pl/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Śnieżna kula - Sanie rakietowe - Fircyk i Tancerz - Gra Śnieżka - Śnieżne starcie + Gumball + Memory + Elf Jetpack + Sanie rakietowe + Fircyk i Tancerz + Śnieżne starcie + Miejski quiz + Wyprawa po prezenty diff --git a/common/src/main/res/values-pl/strings_invite.xml b/common/src/main/res/values-pl/strings_invite.xml index 403829439..df36c3352 100644 --- a/common/src/main/res/values-pl/strings_invite.xml +++ b/common/src/main/res/values-pl/strings_invite.xml @@ -1,6 +1,22 @@ + + - Zaproś znajomych do śledzenia Świętego Mikołaja w Google + Zaproś do śledzenia Mikołaja Dzięki aplikacji Trasa Świętego Mikołaja zobaczysz, jak Święty Mikołaj lata po całym świecie. Mój wynik w grze %2$s rozgrywanej z elfami w Google Santa Tracker to %1$d. Dasz radę mnie pokonać? diff --git a/common/src/main/res/values-pl/strings_jetpack.xml b/common/src/main/res/values-pl/strings_jetpack.xml index a2d3c0aae..3e5e74fa7 100644 --- a/common/src/main/res/values-pl/strings_jetpack.xml +++ b/common/src/main/res/values-pl/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Zaloguj się, aby odblokować osiągnięcia i opublikować swój wynik. Zagraj jeszcze raz - Wynik + Wróć do mapy + WYNIK + Wróć do mapy diff --git a/common/src/main/res/values-pt-rBR/strings.xml b/common/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 000000000..b586d8b3b --- /dev/null +++ b/common/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,21 @@ + + + + Voltar para o mapa + Voltar para a vila + Esta versão do Siga o Papai Noel está desatualizada. Visite a Play Store e atualize para a versão mais recente. + diff --git a/common/src/main/res/values-pt-rBR/strings_gamenames.xml b/common/src/main/res/values-pt-rBR/strings_gamenames.xml index 9f9c58d34..cd05396ed 100644 --- a/common/src/main/res/values-pt-rBR/strings_gamenames.xml +++ b/common/src/main/res/values-pt-rBR/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memória - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Jogo Snowball - Snowdown + Gumball + Memória + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Jogo das cidades + Caça ao presente diff --git a/common/src/main/res/values-pt-rBR/strings_invite.xml b/common/src/main/res/values-pt-rBR/strings_invite.xml index c92fd0956..75e268a18 100644 --- a/common/src/main/res/values-pt-rBR/strings_invite.xml +++ b/common/src/main/res/values-pt-rBR/strings_invite.xml @@ -1,6 +1,22 @@ + + Convide seus amigos para seguir o Papai Noel com o Google - Teste o Siga o Papai Noel e veja o Papai Noel voar pelo mundo! + Teste o app Siga o Papai Noel e acompanhe suas aventuras pelo mundo! Fiz %1$d pontos no jogo %2$s com os duendes no Siga o Papai Noel do Google. Você consegue fazer mais? diff --git a/common/src/main/res/values-pt-rBR/strings_jetpack.xml b/common/src/main/res/values-pt-rBR/strings_jetpack.xml index 7d64cac4a..6701da49c 100644 --- a/common/src/main/res/values-pt-rBR/strings_jetpack.xml +++ b/common/src/main/res/values-pt-rBR/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Faça login para desbloquear conquistas e postar sua pontuação. Jogar novamente - Pontuação + Retornar ao mapa + PONTUAÇÃO + Retornar ao mapa diff --git a/common/src/main/res/values-pt-rPT/strings.xml b/common/src/main/res/values-pt-rPT/strings.xml new file mode 100644 index 000000000..ba25ef2ba --- /dev/null +++ b/common/src/main/res/values-pt-rPT/strings.xml @@ -0,0 +1,21 @@ + + + + Voltar ao mapa + Voltar à aldeia + A versão da aplicação Viagem do Pai Natal está desatualizada. Visite a Play Store para atualizar para a versão mais recente. + diff --git a/common/src/main/res/values-pt-rPT/strings_gamenames.xml b/common/src/main/res/values-pt-rPT/strings_gamenames.xml index b991dac49..212518f7a 100644 --- a/common/src/main/res/values-pt-rPT/strings_gamenames.xml +++ b/common/src/main/res/values-pt-rPT/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memória - Elf Jetpack - Globo de Neve - Trenó-foguete - Dançarino Veloz - Jogo Bola de Neve - Snowdown + Gumball + Memória + Elf Jetpack + Trenó-foguete + Dançarino Veloz + Snowdown + Questionário de cidades + Caça aos presentes diff --git a/common/src/main/res/values-pt-rPT/strings_invite.xml b/common/src/main/res/values-pt-rPT/strings_invite.xml index b98b3a6fb..9edd0d466 100644 --- a/common/src/main/res/values-pt-rPT/strings_invite.xml +++ b/common/src/main/res/values-pt-rPT/strings_invite.xml @@ -1,6 +1,22 @@ + + Convidar os seus amigos para seguirem o Pai Natal com o Google - Experimenta o Localizador do Pai Natal e vê-o voar por todo o mundo! - Consegui uma classificação de %1$d no jogo %2$s com elfos no Localizador do Pai Natal da Google. Consegues melhor? + Experimenta A viagem do Pai Natal e vê-o voar por todo o mundo! + Consegui uma classificação de %1$d no jogo %2$s com os gnomos em A viagem do Pai Natal da Google. Consegues melhor? diff --git a/common/src/main/res/values-pt-rPT/strings_jetpack.xml b/common/src/main/res/values-pt-rPT/strings_jetpack.xml index 6b795c980..91844d77e 100644 --- a/common/src/main/res/values-pt-rPT/strings_jetpack.xml +++ b/common/src/main/res/values-pt-rPT/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Inicie sessão para desbloquear conquistas e publicar a sua pontuação! Jogar de novo - Pontuação + Voltar ao mapa + PONTUAÇÃO + Voltar ao mapa diff --git a/common/src/main/res/values-pt/strings.xml b/common/src/main/res/values-pt/strings.xml new file mode 100644 index 000000000..b586d8b3b --- /dev/null +++ b/common/src/main/res/values-pt/strings.xml @@ -0,0 +1,21 @@ + + + + Voltar para o mapa + Voltar para a vila + Esta versão do Siga o Papai Noel está desatualizada. Visite a Play Store e atualize para a versão mais recente. + diff --git a/common/src/main/res/values-pt/strings_gamenames.xml b/common/src/main/res/values-pt/strings_gamenames.xml index 9f9c58d34..cd05396ed 100644 --- a/common/src/main/res/values-pt/strings_gamenames.xml +++ b/common/src/main/res/values-pt/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memória - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Jogo Snowball - Snowdown + Gumball + Memória + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Jogo das cidades + Caça ao presente diff --git a/common/src/main/res/values-pt/strings_invite.xml b/common/src/main/res/values-pt/strings_invite.xml index c92fd0956..75e268a18 100644 --- a/common/src/main/res/values-pt/strings_invite.xml +++ b/common/src/main/res/values-pt/strings_invite.xml @@ -1,6 +1,22 @@ + + Convide seus amigos para seguir o Papai Noel com o Google - Teste o Siga o Papai Noel e veja o Papai Noel voar pelo mundo! + Teste o app Siga o Papai Noel e acompanhe suas aventuras pelo mundo! Fiz %1$d pontos no jogo %2$s com os duendes no Siga o Papai Noel do Google. Você consegue fazer mais? diff --git a/common/src/main/res/values-pt/strings_jetpack.xml b/common/src/main/res/values-pt/strings_jetpack.xml index 7d64cac4a..6701da49c 100644 --- a/common/src/main/res/values-pt/strings_jetpack.xml +++ b/common/src/main/res/values-pt/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Faça login para desbloquear conquistas e postar sua pontuação. Jogar novamente - Pontuação + Retornar ao mapa + PONTUAÇÃO + Retornar ao mapa diff --git a/common/src/main/res/values-ro/strings.xml b/common/src/main/res/values-ro/strings.xml new file mode 100644 index 000000000..2a02c6c70 --- /dev/null +++ b/common/src/main/res/values-ro/strings.xml @@ -0,0 +1,21 @@ + + + + Înapoi la hartă + Înapoi în sat + Această versiune a aplicației Pe urmele lui Moș Crăciun este învechită. Accesează Magazinul Google Play pentru cea mai nouă versiune. + diff --git a/common/src/main/res/values-ro/strings_gamenames.xml b/common/src/main/res/values-ro/strings_gamenames.xml index 41cc42d93..5e6af0942 100644 --- a/common/src/main/res/values-ro/strings_gamenames.xml +++ b/common/src/main/res/values-ro/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Jocul Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Sania-rachetă + Dansează cu Dasher + Bulgăreală + Găsește orașul + În căutarea cadourilor diff --git a/common/src/main/res/values-ro/strings_invite.xml b/common/src/main/res/values-ro/strings_invite.xml index 2fa2ba7f3..85b2be76b 100644 --- a/common/src/main/res/values-ro/strings_invite.xml +++ b/common/src/main/res/values-ro/strings_invite.xml @@ -1,6 +1,22 @@ + + - Invitați-vă prietenii să-l urmărească pe Moș Crăciun cu Google - Încercați Pe urmele lui Moș Crăciun și urmăriți-l pe Moș Crăciun cum călătorește în întreaga lume! - Am obținut un scor de %1$d jucând %2$s cu elfii, în Pe urmele lui Moș Crăciun de la Google. Mă puteți întrece? + Invită-ți prietenii să-l urmărească pe Moș Crăciun cu Google + Joacă Pe urmele lui Moș Crăciun și vezi pe unde călătorește Moș Crăciun în întreaga lume! + Am obținut un scor de %1$d jucând %2$s cu elfii, în Pe urmele lui Moș Crăciun de la Google. Mă poți întrece? diff --git a/common/src/main/res/values-ro/strings_jetpack.xml b/common/src/main/res/values-ro/strings_jetpack.xml index 909e54286..8da1aad5e 100644 --- a/common/src/main/res/values-ro/strings_jetpack.xml +++ b/common/src/main/res/values-ro/strings_jetpack.xml @@ -1,6 +1,24 @@ + + - Conectați-vă pentru a debloca realizările și pentru a vă posta scorul! - Jucați din nou - Scor + Conectează-te pentru a debloca realizările și pentru a-ți posta scorul! + Joacă din nou + Înapoi la hartă + SCOR + Înapoi la hartă diff --git a/common/src/main/res/values-ru/strings.xml b/common/src/main/res/values-ru/strings.xml new file mode 100644 index 000000000..4723778cb --- /dev/null +++ b/common/src/main/res/values-ru/strings.xml @@ -0,0 +1,21 @@ + + + + Назад к карте + Вернуться в деревню + Эта версия приложения устарела. Обновите его. + diff --git a/common/src/main/res/values-ru/strings_gamenames.xml b/common/src/main/res/values-ru/strings_gamenames.xml index f3557ddb9..5210a317e 100644 --- a/common/src/main/res/values-ru/strings_gamenames.xml +++ b/common/src/main/res/values-ru/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Жвачка - Память - Летающий эльф - Снежный шар - Реактивные сани - Лучший танцор - Снежок - Снежная битва + Жвачка + Память + Летающий эльф + Реактивные сани + Лучший танцор + Снежная битва + Угадай город + Найди подарок diff --git a/common/src/main/res/values-ru/strings_invite.xml b/common/src/main/res/values-ru/strings_invite.xml index 9fe6762c9..ca7f1bd96 100644 --- a/common/src/main/res/values-ru/strings_invite.xml +++ b/common/src/main/res/values-ru/strings_invite.xml @@ -1,6 +1,22 @@ + + - Пригласите друзей скачать приложение + Пригласите друзей Скачай приложение \"Радар Санта-Клауса\" и следи за путешествиями Санты. Мой результат в игре %2$s – %1$d очков! Сможешь набрать больше? diff --git a/common/src/main/res/values-ru/strings_jetpack.xml b/common/src/main/res/values-ru/strings_jetpack.xml index 0f4eeeea4..c60dc6b61 100644 --- a/common/src/main/res/values-ru/strings_jetpack.xml +++ b/common/src/main/res/values-ru/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Хотите получать награды и делиться результатами с друзьями? Войдите в аккаунт! Сыграть ещё раз - Счет + Перейти к карте + СЧЕТ + Перейти к карте diff --git a/common/src/main/res/values-sl/strings.xml b/common/src/main/res/values-sl/strings.xml new file mode 100644 index 000000000..f73238995 --- /dev/null +++ b/common/src/main/res/values-sl/strings.xml @@ -0,0 +1,21 @@ + + + + Nazaj na zemljevid + Nazaj v vas + Ta različica Spremljanja Božičkove poti je zastarela. Obiščite Play Store in jo posodobite v najnovejšo različico. + diff --git a/common/src/main/res/values-sl/strings_gamenames.xml b/common/src/main/res/values-sl/strings_gamenames.xml index e86193943..0da5f22f7 100644 --- a/common/src/main/res/values-sl/strings_gamenames.xml +++ b/common/src/main/res/values-sl/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Igra Snowball - Snežni spopad + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snežni spopad + Ugibanje mest + Iskanje daril diff --git a/common/src/main/res/values-sl/strings_invite.xml b/common/src/main/res/values-sl/strings_invite.xml index 4030a6571..bf7b355ed 100644 --- a/common/src/main/res/values-sl/strings_invite.xml +++ b/common/src/main/res/values-sl/strings_invite.xml @@ -1,4 +1,20 @@ + + Povabite svoje prijatelje, da spremljajo Božička z Googlom Preskusite Spremljanje Božičkove poti in glejte, kako Božiček leta po svetu. diff --git a/common/src/main/res/values-sl/strings_jetpack.xml b/common/src/main/res/values-sl/strings_jetpack.xml index 596140dbc..132f5817b 100644 --- a/common/src/main/res/values-sl/strings_jetpack.xml +++ b/common/src/main/res/values-sl/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Prijavite se, da odklenete dosežke in objavite svoj rezultat. Igraj znova - Rezultat + Nazaj na zemljevid + REZULTAT + Nazaj na zemljevid diff --git a/common/src/main/res/values-sv/strings.xml b/common/src/main/res/values-sv/strings.xml new file mode 100644 index 000000000..3e746baf3 --- /dev/null +++ b/common/src/main/res/values-sv/strings.xml @@ -0,0 +1,21 @@ + + + + Tillbaka till kartan + Tillbaka till byn + Den här versionen av Följ jultomten är inaktuell. Besök Play Butik för att uppdatera appen till den senaste versionen. + diff --git a/common/src/main/res/values-sv/strings_gamenames.xml b/common/src/main/res/values-sv/strings_gamenames.xml index b84b3125b..44b936c20 100644 --- a/common/src/main/res/values-sv/strings_gamenames.xml +++ b/common/src/main/res/values-sv/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Tomtenisse-jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Spelet Snowball - Snowdown + Gumball + Memory + Tomtenisse-jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Stadsfrågor + Klappjakten diff --git a/common/src/main/res/values-sv/strings_invite.xml b/common/src/main/res/values-sv/strings_invite.xml index 47ff8e79e..e3c2896e8 100644 --- a/common/src/main/res/values-sv/strings_invite.xml +++ b/common/src/main/res/values-sv/strings_invite.xml @@ -1,4 +1,20 @@ + + Bjud in dina vänner att följa Jultomten med Google Prova Följ jultomten och se hur tomten flyger runt hela världen! diff --git a/common/src/main/res/values-sv/strings_jetpack.xml b/common/src/main/res/values-sv/strings_jetpack.xml index ad1cbe0e6..46d15b936 100644 --- a/common/src/main/res/values-sv/strings_jetpack.xml +++ b/common/src/main/res/values-sv/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Logga in för att låsa upp prestationer och skicka in ditt resultat. Spela igen - Poäng + Tillbaka till kartan + POÄNG + Tillbaka till kartan diff --git a/common/src/main/res/values-sw600dp/dimens.xml b/common/src/main/res/values-sw600dp/dimens.xml index 67af92005..462c04b88 100644 --- a/common/src/main/res/values-sw600dp/dimens.xml +++ b/common/src/main/res/values-sw600dp/dimens.xml @@ -1,3 +1,19 @@ + + 20dp diff --git a/common/src/main/res/values-sw720dp/dimens.xml b/common/src/main/res/values-sw720dp/dimens.xml index 70387207b..977dcf8ed 100644 --- a/common/src/main/res/values-sw720dp/dimens.xml +++ b/common/src/main/res/values-sw720dp/dimens.xml @@ -1,3 +1,19 @@ + + 28sp diff --git a/common/src/main/res/values-ta/strings.xml b/common/src/main/res/values-ta/strings.xml new file mode 100644 index 000000000..7cf5b90c7 --- /dev/null +++ b/common/src/main/res/values-ta/strings.xml @@ -0,0 +1,21 @@ + + + + வரைபடத்திற்குச் செல் + கிராமத்திற்குச் செல் + சான்டா டிராக்கரின் இந்தப் பதிப்பு காலாவதியானது. Play ஸ்டோருக்குச் சென்று, சமீபத்திய பதிப்புக்குப் புதுப்பிக்கவும். + diff --git a/common/src/main/res/values-ta/strings_gamenames.xml b/common/src/main/res/values-ta/strings_gamenames.xml index 0db312ac1..1daa55333 100644 --- a/common/src/main/res/values-ta/strings_gamenames.xml +++ b/common/src/main/res/values-ta/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - கம் பால் - மெமரி - எல்ஃப் ஜெட்பேக் - ஸ்னோகுளோப் - ராக்கெட் ஸ்லெய் - டேஷர் டான்சர் - ஸ்னோபால் கேம் - ஸ்னோடவுன் + கம் பால் + மெமரி + எல்ஃப் ஜெட்பேக் + ராக்கெட் ஸ்லெய் + டேஷர் டான்சர் + ஸ்னோடவுன் + சிட்டி வினாடி வினா + பிரசென்ட் குவெஸ்ட் diff --git a/common/src/main/res/values-ta/strings_invite.xml b/common/src/main/res/values-ta/strings_invite.xml index d5450cdff..c37f48ded 100644 --- a/common/src/main/res/values-ta/strings_invite.xml +++ b/common/src/main/res/values-ta/strings_invite.xml @@ -1,6 +1,22 @@ + + - Google உடன் சேர்ந்து சான்டாவைக் கண்காணிக்க நண்பர்களை அழைக்கவும் + Google உடன் சேர்ந்து சான்டாவின் இடமறிய நண்பர்களை அழைக்கவும் சான்டா ட்ராக்கரைப் பயன்படுத்தி, சான்டாவின் பயண வழிகளைப் பார்க்கவும்! Google இன் சான்டா டிராக்கரில் குட்டித் தேவதைகளுடன் %2$s கேமில் %1$d ஸ்கோர் செய்துள்ளேன்! இதை முறியடிக்க முடியுமா? diff --git a/common/src/main/res/values-ta/strings_jetpack.xml b/common/src/main/res/values-ta/strings_jetpack.xml index 7a2a54f93..f88d4d5b0 100644 --- a/common/src/main/res/values-ta/strings_jetpack.xml +++ b/common/src/main/res/values-ta/strings_jetpack.xml @@ -1,6 +1,24 @@ + + சாதனைகளை எட்டவும் உங்கள் ஸ்கோரை வெளியிடவும், உள்நுழையவும்! - மீண்டும் விளையாடு + மீண்டும் விளையாடுக + வரைபடத்திற்குச் செல் ஸ்கோர் + வரைபடத்திற்குச் செல் diff --git a/common/src/main/res/values-th/strings.xml b/common/src/main/res/values-th/strings.xml new file mode 100644 index 000000000..98466e86f --- /dev/null +++ b/common/src/main/res/values-th/strings.xml @@ -0,0 +1,21 @@ + + + + กลับไปยังแผนที่ + กลับไปยังหมู่บ้าน + ตามติดซานต้าเวอร์ชันนี้ล้าสมัยแล้ว โปรดไปที่ Play Store เพื่ออัปเดตเป็นเวอร์ชันล่าสุด + diff --git a/common/src/main/res/values-th/strings_gamenames.xml b/common/src/main/res/values-th/strings_gamenames.xml index f6e5a3b68..9ef0159d1 100644 --- a/common/src/main/res/values-th/strings_gamenames.xml +++ b/common/src/main/res/values-th/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - เกมความจำ - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Gumball + เกมความจำ + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-th/strings_invite.xml b/common/src/main/res/values-th/strings_invite.xml index db165e988..39feb0aee 100644 --- a/common/src/main/res/values-th/strings_invite.xml +++ b/common/src/main/res/values-th/strings_invite.xml @@ -1,6 +1,22 @@ + + - กำลังเชิญเพื่อนๆ ของคุณมาร่วมตามติดซานต้าบน Google + เชิญเพื่อนๆ มาร่วมตามติดซานต้ากับ Google ลองตามติดซานต้าและดูซานต้าบินไปรอบโลก! ฉันได้ %1$d คะแนนในการเล่นเกม %2$s กับชาวเอลฟ์ในตามติดซานต้าของ Google คุณเอาชนะฉันได้ไหม diff --git a/common/src/main/res/values-th/strings_jetpack.xml b/common/src/main/res/values-th/strings_jetpack.xml index 45a78ab07..c8cb6c6dc 100644 --- a/common/src/main/res/values-th/strings_jetpack.xml +++ b/common/src/main/res/values-th/strings_jetpack.xml @@ -1,6 +1,24 @@ + + ลงชื่อเข้าใช้เพื่อปลดล็อกรางวัลพิเศษและโพสต์คะแนนของคุณ เล่นอีกครั้ง + กลับไปที่แผนที่ คะแนน + กลับไปที่แผนที่ diff --git a/common/src/main/res/values-tl/strings.xml b/common/src/main/res/values-tl/strings.xml new file mode 100644 index 000000000..b79cacce8 --- /dev/null +++ b/common/src/main/res/values-tl/strings.xml @@ -0,0 +1,21 @@ + + + + Bumalik sa mapa + Bumalik sa village + Luma na ang bersyong ito ng Santa Tracker. Pakibisita ang Play Store upang makapag-update sa pinakabagong bersyon. + diff --git a/common/src/main/res/values-tl/strings_gamenames.xml b/common/src/main/res/values-tl/strings_gamenames.xml index 53e834857..21d77d782 100644 --- a/common/src/main/res/values-tl/strings_gamenames.xml +++ b/common/src/main/res/values-tl/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Larong Snowball - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values-tl/strings_invite.xml b/common/src/main/res/values-tl/strings_invite.xml index ad736646d..3d5b566be 100644 --- a/common/src/main/res/values-tl/strings_invite.xml +++ b/common/src/main/res/values-tl/strings_invite.xml @@ -1,4 +1,20 @@ + + Imbitahan ang iyong mga kaibigan na subaybayan si Santa sa Google Subukan ang Santa Tracker at panoorin ang paglipad ni Santa sa buong mundo! diff --git a/common/src/main/res/values-tl/strings_jetpack.xml b/common/src/main/res/values-tl/strings_jetpack.xml index 0723cba66..2588c5142 100644 --- a/common/src/main/res/values-tl/strings_jetpack.xml +++ b/common/src/main/res/values-tl/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Mag-sign in upang mai-unlock ang mga achievement at mai-post ang iyong score! Maglaro Muli - Score + Bumalik sa Mapa + SCORE + Bumalik sa mapa diff --git a/common/src/main/res/values-uk/strings.xml b/common/src/main/res/values-uk/strings.xml new file mode 100644 index 000000000..776f0320c --- /dev/null +++ b/common/src/main/res/values-uk/strings.xml @@ -0,0 +1,21 @@ + + + + Назад на карту + Назад у містечко + Ця версія додатка Де Дід Мороз застаріла. Перейдіть у веб-магазин Play, щоб завантажити останню версію. + diff --git a/common/src/main/res/values-uk/strings_gamenames.xml b/common/src/main/res/values-uk/strings_gamenames.xml index c74f9043d..64c3fd8fa 100644 --- a/common/src/main/res/values-uk/strings_gamenames.xml +++ b/common/src/main/res/values-uk/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Гамбол - Згадати все - Реактивні ельфи - Снігова куля - Реактивні санчата - Олені - Гра \"Сніжки\" - Сніжки + Гамбол + Згадати все + Реактивні ельфи + Реактивні санчата + Олені + Сніжки + Угадай місто + Знайди подарунок diff --git a/common/src/main/res/values-uk/strings_invite.xml b/common/src/main/res/values-uk/strings_invite.xml index a51b7b640..7092566b7 100644 --- a/common/src/main/res/values-uk/strings_invite.xml +++ b/common/src/main/res/values-uk/strings_invite.xml @@ -1,6 +1,22 @@ + + - Запропонуйте друзям стежити за мандрівкою Діда Мороза в Google - Завантажте додаток Де Дід Мороз і стежте за пересуванням Діда Мороза по світу! + Запросіть друзів стежити за Дідом Морозом у Google + Завантажте додаток Де Дід Мороз і стежте за мандрівкою Діда Мороза! У грі \"%2$s\" у Google Де Дід Мороз у мене вже стільки очок: %1$d. Наберете більше? diff --git a/common/src/main/res/values-uk/strings_jetpack.xml b/common/src/main/res/values-uk/strings_jetpack.xml index 1d1b10ed0..3908af866 100644 --- a/common/src/main/res/values-uk/strings_jetpack.xml +++ b/common/src/main/res/values-uk/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Увійдіть, щоб розблокувати досягнення й повідомити свій результат іншим. Грати ще раз - Результат + Назад на карту + РАХУНОК + Назад на карту diff --git a/common/src/main/res/values-v21/styles.xml b/common/src/main/res/values-v21/styles.xml new file mode 100644 index 000000000..91e804b61 --- /dev/null +++ b/common/src/main/res/values-v21/styles.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/common/src/main/res/values-vi/strings.xml b/common/src/main/res/values-vi/strings.xml new file mode 100644 index 000000000..252fd4a46 --- /dev/null +++ b/common/src/main/res/values-vi/strings.xml @@ -0,0 +1,21 @@ + + + + Quay lại bản đồ + Quay lại làng + Phiên bản Theo chân ông già Noel này đã cũ. Vui lòng truy cập Cửa hàng Play để cập nhật lên phiên bản mới nhất. + diff --git a/common/src/main/res/values-vi/strings_gamenames.xml b/common/src/main/res/values-vi/strings_gamenames.xml index c379c4d70..c99176348 100644 --- a/common/src/main/res/values-vi/strings_gamenames.xml +++ b/common/src/main/res/values-vi/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Trò chơi Gumball - Trò chơi Trí nhớ - Trò chơi Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Trò chơi Snowball - Snowdown + Trò chơi Gumball + Trò chơi Trí nhớ + Trò chơi Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + Đoán tên thành phố + Săn tìm quà tặng diff --git a/common/src/main/res/values-vi/strings_invite.xml b/common/src/main/res/values-vi/strings_invite.xml index 753baa2af..85f55f4e1 100644 --- a/common/src/main/res/values-vi/strings_invite.xml +++ b/common/src/main/res/values-vi/strings_invite.xml @@ -1,6 +1,22 @@ + + - Mời bạn bè theo dõi Ông già Noel với Google + Mời bạn bè theo dõi ông già Noel với Google Hãy dùng thử công cụ Theo chân ông già Noel và xem ông già Noel bay khắp thế giới! Tôi đã ghi %1$d khi chơi trò %2$s với các chú lùn trong công cụ Theo chân ông già Noel của Google, bạn có thể đánh bại số điểm đó không? diff --git a/common/src/main/res/values-vi/strings_jetpack.xml b/common/src/main/res/values-vi/strings_jetpack.xml index ac07d5c4b..2a9b1dc3b 100644 --- a/common/src/main/res/values-vi/strings_jetpack.xml +++ b/common/src/main/res/values-vi/strings_jetpack.xml @@ -1,6 +1,24 @@ + + Đăng nhập để gặt hái thành tích và đăng điểm của bạn! Chơi lại - Điểm + Trở lại bản đồ + ĐIỂM + Trở lại bản đồ diff --git a/common/src/main/res/values-xhdpi/dimens.xml b/common/src/main/res/values-xhdpi/dimens.xml index 6697d3c78..938f9baef 100644 --- a/common/src/main/res/values-xhdpi/dimens.xml +++ b/common/src/main/res/values-xhdpi/dimens.xml @@ -1,3 +1,19 @@ + + 12sp diff --git a/common/src/main/res/values-zh-rCN/strings.xml b/common/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 000000000..a6881d7fb --- /dev/null +++ b/common/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,21 @@ + + + + 返回地图 + 返回小镇 + 此版本的“追踪圣诞老人”应用已经失效。请访问 Google Play 商店更新为最新版本。 + diff --git a/common/src/main/res/values-zh-rCN/strings_gamenames.xml b/common/src/main/res/values-zh-rCN/strings_gamenames.xml index 66587b8fd..133b74861 100644 --- a/common/src/main/res/values-zh-rCN/strings_gamenames.xml +++ b/common/src/main/res/values-zh-rCN/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball 游戏 - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + 城市知多少 + 寻找礼物 diff --git a/common/src/main/res/values-zh-rCN/strings_invite.xml b/common/src/main/res/values-zh-rCN/strings_invite.xml index e4e256ba4..60cbcdc2e 100644 --- a/common/src/main/res/values-zh-rCN/strings_invite.xml +++ b/common/src/main/res/values-zh-rCN/strings_invite.xml @@ -1,6 +1,22 @@ + + 邀请好友在 Google 上追踪圣诞老人 - 欢迎体验“追踪圣诞老人”,跟随圣诞老人环游世界! + 快来试玩“追踪圣诞老人”,与圣诞老人一起环游世界! 我在 Google 的“追踪圣诞老人”中与小精灵们玩“%2$s”游戏时得了 %1$d 分。你敢来挑战吗? diff --git a/common/src/main/res/values-zh-rCN/strings_jetpack.xml b/common/src/main/res/values-zh-rCN/strings_jetpack.xml index 175392b87..fe8cea794 100644 --- a/common/src/main/res/values-zh-rCN/strings_jetpack.xml +++ b/common/src/main/res/values-zh-rCN/strings_jetpack.xml @@ -1,6 +1,24 @@ + + 登录即可记录您的成就并发布您的得分! 重玩 + 返回地图 得分 + 返回地图 diff --git a/common/src/main/res/values-zh-rHK/strings.xml b/common/src/main/res/values-zh-rHK/strings.xml new file mode 100644 index 000000000..df8c0de53 --- /dev/null +++ b/common/src/main/res/values-zh-rHK/strings.xml @@ -0,0 +1,21 @@ + + + + 返回地圖 + 返回村落 + 這個「聖誕老人追蹤器」不是最新版本。請前往 Play 商店更新至最新版本。 + diff --git a/common/src/main/res/values-zh-rHK/strings_gamenames.xml b/common/src/main/res/values-zh-rHK/strings_gamenames.xml index 1dff059dd..0bb3ca070 100644 --- a/common/src/main/res/values-zh-rHK/strings_gamenames.xml +++ b/common/src/main/res/values-zh-rHK/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - 小精靈飛行背包 - 雪景球 - 火箭雪橇 - 猛衝‧跳舞 - 雪球遊戲 - Snowdown + Gumball + Memory + 小精靈飛行背包 + 火箭雪橇 + 猛衝‧跳舞 + Snowdown + 城市問答 + 禮物尋寶 diff --git a/common/src/main/res/values-zh-rHK/strings_invite.xml b/common/src/main/res/values-zh-rHK/strings_invite.xml index 34e710996..b56509370 100644 --- a/common/src/main/res/values-zh-rHK/strings_invite.xml +++ b/common/src/main/res/values-zh-rHK/strings_invite.xml @@ -1,4 +1,20 @@ + + 邀請好友在 Google 追蹤聖誕老人 試玩「追蹤聖誕老人」,追看聖誕老人遨遊世界各地! diff --git a/common/src/main/res/values-zh-rHK/strings_jetpack.xml b/common/src/main/res/values-zh-rHK/strings_jetpack.xml index d7c3a81c1..d77112925 100644 --- a/common/src/main/res/values-zh-rHK/strings_jetpack.xml +++ b/common/src/main/res/values-zh-rHK/strings_jetpack.xml @@ -1,6 +1,24 @@ + + 登入即可解鎖成就並發佈您的得分! 再玩一次 - 樂譜 + 返回地圖 + 得分 + 返回地圖 diff --git a/common/src/main/res/values-zh-rTW/strings.xml b/common/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 000000000..3b85494a6 --- /dev/null +++ b/common/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,21 @@ + + + + 返回地圖 + 返回聖誕老人村 + 目前的聖誕老人追蹤器版本已過期。請前往 Google Play 商店更新至最新版本。 + diff --git a/common/src/main/res/values-zh-rTW/strings_gamenames.xml b/common/src/main/res/values-zh-rTW/strings_gamenames.xml index 907448c97..4a4050a5f 100644 --- a/common/src/main/res/values-zh-rTW/strings_gamenames.xml +++ b/common/src/main/res/values-zh-rTW/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - 雪花玻璃球 - 火箭雪橇 - 馴鹿快跑 - 雪花玻璃球遊戲 - 雪球爭霸戰 + 口香糖球 + 翻牌配對 + Elf Jetpack + 火箭雪橇 + 馴鹿快跑 + 雪球爭霸戰 + 城市猜謎 + 禮物尋寶 diff --git a/common/src/main/res/values-zh-rTW/strings_invite.xml b/common/src/main/res/values-zh-rTW/strings_invite.xml index a90a9c4d4..60f9d5111 100644 --- a/common/src/main/res/values-zh-rTW/strings_invite.xml +++ b/common/src/main/res/values-zh-rTW/strings_invite.xml @@ -1,4 +1,20 @@ + + 邀請好友與 Google 一起追蹤聖誕老人 快來體驗聖誕老人追蹤器,和聖誕老人一起遨遊世界! diff --git a/common/src/main/res/values-zh-rTW/strings_jetpack.xml b/common/src/main/res/values-zh-rTW/strings_jetpack.xml index c0c67b7f2..25da57a8c 100644 --- a/common/src/main/res/values-zh-rTW/strings_jetpack.xml +++ b/common/src/main/res/values-zh-rTW/strings_jetpack.xml @@ -1,6 +1,24 @@ + + 登入即可解開遊戲關卡並發表您的得分! 再玩一次 - 得分 + 返回地圖 + 總成績 + 返回地圖 diff --git a/common/src/main/res/values-zh/strings.xml b/common/src/main/res/values-zh/strings.xml new file mode 100644 index 000000000..a6881d7fb --- /dev/null +++ b/common/src/main/res/values-zh/strings.xml @@ -0,0 +1,21 @@ + + + + 返回地图 + 返回小镇 + 此版本的“追踪圣诞老人”应用已经失效。请访问 Google Play 商店更新为最新版本。 + diff --git a/common/src/main/res/values-zh/strings_gamenames.xml b/common/src/main/res/values-zh/strings_gamenames.xml index 66587b8fd..133b74861 100644 --- a/common/src/main/res/values-zh/strings_gamenames.xml +++ b/common/src/main/res/values-zh/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball 游戏 - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + 城市知多少 + 寻找礼物 diff --git a/common/src/main/res/values-zh/strings_invite.xml b/common/src/main/res/values-zh/strings_invite.xml index e4e256ba4..60cbcdc2e 100644 --- a/common/src/main/res/values-zh/strings_invite.xml +++ b/common/src/main/res/values-zh/strings_invite.xml @@ -1,6 +1,22 @@ + + 邀请好友在 Google 上追踪圣诞老人 - 欢迎体验“追踪圣诞老人”,跟随圣诞老人环游世界! + 快来试玩“追踪圣诞老人”,与圣诞老人一起环游世界! 我在 Google 的“追踪圣诞老人”中与小精灵们玩“%2$s”游戏时得了 %1$d 分。你敢来挑战吗? diff --git a/common/src/main/res/values-zh/strings_jetpack.xml b/common/src/main/res/values-zh/strings_jetpack.xml index 175392b87..fe8cea794 100644 --- a/common/src/main/res/values-zh/strings_jetpack.xml +++ b/common/src/main/res/values-zh/strings_jetpack.xml @@ -1,6 +1,24 @@ + + 登录即可记录您的成就并发布您的得分! 重玩 + 返回地图 得分 + 返回地图 diff --git a/common/src/main/res/values/game_colors.xml b/common/src/main/res/values/game_colors.xml index a65a2f29e..e4956cbcc 100644 --- a/common/src/main/res/values/game_colors.xml +++ b/common/src/main/res/values/game_colors.xml @@ -1,6 +1,26 @@ + + + #00C3EA + #9600daea + #9A519F + #99ffffff #ff25af31 #FF17B223 - \ No newline at end of file + diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index 185e6f2ad..01f4d6f30 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -1,3 +1,22 @@ + + - Common + Common + Back to map + Back to village + This version of Santa Tracker is out of date. Please visit the Play Store to update to the latest version. diff --git a/common/src/main/res/values/strings_gamenames.xml b/common/src/main/res/values/strings_gamenames.xml index 6529032bf..21d77d782 100644 --- a/common/src/main/res/values/strings_gamenames.xml +++ b/common/src/main/res/values/strings_gamenames.xml @@ -1,11 +1,27 @@ + + - Gumball - Memory - Elf Jetpack - Snowglobe - Rocket Sleigh - Dasher Dancer - Snowball game - Snowdown + Gumball + Memory + Elf Jetpack + Rocket Sleigh + Dasher Dancer + Snowdown + City Quiz + Present Quest diff --git a/common/src/main/res/values/strings_invite.xml b/common/src/main/res/values/strings_invite.xml index 931856330..1a242e409 100644 --- a/common/src/main/res/values/strings_invite.xml +++ b/common/src/main/res/values/strings_invite.xml @@ -1,12 +1,28 @@ + + - + Invite your friends to track Santa with Google - + Try Santa Tracker and watch Santa fly around the world! - + I scored %1$d playing the %2$s game with the elves in Google\'s Santa Tracker, can you beat that? diff --git a/common/src/main/res/values/strings_jetpack.xml b/common/src/main/res/values/strings_jetpack.xml index a77357826..7d3ff2361 100644 --- a/common/src/main/res/values/strings_jetpack.xml +++ b/common/src/main/res/values/strings_jetpack.xml @@ -1,6 +1,24 @@ + + - Sign in to unlock achievements and post your score! - Play Again - Score + Sign in to unlock achievements and post your score! + Play Again + Return to Map + SCORE + Return to map diff --git a/common/src/main/res/values/styles.xml b/common/src/main/res/values/styles.xml new file mode 100644 index 000000000..edaa91371 --- /dev/null +++ b/common/src/main/res/values/styles.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + diff --git a/common/src/main/res/xml/config_analytics_tracker.xml b/common/src/main/res/xml/config_analytics_tracker.xml index 5d667745c..05f92ab4a 100644 --- a/common/src/main/res/xml/config_analytics_tracker.xml +++ b/common/src/main/res/xml/config_analytics_tracker.xml @@ -1,4 +1,20 @@ - + + + 300 @@ -10,4 +26,4 @@ UA-37048309-4 - \ No newline at end of file + diff --git a/common/src/main/res/xml/remote_config_defaults.xml b/common/src/main/res/xml/remote_config_defaults.xml new file mode 100644 index 000000000..dfc985a53 --- /dev/null +++ b/common/src/main/res/xml/remote_config_defaults.xml @@ -0,0 +1,143 @@ + + + + + + DisableCastButton + false + + + DisableDestinationPhoto + false + + + DisableGumballGame + false + + + DisableJetpackGame + false + + + DisableMemoryGame + false + + + DisableRocketGame + false + + + DisableDancerGame + false + + + DisableSnowdownGame + false + + + DisableSwimmingGame + false + + + DisableBmxGame + false + + + DisableRunningGame + false + + + DisableTennisGame + false + + + DisableWaterpoloGame + false + + + Video1 + zE_D9Vd69aw + + + Video15 + IXmDOu-eSx4 + + + Video23 + h83b1lWPuvQ + + + CityQuizRoundCount + 5 + + + PqLocationRequestIntervalMs + 3000 + + + PqLocationRequestIntervalFastestMs + 1000 + + + PqMinNearbyPresents + 5 + + + PqNearbyRadiusMeters + 1000 + + + PqReachableRadiusMeters + 150 + + + PqMaxPresents + 20 + + + PqMinCachedPlaces + 20 + + + PqMaxCachedPlaces + 2000 + + + PqCacheRefreshMs + 300000 + + + PqUsedPlaceRadiusWeight + 0.8 + + + PqFirstPlaceRadiusWeight + 1.1 + + + PqMaxCacheRandomSampleSize + 10 + + + PqNearbyWorkshopRadius + 1000 + + + SwimmingObstacleDensity + 0.10 + + diff --git a/dasherdancer/build.gradle b/dasherdancer/build.gradle index 5e15ac2a0..1fec3f3fd 100644 --- a/dasherdancer/build.gradle +++ b/dasherdancer/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 23 + compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.tools defaultConfig { - minSdkVersion 15 - targetSdkVersion 23 + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion } } diff --git a/dasherdancer/src/main/AndroidManifest.xml b/dasherdancer/src/main/AndroidManifest.xml index e6f01795f..88cbea013 100644 --- a/dasherdancer/src/main/AndroidManifest.xml +++ b/dasherdancer/src/main/AndroidManifest.xml @@ -1,15 +1,41 @@ + + - + - + - + diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Character.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Character.java index d0afaf157..8f3a7a403 100644 --- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Character.java +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Character.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package com.google.android.apps.santatracker.dasherdancer; +import android.support.annotation.RawRes; + /** * Interface for characters. To create a character, implement this interface. The animationKey passed * to this interface's methods is called with one of the ANIM_* static values defined in this interface. @@ -24,15 +26,21 @@ */ public interface Character { - public static int ANIM_IDLE = 0; - public static int ANIM_TAP = 1; - public static int ANIM_SHAKE = 2; - public static int ANIM_SWIPE_DOWN = 3; - public static int ANIM_SWIPE_UP = 4; - public static int ANIM_SWIPE_LEFT = 5; - public static int ANIM_SWIPE_RIGHT = 6; - public static int ANIM_PINCH_IN = 7; - public static int ANIM_PINCH_OUT = 8; + int ANIM_IDLE = 0; + int ANIM_TAP = 1; + int ANIM_SHAKE = 2; + int ANIM_SWIPE_DOWN = 3; + int ANIM_SWIPE_UP = 4; + int ANIM_SWIPE_LEFT = 5; + int ANIM_SWIPE_RIGHT = 6; + int ANIM_PINCH_IN = 7; + int ANIM_PINCH_OUT = 8; + + int[] ALL_ANIMS = new int[]{ + ANIM_IDLE, ANIM_TAP, ANIM_SHAKE, + ANIM_SWIPE_DOWN, ANIM_SWIPE_UP, ANIM_SWIPE_LEFT, ANIM_SWIPE_RIGHT, + ANIM_PINCH_IN, ANIM_PINCH_OUT + }; long getDuration(int animationKey); @@ -40,6 +48,9 @@ public interface Character { int[] getFrames(int animationKey); + @RawRes + int getSoundResource(int animationid); + // The initial release used getClass().getSimpleName(), which was ProGuarded out. // These strings are the pro-guarded names from the released version. In future releases // these should be changed to the names of the characters. diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterActivity.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterActivity.java index 446cbb886..b41fd8b61 100644 --- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterActivity.java +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterAdapter.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterAdapter.java index 5be82df09..7705b5080 100644 --- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterAdapter.java +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -82,7 +82,7 @@ public Object instantiateItem(ViewGroup container, int position) { view = mViews.get(position); } else { view = new FrameAnimationView(container.getContext()); - view.setScaleType(ImageView.ScaleType.CENTER_CROP); + view.setScaleType(ImageView.ScaleType.MATRIX); //Load the first idle frame. view.setBackgroundResource(mBackgrounds[position]); view.setTag(position); diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/DasherDancerActivity.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/DasherDancerActivity.java index b64a15d8d..d91d117a5 100644 --- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/DasherDancerActivity.java +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/DasherDancerActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,19 +24,24 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Point; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.media.AudioManager; import android.media.SoundPool; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.support.annotation.DrawableRes; +import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewPager.OnPageChangeListener; +import android.util.Log; import android.util.LruCache; import android.view.GestureDetector.OnGestureListener; import android.view.MotionEvent; @@ -61,6 +66,8 @@ public class DasherDancerActivity extends FragmentActivity implements OnGestureListener, OnScaleGestureListener, Handler.Callback, Listener, SensorEventListener, AnimatorListener, OnPageChangeListener, SignInListener { + private static final String TAG = "DasherDancer"; + /** * Extra key used to pass back the character id that should be selected, set by the CharacterActivity. */ @@ -72,6 +79,9 @@ public class DasherDancerActivity extends FragmentActivity implements public static final int CHARACTER_ID_REINDEER = 2; public static final int CHARACTER_ID_SNOWMAN = 3; + /** Number of times to try downsampling before giving up **/ + public static final int MAX_DOWNSAMPLING_ATTEMPTS = 3; + /** * Request code for calling CharacterActivity for result. */ @@ -95,12 +105,12 @@ public class DasherDancerActivity extends FragmentActivity implements {-1,-1,-1,-1,-1,-1,-1,-1,-1} //snowman }; - private LruCache mMemoryCache; + private LruCache mMemoryCache; private NoSwipeViewPager mPager; private Handler mHandler; private ShakeDetector mDetector; private LoadBitmapsTask mLoadBitmapsTask; - private LoadAllBitmapsTask mLoadAllBitmapsTask; + private LoadCharacterResourcesTask mLoadCharacterTask; private ObjectAnimator mAnimator; private boolean mPlayingRest = false; private boolean mAnimCanceled = false; @@ -114,6 +124,10 @@ public class DasherDancerActivity extends FragmentActivity implements private ActivityManager mActivityManager; private FirebaseAnalytics mMeasurement; + // Bitmap downsampling options + private BitmapFactory.Options mOptions; + private int mDownSamplingAttempts; + private PlayGamesFragment mGamesFragment; // For achievements @@ -133,15 +147,30 @@ public void onCreate(Bundle savedInstanceState) { mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); - mMemoryCache = new LruCache(240) { - protected void entryRemoved(boolean evicted, Integer key, Bitmap oldValue, Bitmap newValue) { + mMemoryCache = new LruCache(240) { + protected void entryRemoved(boolean evicted, Integer key, Drawable oldValue, Drawable newValue) { if ((oldValue != null) && (oldValue != newValue)) { - oldValue.recycle(); - oldValue = null; + if (oldValue instanceof InsetDrawableCompat){ + Drawable drawable = ((InsetDrawableCompat) oldValue).getDrawable(); + if (drawable instanceof BitmapDrawable){ + ((BitmapDrawable) drawable).getBitmap().recycle(); + } + } } } }; + // Initialize default Bitmap options + mOptions = new BitmapFactory.Options(); + mOptions.inPreferredConfig = Bitmap.Config.RGB_565; + mOptions.inSampleSize = getResources().getInteger(R.integer.res); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (mActivityManager.isLowRamDevice()) { + Log.w(TAG, "isLowRamDevice: downsampling default bitmap options"); + mOptions.inSampleSize *= 2; + } + } + CharacterAdapter adapter = new CharacterAdapter(sCharacters); mPager = (NoSwipeViewPager) findViewById(R.id.character_pager); mPager.setAdapter(adapter); @@ -153,38 +182,6 @@ protected void entryRemoved(boolean evicted, Integer key, Bitmap oldValue, Bitma mDetector = new ShakeDetector(this); mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0); - mSoundIds[0][Character.ANIM_PINCH_IN] = mSoundPool.load(this, R.raw.santa_pinchin, 1); - mSoundIds[0][Character.ANIM_PINCH_OUT] = mSoundPool.load(this, R.raw.santa_pinchout, 1); - mSoundIds[0][Character.ANIM_SHAKE] = mSoundPool.load(this, R.raw.santa_shake, 1); - mSoundIds[0][Character.ANIM_SWIPE_UP] = mSoundPool.load(this, R.raw.santa_swipeup, 1); - mSoundIds[0][Character.ANIM_SWIPE_LEFT] = mSoundPool.load(this, R.raw.santa_swipeleft, 1); - mSoundIds[0][Character.ANIM_SWIPE_RIGHT] = mSoundPool.load(this, R.raw.santa_swiperight, 1); - mSoundIds[0][Character.ANIM_SWIPE_DOWN] = mSoundPool.load(this, R.raw.santa_swipedown, 1); - mSoundIds[0][Character.ANIM_TAP] = mSoundPool.load(this, R.raw.santa_tap, 1); - mSoundIds[1][Character.ANIM_PINCH_IN] = mSoundPool.load(this, R.raw.elf_pinchin_ball, 1); - mSoundIds[1][Character.ANIM_PINCH_OUT] = mSoundPool.load(this, R.raw.elf_pinchout, 1); - mSoundIds[1][Character.ANIM_SHAKE] = mSoundPool.load(this, R.raw.elf_shake2, 1); - mSoundIds[1][Character.ANIM_SWIPE_DOWN] = mSoundPool.load(this, R.raw.elf_swipedown2, 1); - mSoundIds[1][Character.ANIM_SWIPE_UP] = mSoundPool.load(this, R.raw.elf_swipeup2, 1); - mSoundIds[1][Character.ANIM_SWIPE_LEFT] = mSoundPool.load(this, R.raw.elf_swipeleft, 1); - mSoundIds[1][Character.ANIM_SWIPE_RIGHT] = mSoundPool.load(this, R.raw.elf_swiperight, 1); - mSoundIds[1][Character.ANIM_TAP] = mSoundPool.load(this, R.raw.elf_tap3, 1); - mSoundIds[2][Character.ANIM_PINCH_IN] = mSoundPool.load(this, R.raw.reindeer_pinchin, 1); - mSoundIds[2][Character.ANIM_PINCH_OUT] = mSoundPool.load(this, R.raw.reindeer_pinchout, 1); - mSoundIds[2][Character.ANIM_SHAKE] = mSoundPool.load(this, R.raw.reindeer_shake, 1); - mSoundIds[2][Character.ANIM_SWIPE_UP] = mSoundPool.load(this, R.raw.reindeer_swipeup, 1); - mSoundIds[2][Character.ANIM_SWIPE_DOWN] = mSoundPool.load(this, R.raw.reindeer_swipedown, 1); - mSoundIds[2][Character.ANIM_SWIPE_LEFT] = mSoundPool.load(this, R.raw.reindeer_swipeleft, 1); - mSoundIds[2][Character.ANIM_SWIPE_RIGHT] = mSoundPool.load(this, R.raw.reindeer_swiperight, 1); - mSoundIds[2][Character.ANIM_TAP] = mSoundPool.load(this, R.raw.reindeer_tap2, 1); - mSoundIds[3][Character.ANIM_PINCH_IN] = mSoundPool.load(this, R.raw.snowman_pinchin, 1); - mSoundIds[3][Character.ANIM_PINCH_OUT] = mSoundPool.load(this, R.raw.snowman_pinchout, 1); - mSoundIds[3][Character.ANIM_SHAKE] = mSoundPool.load(this, R.raw.snowman_shake, 1); - mSoundIds[3][Character.ANIM_SWIPE_UP] = mSoundPool.load(this, R.raw.snowman_swipeup, 1); - mSoundIds[3][Character.ANIM_SWIPE_DOWN] = mSoundPool.load(this, R.raw.snowman_swipedown, 1); - mSoundIds[3][Character.ANIM_SWIPE_LEFT] = mSoundPool.load(this, R.raw.snowman_swipeleft, 1); - mSoundIds[3][Character.ANIM_SWIPE_RIGHT] = mSoundPool.load(this, R.raw.snowman_swiperight, 1); - mSoundIds[3][Character.ANIM_TAP] = mSoundPool.load(this, R.raw.snowman_tap, 1); mAchievements = new HashSet[4]; mAchievements[0] = new HashSet(); @@ -227,11 +224,12 @@ public void run() { }, 300); } else { - if(mLoadAllBitmapsTask != null) { - mLoadAllBitmapsTask.cancel(true); + if(mLoadCharacterTask != null) { + mLoadCharacterTask.cancel(true); } - mLoadAllBitmapsTask = new LoadAllBitmapsTask(); - mLoadAllBitmapsTask.execute(sCharacters[mPager.getCurrentItem()]); + + mLoadCharacterTask = new LoadCharacterResourcesTask(mPager.getCurrentItem()); + mLoadCharacterTask.execute(); } } @@ -276,8 +274,8 @@ public void onChangeClick(View view) { if(mLoadBitmapsTask != null) { mLoadBitmapsTask.cancel(true); } - if(mLoadAllBitmapsTask != null) { - mLoadAllBitmapsTask.cancel(true); + if(mLoadCharacterTask != null) { + mLoadCharacterTask.cancel(true); } if(mAnimator != null) { mAnimator.cancel(); @@ -521,8 +519,28 @@ private void loadAnimation(boolean playingRest, long animationTime, int[] frameI mLoadBitmapsTask.cancel(true); mAnimator.cancel(); } - LoadBitmapsTask task = new LoadBitmapsTask(animationTime, frameIndices, frameResourceIds); - task.execute(); + + mLoadBitmapsTask = new LoadBitmapsTask(animationTime, frameIndices, frameResourceIds); + mLoadBitmapsTask.execute(); + } + + /** + * Load and cache all sounds for a given character. + * @param characterIndex index of the character in the array, like {@link #CHARACTER_ID_SANTA}. + */ + private void loadSoundsForCharacter(int characterIndex) { + for (int animationId : Character.ALL_ANIMS) { + // No need to load sounds twice + if (mSoundIds[characterIndex][animationId] != -1) { + continue; + } + + int soundResource = sCharacters[characterIndex].getSoundResource(animationId); + if (soundResource != -1) { + mSoundIds[characterIndex][animationId] = + mSoundPool.load(this, soundResource, 1); + } + } } @Override @@ -535,101 +553,92 @@ public void onSignInSucceeded() { } - private class LoadAllBitmapsTask extends AsyncTask { + @Nullable + private Drawable tryLoadBitmap(@DrawableRes int resourceId) throws BitmapLoadException { + try { + Bitmap bmp = BitmapFactory.decodeResource(getResources(), resourceId, mOptions); + BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), bmp); + Point p = ResourceOffsets.getOffsets(resourceId); + int x = Math.round(p.x / (float)mOptions.inSampleSize); + int y = Math.round(p.y / (float)mOptions.inSampleSize); + int w = Math.round(ResourceOffsets.ORIG_SIZE.x / (float)mOptions.inSampleSize); + int h = Math.round(ResourceOffsets.ORIG_SIZE.y / (float)mOptions.inSampleSize); + InsetDrawableCompat insetDrawable = new InsetDrawableCompat(bitmapDrawable, + x, + y, + w - bmp.getWidth() - x, + h - bmp.getHeight() - y + ); + return insetDrawable; + + } catch (OutOfMemoryError oom) { + Log.w(TAG, "Out of memory error, inSampleSize=" + mOptions.inSampleSize); + if (mDownSamplingAttempts < MAX_DOWNSAMPLING_ATTEMPTS) { + mOptions.inSampleSize *= 2; + mDownSamplingAttempts++; + } + } + + throw new BitmapLoadException("Failed to load resource ID: " + resourceId); + } + + /** + * Load all of the resources for a given Character, then begin playing the "IDLE" animation. + * for that character. + */ + private class LoadCharacterResourcesTask extends RetryableAsyncTask { + + private Character mCharacter; + private int mCharacterIndex; - final BitmapFactory.Options mOptions = new BitmapFactory.Options(); + LoadCharacterResourcesTask(int characterIndex) { + mCharacter = sCharacters[characterIndex]; + mCharacterIndex = characterIndex; + } @Override - protected Void doInBackground(Character... params) { + protected Void doInBackground(Void... params) { mCanTouch = false; //See if we can free up any memory before we allocate some ourselves. //Request garbage collection. System.gc(); - Character c = params[0]; - mOptions.inPreferredConfig = Bitmap.Config.RGB_565; - mOptions.inSampleSize = getResources().getInteger(R.integer.res); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - if (mActivityManager.isLowRamDevice()) { - mOptions.inSampleSize *= 2; - } - } + // Load all sounds for this character + loadSoundsForCharacter(mCharacterIndex); - for (int resourceId : c.getFrames(Character.ANIM_IDLE)) { - if(isCancelled()) { - break; - } - loadBitmapHelper(resourceId); - } - for (int resourceId : c.getFrames(Character.ANIM_TAP)) { - if(isCancelled()) { - break; - } - loadBitmapHelper(resourceId); - } - for (int resourceId : c.getFrames(Character.ANIM_SHAKE)) { - if(isCancelled()) { - break; - } - loadBitmapHelper(resourceId); - } - for (int resourceId : c.getFrames(Character.ANIM_SWIPE_UP)) { - if(isCancelled()) { - break; - } - loadBitmapHelper(resourceId); - } - for (int resourceId : c.getFrames(Character.ANIM_SWIPE_DOWN)) { - if(isCancelled()) { - break; - } - loadBitmapHelper(resourceId); - } - for (int resourceId : c.getFrames(Character.ANIM_SWIPE_LEFT)) { - if(isCancelled()) { - break; - } - loadBitmapHelper(resourceId); - } - for (int resourceId : c.getFrames(Character.ANIM_SWIPE_RIGHT)) { - if(isCancelled()) { - break; - } - loadBitmapHelper(resourceId); - } - for (int resourceId : c.getFrames(Character.ANIM_PINCH_IN)) { - if(isCancelled()) { - break; - } - loadBitmapHelper(resourceId); - } - for (int resourceId : c.getFrames(Character.ANIM_PINCH_OUT)) { - if(isCancelled()) { + // Load all animations types for this character + for (int animation : Character.ALL_ANIMS) { + for (int resourceId : mCharacter.getFrames(animation)) { + if (isCancelled()) { break; } - loadBitmapHelper(resourceId); - } - return null; - } + if (mMemoryCache.get(resourceId) == null) { + try { + Drawable bitmap = tryLoadBitmap(resourceId); + mMemoryCache.put(resourceId, bitmap); + } catch (BitmapLoadException e) { + Log.e(TAG, "LoadCharacterResourcesTask: failed", e); - private void loadBitmapHelper(int resourceId) { - if(mMemoryCache.get(resourceId) == null) { - mMemoryCache.put(resourceId, BitmapFactory.decodeResource( - DasherDancerActivity.this.getResources(), - resourceId, - mOptions)); - if (isCancelled()) { - // Remove the BMP we just added - // The check and remove should be atomic so we synchronize - // (There could be an evict going on so make sure it's still there... - synchronized(mMemoryCache) { - if (mMemoryCache.get(resourceId) != null) { - mMemoryCache.remove(resourceId); + // Retry the task + return retrySelf(params); + } + + if (isCancelled()) { + // Remove the BMP we just added + // The check and remove should be atomic so we synchronize + // (There could be an evict going on so make sure it's still there... + synchronized(mMemoryCache) { + if (mMemoryCache.get(resourceId) != null) { + mMemoryCache.remove(resourceId); + } + } } } } } + + return null; } @Override @@ -640,59 +649,79 @@ public void onPostExecute(Void result) { findViewById(R.id.progress).setVisibility(View.GONE); - Bitmap[] frames = new Bitmap[sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_IDLE).length]; + Character currentCharacter = sCharacters[mPager.getCurrentItem()]; + Drawable[] frames = new Drawable[currentCharacter.getFrames(Character.ANIM_IDLE).length]; for(int i=0; i { + private class LoadBitmapsTask extends RetryableAsyncTask { private int[] mFrames; private int[] mFrameIndices; private long mDuration; public LoadBitmapsTask(long duration, int[] frameIndices, int[] frames) { - mFrameIndices = frameIndices; mDuration = duration; + mFrameIndices = frameIndices; mFrames = frames; } @Override - protected Bitmap[] doInBackground(Void... params) { - Bitmap[] bitmaps = new Bitmap[mFrames.length]; - final BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.RGB_565; - options.inSampleSize = getResources().getInteger(R.integer.res); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - if (mActivityManager.isLowRamDevice()) { - options.inSampleSize *= 2; + protected Drawable[] doInBackground(Void... params) { + Drawable[] bitmaps = new Drawable[mFrames.length]; + + for(int i = 0; i < mFrames.length; i++) { + if (isCancelled()) { + break; } - } - for(int i=0; i= 0 && mFrameIndex < mFrameIndices.length - && mFrames[mFrameIndices[mFrameIndex]] != null && !mFrames[mFrameIndices[mFrameIndex]].isRecycled()) { + private Drawable[] mFrames; + + private int[] mFrameIndices; + private int mFrameIndex; + private final Paint mPaint = new Paint(); + private InsetDrawableCompat mInsetDrawable; + private BitmapDrawable mBitmapDrawable; + + + public FrameAnimationView(Context context) { + super(context); + init(); + } + + public FrameAnimationView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public FrameAnimationView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + mPaint.setAntiAlias(true); + setImageDrawable(mInsetDrawable); + } + + /** + * Will attempt to recycle the old frames before setting the new frames. + * + * @param frames + * @param frameIndices + */ + public void setFrames(Drawable[] frames, int[] frameIndices) { + if (mFrames != null) { + mFrames = null; + } + mFrames = frames; + mFrameIndices = frameIndices; + } + + public int getFrameIndex() { + return mFrameIndex; + } + + public void setFrameIndex(int frameIndex) { + mFrameIndex = frameIndex; + if (mFrames != null && mFrameIndex >= 0 && mFrameIndex < mFrameIndices.length + && mFrames[mFrameIndices[mFrameIndex]] != null && !isBitmapRecycled(mFrames[mFrameIndices[mFrameIndex]])) { invalidate(); } - } - - public void onDraw(Canvas c) { - if(mFrames != null && mFrameIndex >= 0 && mFrameIndex < mFrameIndices.length) { - setImageBitmap(mFrames[mFrameIndices[mFrameIndex]]); - } - if(getDrawable() == null) { - super.onDraw(c); - return; + } + + private boolean isBitmapRecycled(Drawable drawable) { + if (drawable != null && drawable instanceof InsetDrawableCompat) { + drawable = ((InsetDrawableCompat) drawable).getDrawable(); + } + if (drawable != null && drawable instanceof BitmapDrawable) { + Bitmap bmp = ((BitmapDrawable) drawable).getBitmap(); + if (bmp != null) { + return bmp.isRecycled(); + } + } + return true; + } + + Matrix matrix = new Matrix(); + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + recalculateMatrix(w, h); + } + + private void recalculateMatrix(int vwidth, int vheight) { + if (mFrames != null && mFrameIndex >= 0 && mFrameIndex < mFrameIndices.length) { + InsetDrawableCompat insetDrawableCompat = + (InsetDrawableCompat) mFrames[mFrameIndices[mFrameIndex]]; + + if (isBitmapRecycled(insetDrawableCompat)) { + return; + } + + matrix.reset(); + float scale; + float dx = 0, dy = 0; + + int dwidth = insetDrawableCompat.getDrawable().getIntrinsicWidth() + + insetDrawableCompat.getLeft() + insetDrawableCompat.getRight(); + int dheight = insetDrawableCompat.getDrawable().getIntrinsicHeight() + + insetDrawableCompat.getTop() + insetDrawableCompat.getBottom(); + + if (dwidth * vheight > vwidth * dheight) { + scale = (float) vheight / (float) dheight; + dx = (vwidth - dwidth * scale) * 0.5f; + } else { + scale = (float) vwidth / (float) dwidth; + dy = (vheight - dheight * scale) * 0.5f; + } + + matrix.setTranslate(insetDrawableCompat.getLeft(), insetDrawableCompat.getTop()); + matrix.postScale(scale, scale); + matrix.postTranslate(Math.round(dx), Math.round(dy)); + setImageMatrix(matrix); } - if(((BitmapDrawable)getDrawable()).getBitmap() == null - || ((BitmapDrawable)getDrawable()).getBitmap().isRecycled()) { + } + + public void onDraw(Canvas c) { + if (mFrames != null && mFrameIndex >= 0 && mFrameIndex < mFrameIndices.length) { + //the line below should work with InsetDrawable with CENTER_CROP, + //but it doesn't work on older APIs (JB) beacause of different handling of insets: + //setImageDrawable(mFrames[mFrameIndices[mFrameIndex]]); + + //code below fixes the bug in InsetDrawable and works on all API levels: + //instead of setting the InsetDrawable on FrameAnimationView, + //we set the Bitmap directly and use the insets to calculate the correct matrix + + InsetDrawableCompat insetDrawableCompat = (InsetDrawableCompat) mFrames[mFrameIndices[mFrameIndex]]; + if (isBitmapRecycled(insetDrawableCompat)) { + return; + } + Bitmap newBitmap = ((BitmapDrawable) insetDrawableCompat.getDrawable()).getBitmap(); + + Drawable current = getDrawable(); + if (current == null + || (current instanceof BitmapDrawable + && !newBitmap.equals(((BitmapDrawable) current).getBitmap()))) { + setImageBitmap(newBitmap); + recalculateMatrix(getWidth(), getHeight()); + } + } + + if (isBitmapRecycled(getDrawable())) { return; } - super.onDraw(c); - } + super.onDraw(c); + } } diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/InsetDrawableCompat.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/InsetDrawableCompat.java new file mode 100644 index 000000000..2d2c60052 --- /dev/null +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/InsetDrawableCompat.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.apps.santatracker.dasherdancer; + +import android.graphics.drawable.Drawable; +import android.graphics.drawable.InsetDrawable; + + +public class InsetDrawableCompat extends InsetDrawable { + + private Drawable mDrawable; + private int mLeft, mTop, mRight, mBottom; + + public Drawable getDrawable(){ + return mDrawable; + } + + public int getLeft() { + return mLeft; + } + + public int getTop() { + return mTop; + } + + public int getRight() { + return mRight; + } + + public int getBottom() { + return mBottom; + } + + public InsetDrawableCompat(Drawable drawable, int inset) { + super(drawable, inset); + mDrawable = drawable; + mLeft = inset; + mTop = inset; + mRight = inset; + mBottom = inset; + } + + public InsetDrawableCompat(Drawable drawable, int insetLeft, int insetTop, int insetRight, int insetBottom) { + super(drawable, insetLeft, insetTop, insetRight, insetBottom); + mDrawable = drawable; + mLeft = insetLeft; + mTop = insetTop; + mRight = insetRight; + mBottom = insetBottom; + } + +} diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/NoSwipeViewPager.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/NoSwipeViewPager.java index 3446d58da..41cc7b543 100644 --- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/NoSwipeViewPager.java +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/NoSwipeViewPager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Reindeer.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Reindeer.java index bcc951b75..3cdab2a9c 100644 --- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Reindeer.java +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Reindeer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -225,6 +225,30 @@ public int[] getFrames(int animationKey) { return sFrames[animationKey]; } + @Override + public int getSoundResource(int animationid) { + switch (animationid) { + case Character.ANIM_PINCH_IN: + return R.raw.reindeer_pinchin; + case Character.ANIM_PINCH_OUT: + return R.raw.reindeer_pinchout; + case Character.ANIM_SHAKE: + return R.raw.reindeer_shake; + case Character.ANIM_SWIPE_UP: + return R.raw.reindeer_swipeup; + case Character.ANIM_SWIPE_DOWN: + return R.raw.reindeer_swipedown; + case Character.ANIM_SWIPE_LEFT: + return R.raw.reindeer_swipeleft; + case Character.ANIM_SWIPE_RIGHT: + return R.raw.reindeer_swiperight; + case Character.ANIM_TAP: + return R.raw.reindeer_tap2; + } + + return -1; + } + @Override public String getCharacterName() { return "r"; diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/ResourceOffsets.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/ResourceOffsets.java new file mode 100644 index 000000000..6fe3960b0 --- /dev/null +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/ResourceOffsets.java @@ -0,0 +1,922 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.apps.santatracker.dasherdancer; + +import android.graphics.Point; +import android.support.annotation.DrawableRes; + +import java.util.HashMap; + +/** + * To reduce RAM usage transparent areas were removed from all image frames for this game. This + * class encodes the offsets needed to display all the frames so that they align with the + * transparent regions removed. + */ +public class ResourceOffsets { + + private static HashMap offsets = new HashMap<>(); + private static Point EMPTY = new Point(0,0); + + public static Point ORIG_SIZE = new Point(1280, 1280); + + public static Point getOffsets(@DrawableRes int drawableId) { + Point p = offsets.get(drawableId); + return p == null ? EMPTY : p; + } + + static { + offsets.put(R.drawable.elf_pinchout0006, new Point(0, 0)); + offsets.put(R.drawable.snowman_swiperight0015, new Point(429, 221)); + offsets.put(R.drawable.reindeer_swipedown0018, new Point(365, 709)); + offsets.put(R.drawable.elf_shake0006, new Point(318, 230)); + offsets.put(R.drawable.reindeer_swipeleft0002, new Point(341, 331)); + offsets.put(R.drawable.reindeer_pinchout0024, new Point(342, 337)); + offsets.put(R.drawable.snowman_swipeup0023, new Point(429, 220)); + offsets.put(R.drawable.snowman_pinchout0001, new Point(429, 221)); + offsets.put(R.drawable.snowman_pinchout0022, new Point(334, 310)); + offsets.put(R.drawable.reindeer_swipedown0008, new Point(365, 705)); + offsets.put(R.drawable.santa_pinchin0007, new Point(136, 218)); + offsets.put(R.drawable.snowman_swipedown0021, new Point(429, 250)); + offsets.put(R.drawable.santa_idle0021, new Point(415, 434)); + offsets.put(R.drawable.santa_idle0024, new Point(415, 435)); + offsets.put(R.drawable.santa_pinchout20001, new Point(0, 0)); + offsets.put(R.drawable.reindeer_swipedown0009, new Point(376, 709)); + offsets.put(R.drawable.elf_swipedown0014, new Point(396, 611)); + offsets.put(R.drawable.snowman_pinchin0001, new Point(429, 221)); + offsets.put(R.drawable.snowman_pinchout0005, new Point(360, 434)); + offsets.put(R.drawable.santa_swipeleft0017, new Point(147, 628)); + offsets.put(R.drawable.reindeer_swipeup0013, new Point(210, 37)); + offsets.put(R.drawable.snowman_pinchin0012, new Point(90, 806)); + offsets.put(R.drawable.santa_swipeleft0009, new Point(94, 606)); + offsets.put(R.drawable.elf_pinchout0017, new Point(0, 0)); + offsets.put(R.drawable.snowman_swipeleft0007, new Point(429, 221)); + offsets.put(R.drawable.santa_idle0027, new Point(415, 432)); + offsets.put(R.drawable.snowman_tap0017, new Point(94, 221)); + offsets.put(R.drawable.santa_temp_tap01, new Point(415, 435)); + offsets.put(R.drawable.elf_swipeleft0023, new Point(435, 358)); + offsets.put(R.drawable.reindeer_swipeleft0019, new Point(384, 347)); + offsets.put(R.drawable.snowman_pinchin0009, new Point(90, 422)); + offsets.put(R.drawable.elf_idle0007, new Point(435, 437)); + offsets.put(R.drawable.snowman_idle0002, new Point(429, 220)); + offsets.put(R.drawable.reindeer_tap0008, new Point(342, 337)); + offsets.put(R.drawable.santa_swipe_right20005, new Point(350, 423)); + offsets.put(R.drawable.snowman_pinchout0003, new Point(395, 339)); + offsets.put(R.drawable.reindeer_pinchout0018, new Point(98, 37)); + offsets.put(R.drawable.snowman_swipeleft0004, new Point(429, 221)); + offsets.put(R.drawable.santa_idle0007, new Point(416, 430)); + offsets.put(R.drawable.snowman_swipeup0022, new Point(429, 219)); + offsets.put(R.drawable.santa_shake0005, new Point(229, 475)); + offsets.put(R.drawable.santa_swipeup0016, new Point(253, 221)); + offsets.put(R.drawable.snowman_tap0019, new Point(102, 221)); + offsets.put(R.drawable.santa_swipeup0023, new Point(427, 427)); + offsets.put(R.drawable.reindeer_pinchin0023, new Point(0, 0)); + offsets.put(R.drawable.snowman_swiperight0005, new Point(314, 221)); + offsets.put(R.drawable.elf_shake0016, new Point(285, 309)); + offsets.put(R.drawable.reindeer_swipeup0016, new Point(240, 73)); + offsets.put(R.drawable.reindeer_swipedown0023, new Point(344, 351)); + offsets.put(R.drawable.snowman_swiperight0024, new Point(429, 221)); + offsets.put(R.drawable.reindeer_swipeup0010, new Point(210, 34)); + offsets.put(R.drawable.reindeer_swipedown0007, new Point(375, 595)); + offsets.put(R.drawable.reindeer_pinchin0003, new Point(0, 0)); + offsets.put(R.drawable.santa_shake0010, new Point(241, 468)); + offsets.put(R.drawable.snowman_swipeleft0011, new Point(429, 221)); + offsets.put(R.drawable.elf_tap0018, new Point(435, 440)); + offsets.put(R.drawable.santa_swipeup0001, new Point(415, 435)); + offsets.put(R.drawable.elf_idle0012, new Point(435, 436)); + offsets.put(R.drawable.snowman_swiperight0008, new Point(271, 221)); + offsets.put(R.drawable.elf_idle0002, new Point(435, 440)); + offsets.put(R.drawable.snowman_pinchin0010, new Point(90, 513)); + offsets.put(R.drawable.elf_swiperight0011, new Point(1073, 707)); + offsets.put(R.drawable.santa_shake0003, new Point(279, 476)); + offsets.put(R.drawable.elf_swipeleft0012, new Point(294, 460)); + offsets.put(R.drawable.elf_tap0017, new Point(429, 436)); + offsets.put(R.drawable.elf_pinchin_ball0008, new Point(520, 914)); + offsets.put(R.drawable.snowman_swipeup0003, new Point(429, 182)); + offsets.put(R.drawable.santa_swipeleft0013, new Point(429, 608)); + offsets.put(R.drawable.snowman_pinchout0020, new Point(237, 580)); + offsets.put(R.drawable.reindeer_shake0018, new Point(384, 13)); + offsets.put(R.drawable.snowman_swipeleft0001, new Point(429, 221)); + offsets.put(R.drawable.reindeer_swipedown0005, new Point(381, 451)); + offsets.put(R.drawable.reindeer_shake0021, new Point(384, 206)); + offsets.put(R.drawable.snowman_idle0020, new Point(429, 218)); + offsets.put(R.drawable.reindeer_tap0022, new Point(342, 337)); + offsets.put(R.drawable.snowman_swipedown0020, new Point(429, 279)); + offsets.put(R.drawable.snowman_shake0005, new Point(115, 0)); + offsets.put(R.drawable.snowman_swipeup0012, new Point(429, 21)); + offsets.put(R.drawable.reindeer_tap0013, new Point(342, 337)); + offsets.put(R.drawable.reindeer_pinchin0008, new Point(0, 0)); + offsets.put(R.drawable.santa_shake0013, new Point(363, 426)); + offsets.put(R.drawable.elf_pinchin_ball0001, new Point(435, 440)); + offsets.put(R.drawable.snowman_idle0022, new Point(429, 219)); + offsets.put(R.drawable.reindeer_swipeleft0021, new Point(370, 339)); + offsets.put(R.drawable.santa_pinchin0017, new Point(270, 435)); + offsets.put(R.drawable.santa_idle0014, new Point(416, 430)); + offsets.put(R.drawable.elf_swiperight0020, new Point(252, 504)); + offsets.put(R.drawable.reindeer_tap0024, new Point(342, 337)); + offsets.put(R.drawable.elf_pinchout0015, new Point(0, 0)); + offsets.put(R.drawable.elf_tap0005, new Point(347, 380)); + offsets.put(R.drawable.snowman_pinchin0008, new Point(90, 367)); + offsets.put(R.drawable.snowman_idle0011, new Point(429, 217)); + offsets.put(R.drawable.reindeer_pinchin0018, new Point(0, 0)); + offsets.put(R.drawable.santa_idle0035, new Point(416, 429)); + offsets.put(R.drawable.reindeer_swipeup0015, new Point(218, 46)); + offsets.put(R.drawable.santa_idle0032, new Point(416, 429)); + offsets.put(R.drawable.elf_pinchout0020, new Point(106, 0)); + offsets.put(R.drawable.snowman_swipeup0007, new Point(427, 21)); + offsets.put(R.drawable.snowman_swipedown0013, new Point(429, 442)); + offsets.put(R.drawable.elf_swipedown0002, new Point(435, 440)); + offsets.put(R.drawable.snowman_swipedown0018, new Point(429, 212)); + offsets.put(R.drawable.santa_pinchin0009, new Point(96, 154)); + offsets.put(R.drawable.snowman_pinchin0005, new Point(55, 0)); + offsets.put(R.drawable.santa_idle0017, new Point(415, 432)); + offsets.put(R.drawable.santa_swipeleft0007, new Point(165, 589)); + offsets.put(R.drawable.santa_pinchout20015, new Point(0, 0)); + offsets.put(R.drawable.snowman_idle0014, new Point(429, 217)); + offsets.put(R.drawable.santa_idle0011, new Point(416, 429)); + offsets.put(R.drawable.reindeer_swipeleft0010, new Point(282, 280)); + offsets.put(R.drawable.reindeer_shake0013, new Point(383, 20)); + offsets.put(R.drawable.elf_shake0023, new Point(435, 471)); + offsets.put(R.drawable.snowman_swipeup0008, new Point(429, 21)); + offsets.put(R.drawable.santa_swipedown0007, new Point(429, 635)); + offsets.put(R.drawable.reindeer_swipeleft0003, new Point(338, 311)); + offsets.put(R.drawable.reindeer_pinchin0014, new Point(0, 0)); + offsets.put(R.drawable.santa_pinchout20004, new Point(0, 0)); + offsets.put(R.drawable.elf_swipeup0011, new Point(378, 6)); + offsets.put(R.drawable.reindeer_tap0003, new Point(350, 341)); + offsets.put(R.drawable.santa_swipeleft0004, new Point(314, 530)); + offsets.put(R.drawable.elf_idle0001, new Point(435, 440)); + offsets.put(R.drawable.elf_idle0006, new Point(435, 437)); + offsets.put(R.drawable.elf_shake0002, new Point(319, 369)); + offsets.put(R.drawable.elf_tap0010, new Point(100, 262)); + offsets.put(R.drawable.reindeer_tap0020, new Point(342, 337)); + offsets.put(R.drawable.santa_tap0008, new Point(270, 596)); + offsets.put(R.drawable.elf_idle0014, new Point(435, 436)); + offsets.put(R.drawable.santa_pinchin0015, new Point(215, 347)); + offsets.put(R.drawable.reindeer_swipedown0013, new Point(360, 709)); + offsets.put(R.drawable.reindeer_swipeup0020, new Point(334, 368)); + offsets.put(R.drawable.snowman_swiperight0009, new Point(139, 221)); + offsets.put(R.drawable.elf_pinchin_ball0016, new Point(515, 127)); + offsets.put(R.drawable.reindeer_swiperight0012, new Point(0, 1069)); + offsets.put(R.drawable.santa_pinchout20010, new Point(0, 0)); + offsets.put(R.drawable.snowman_swipedown0024, new Point(400, 266)); + offsets.put(R.drawable.reindeer_swipedown0017, new Point(363, 709)); + offsets.put(R.drawable.reindeer_swipeup0007, new Point(327, 105)); + offsets.put(R.drawable.elf_swipedown0005, new Point(435, 454)); + offsets.put(R.drawable.reindeer_swiperight0008, new Point(205, 660)); + offsets.put(R.drawable.reindeer_pinchin0015, new Point(0, 0)); + offsets.put(R.drawable.snowman_swipedown0001, new Point(429, 221)); + offsets.put(R.drawable.reindeer_shake0016, new Point(383, 17)); + offsets.put(R.drawable.reindeer_shake0008, new Point(384, 23)); + offsets.put(R.drawable.elf_swipeleft0024, new Point(435, 363)); + offsets.put(R.drawable.snowman_pinchout0019, new Point(237, 580)); + offsets.put(R.drawable.santa_shake0015, new Point(332, 421)); + offsets.put(R.drawable.reindeer_swiperight0016, new Point(211, 335)); + offsets.put(R.drawable.santa_shake0014, new Point(367, 422)); + offsets.put(R.drawable.elf_swipeup0003, new Point(386, 360)); + offsets.put(R.drawable.elf_tap0011, new Point(81, 270)); + offsets.put(R.drawable.santa_temp_left01, new Point(415, 435)); + offsets.put(R.drawable.elf_swipedown0018, new Point(435, 469)); + offsets.put(R.drawable.santa_idle0031, new Point(416, 430)); + offsets.put(R.drawable.elf_swipeup0006, new Point(476, 165)); + offsets.put(R.drawable.elf_swiperight0022, new Point(435, 459)); + offsets.put(R.drawable.snowman_swipeleft0003, new Point(429, 221)); + offsets.put(R.drawable.elf_swipeup0005, new Point(475, 262)); + offsets.put(R.drawable.snowman_pinchout0006, new Point(342, 473)); + offsets.put(R.drawable.elf_swipeleft0022, new Point(435, 352)); + offsets.put(R.drawable.elf_idle0021, new Point(435, 438)); + offsets.put(R.drawable.santa_swipeup0003, new Point(423, 402)); + offsets.put(R.drawable.snowman_shake0001, new Point(393, 221)); + offsets.put(R.drawable.reindeer_swipeleft0007, new Point(301, 225)); + offsets.put(R.drawable.snowman_swipeleft0024, new Point(429, 221)); + offsets.put(R.drawable.snowman_tap0013, new Point(79, 221)); + offsets.put(R.drawable.santa_idle0029, new Point(415, 431)); + offsets.put(R.drawable.santa_idle0041, new Point(415, 433)); + offsets.put(R.drawable.snowman_swiperight0006, new Point(139, 221)); + offsets.put(R.drawable.reindeer_swipedown0010, new Point(383, 709)); + offsets.put(R.drawable.santa_shake0023, new Point(351, 426)); + offsets.put(R.drawable.santa_swipedown0021, new Point(0, 159)); + offsets.put(R.drawable.snowman_idle0018, new Point(429, 218)); + offsets.put(R.drawable.reindeer_swipeleft0013, new Point(301, 324)); + offsets.put(R.drawable.reindeer_pinchout0004, new Point(331, 324)); + offsets.put(R.drawable.elf_pinchin_ball0014, new Point(520, 134)); + offsets.put(R.drawable.snowman_pinchin0006, new Point(35, 64)); + offsets.put(R.drawable.santa_swipedown0023, new Point(0, 435)); + offsets.put(R.drawable.santa_shake0021, new Point(344, 421)); + offsets.put(R.drawable.santa_swipe_right20020, new Point(401, 435)); + offsets.put(R.drawable.snowman_shake0010, new Point(100, 0)); + offsets.put(R.drawable.elf_swipedown0012, new Point(396, 611)); + offsets.put(R.drawable.elf_swipedown0009, new Point(400, 535)); + offsets.put(R.drawable.reindeer_pinchout0015, new Point(84, 20)); + offsets.put(R.drawable.reindeer_shake0014, new Point(384, 30)); + offsets.put(R.drawable.elf_swipeleft0013, new Point(269, 460)); + offsets.put(R.drawable.reindeer_shake0002, new Point(357, 301)); + offsets.put(R.drawable.reindeer_shake0001, new Point(342, 337)); + offsets.put(R.drawable.snowman_swipeup0013, new Point(415, 21)); + offsets.put(R.drawable.santa_shake0022, new Point(279, 422)); + offsets.put(R.drawable.santa_shake0017, new Point(377, 420)); + offsets.put(R.drawable.santa_pinchin0005, new Point(215, 347)); + offsets.put(R.drawable.snowman_swipeleft0005, new Point(429, 221)); + offsets.put(R.drawable.elf_swipeup0012, new Point(378, 119)); + offsets.put(R.drawable.santa_tap0011, new Point(270, 443)); + offsets.put(R.drawable.snowman_idle0009, new Point(429, 217)); + offsets.put(R.drawable.santa_tap0012, new Point(269, 443)); + offsets.put(R.drawable.snowman_swipeleft0006, new Point(429, 221)); + offsets.put(R.drawable.snowman_shake0002, new Point(130, 0)); + offsets.put(R.drawable.reindeer_swiperight0018, new Point(363, 338)); + offsets.put(R.drawable.elf_pinchout0014, new Point(0, 0)); + offsets.put(R.drawable.santa_shake0019, new Point(341, 420)); + offsets.put(R.drawable.elf_shake0021, new Point(228, 236)); + offsets.put(R.drawable.snowman_idle0017, new Point(429, 217)); + offsets.put(R.drawable.snowman_swiperight0007, new Point(191, 221)); + offsets.put(R.drawable.santa_swipedown0018, new Point(0, 0)); + offsets.put(R.drawable.snowman_tap0022, new Point(118, 221)); + offsets.put(R.drawable.snowman_swiperight0003, new Point(224, 221)); + offsets.put(R.drawable.elf_swipedown0003, new Point(435, 414)); + offsets.put(R.drawable.snowman_swipeup0005, new Point(429, 70)); + offsets.put(R.drawable.elf_pinchout0012, new Point(0, 0)); + offsets.put(R.drawable.snowman_swipedown0006, new Point(253, 447)); + offsets.put(R.drawable.snowman_pinchin0004, new Point(22, 0)); + offsets.put(R.drawable.snowman_swiperight0001, new Point(429, 221)); + offsets.put(R.drawable.santa_swipedown0010, new Point(429, 635)); + offsets.put(R.drawable.snowman_idle0013, new Point(429, 217)); + offsets.put(R.drawable.reindeer_swiperight0003, new Point(344, 337)); + offsets.put(R.drawable.elf_tap0008, new Point(175, 254)); + offsets.put(R.drawable.snowman_swipeup0011, new Point(429, 21)); + offsets.put(R.drawable.santa_swipedown0006, new Point(429, 635)); + offsets.put(R.drawable.reindeer_pinchin0011, new Point(0, 0)); + offsets.put(R.drawable.santa_idle0036, new Point(416, 429)); + offsets.put(R.drawable.snowman_swiperight0017, new Point(429, 221)); + offsets.put(R.drawable.snowman_swipedown0012, new Point(425, 350)); + offsets.put(R.drawable.santa_swipedown0005, new Point(429, 610)); + offsets.put(R.drawable.elf_tap0020, new Point(435, 440)); + offsets.put(R.drawable.santa_idle0016, new Point(415, 432)); + offsets.put(R.drawable.snowman_shake0017, new Point(72, 0)); + offsets.put(R.drawable.elf_pinchin_ball0024, new Point(520, 518)); + offsets.put(R.drawable.snowman_swipedown0007, new Point(226, 419)); + offsets.put(R.drawable.reindeer_pinchout0021, new Point(183, 142)); + offsets.put(R.drawable.reindeer_pinchin0022, new Point(0, 0)); + offsets.put(R.drawable.santa_swipedown0008, new Point(429, 635)); + offsets.put(R.drawable.elf_tap0015, new Point(382, 398)); + offsets.put(R.drawable.reindeer_pinchout0003, new Point(339, 334)); + offsets.put(R.drawable.reindeer_swipeleft0022, new Point(353, 338)); + offsets.put(R.drawable.elf_shake0011, new Point(343, 183)); + offsets.put(R.drawable.elf_swiperight0002, new Point(423, 441)); + offsets.put(R.drawable.reindeer_swipeup0006, new Point(353, 154)); + offsets.put(R.drawable.elf_tap0016, new Point(412, 422)); + offsets.put(R.drawable.santa_temp_shake01, new Point(415, 435)); + offsets.put(R.drawable.elf_swipeup0021, new Point(435, 480)); + offsets.put(R.drawable.elf_idle0009, new Point(435, 437)); + offsets.put(R.drawable.elf_swipedown0016, new Point(433, 561)); + offsets.put(R.drawable.santa_pinchout20006, new Point(0, 0)); + offsets.put(R.drawable.santa_pinchout20020, new Point(0, 0)); + offsets.put(R.drawable.reindeer_pinchout0007, new Point(276, 255)); + offsets.put(R.drawable.santa_idle0048, new Point(415, 435)); + offsets.put(R.drawable.snowman_idle0003, new Point(429, 219)); + offsets.put(R.drawable.elf_swipeleft0019, new Point(432, 393)); + offsets.put(R.drawable.santa_pinchout20012, new Point(0, 0)); + offsets.put(R.drawable.reindeer_pinchout0016, new Point(82, 17)); + offsets.put(R.drawable.elf_tap0024, new Point(435, 440)); + offsets.put(R.drawable.santa_idle0040, new Point(415, 432)); + offsets.put(R.drawable.elf_swiperight0017, new Point(0, 606)); + offsets.put(R.drawable.snowman_swiperight0011, new Point(330, 221)); + offsets.put(R.drawable.santa_idle0001, new Point(415, 435)); + offsets.put(R.drawable.snowman_tap0004, new Point(245, 227)); + offsets.put(R.drawable.elf_tap0013, new Point(286, 324)); + offsets.put(R.drawable.elf_shake0012, new Point(318, 233)); + offsets.put(R.drawable.elf_pinchout0008, new Point(0, 0)); + offsets.put(R.drawable.santa_pinchin0016, new Point(270, 435)); + offsets.put(R.drawable.snowman_swipedown0016, new Point(422, 13)); + offsets.put(R.drawable.reindeer_pinchin0004, new Point(0, 0)); + offsets.put(R.drawable.santa_swipeup0005, new Point(429, 375)); + offsets.put(R.drawable.snowman_shake0003, new Point(126, 21)); + offsets.put(R.drawable.elf_pinchout0004, new Point(0, 0)); + offsets.put(R.drawable.reindeer_swipedown0004, new Point(364, 401)); + offsets.put(R.drawable.reindeer_pinchout0023, new Point(281, 262)); + offsets.put(R.drawable.santa_swipeleft0018, new Point(216, 579)); + offsets.put(R.drawable.elf_pinchout0018, new Point(0, 0)); + offsets.put(R.drawable.reindeer_shake0004, new Point(383, 13)); + offsets.put(R.drawable.reindeer_pinchin0016, new Point(0, 0)); + offsets.put(R.drawable.santa_swipe_right20001, new Point(415, 435)); + offsets.put(R.drawable.santa_swipe_right20021, new Point(389, 435)); + offsets.put(R.drawable.santa_swipeleft0014, new Point(429, 508)); + offsets.put(R.drawable.elf_shake0018, new Point(279, 233)); + offsets.put(R.drawable.santa_idle0003, new Point(415, 433)); + offsets.put(R.drawable.santa_swipeup0018, new Point(317, 317)); + offsets.put(R.drawable.elf_idle0010, new Point(435, 436)); + offsets.put(R.drawable.snowman_pinchin0024, new Point(401, 220)); + offsets.put(R.drawable.snowman_swiperight0016, new Point(429, 221)); + offsets.put(R.drawable.snowman_pinchin0007, new Point(35, 64)); + offsets.put(R.drawable.snowman_swipeup0010, new Point(429, 21)); + offsets.put(R.drawable.reindeer_pinchin0020, new Point(0, 0)); + offsets.put(R.drawable.elf_swipedown0015, new Point(400, 605)); + offsets.put(R.drawable.elf_tap0014, new Point(337, 366)); + offsets.put(R.drawable.elf_tap0006, new Point(290, 333)); + offsets.put(R.drawable.elf_swiperight0023, new Point(423, 440)); + offsets.put(R.drawable.santa_swipe_right20023, new Point(415, 435)); + offsets.put(R.drawable.snowman_swipeup0024, new Point(429, 221)); + offsets.put(R.drawable.snowman_tap0002, new Point(381, 227)); + offsets.put(R.drawable.santa_swipedown0022, new Point(0, 414)); + offsets.put(R.drawable.santa_swipe_right20017, new Point(415, 385)); + offsets.put(R.drawable.reindeer_swipedown0024, new Point(342, 337)); + offsets.put(R.drawable.elf_pinchin_ball0012, new Point(519, 270)); + offsets.put(R.drawable.reindeer_tap0014, new Point(342, 337)); + offsets.put(R.drawable.santa_idle0008, new Point(416, 430)); + offsets.put(R.drawable.snowman_idle0001, new Point(429, 221)); + offsets.put(R.drawable.reindeer_pinchout0010, new Point(177, 135)); + offsets.put(R.drawable.reindeer_swipeup0019, new Point(349, 266)); + offsets.put(R.drawable.santa_tap0022, new Point(358, 435)); + offsets.put(R.drawable.santa_swipeup0012, new Point(417, 213)); + offsets.put(R.drawable.snowman_idle0019, new Point(429, 218)); + offsets.put(R.drawable.elf_swipedown0023, new Point(435, 460)); + offsets.put(R.drawable.elf_pinchin_ball0025, new Point(476, 280)); + offsets.put(R.drawable.santa_swipe_right20009, new Point(332, 416)); + offsets.put(R.drawable.santa_idle0038, new Point(415, 431)); + offsets.put(R.drawable.snowman_pinchout0021, new Point(285, 423)); + offsets.put(R.drawable.santa_swipeup0022, new Point(420, 438)); + offsets.put(R.drawable.elf_pinchin_ball0007, new Point(497, 828)); + offsets.put(R.drawable.reindeer_shake0023, new Point(342, 346)); + offsets.put(R.drawable.snowman_idle0023, new Point(429, 220)); + offsets.put(R.drawable.snowman_swiperight0012, new Point(399, 221)); + offsets.put(R.drawable.elf_shake0024, new Point(435, 440)); + offsets.put(R.drawable.reindeer_pinchout0017, new Point(86, 22)); + offsets.put(R.drawable.reindeer_swipedown0001, new Point(342, 337)); + offsets.put(R.drawable.snowman_pinchin0021, new Point(182, 191)); + offsets.put(R.drawable.snowman_swipeup0020, new Point(429, 221)); + offsets.put(R.drawable.reindeer_shake0019, new Point(384, 34)); + offsets.put(R.drawable.elf_swipeleft0009, new Point(391, 460)); + offsets.put(R.drawable.elf_pinchout0011, new Point(0, 0)); + offsets.put(R.drawable.snowman_tap0016, new Point(90, 221)); + offsets.put(R.drawable.elf_shake0004, new Point(228, 236)); + offsets.put(R.drawable.snowman_tap0020, new Point(105, 221)); + offsets.put(R.drawable.elf_pinchout0022, new Point(464, 489)); + offsets.put(R.drawable.santa_swipedown0011, new Point(345, 613)); + offsets.put(R.drawable.elf_pinchin_ball0029, new Point(404, 450)); + offsets.put(R.drawable.elf_shake0013, new Point(201, 285)); + offsets.put(R.drawable.santa_swipeup0007, new Point(429, 304)); + offsets.put(R.drawable.snowman_idle0016, new Point(429, 217)); + offsets.put(R.drawable.santa_swipe_right20010, new Point(312, 437)); + offsets.put(R.drawable.reindeer_swipeup0018, new Point(329, 183)); + offsets.put(R.drawable.reindeer_tap0010, new Point(342, 337)); + offsets.put(R.drawable.elf_swipedown0001, new Point(435, 440)); + offsets.put(R.drawable.reindeer_pinchin0024, new Point(0, 0)); + offsets.put(R.drawable.elf_swipeup0020, new Point(404, 450)); + offsets.put(R.drawable.elf_pinchout0023, new Point(459, 480)); + offsets.put(R.drawable.santa_pinchin0018, new Point(235, 505)); + offsets.put(R.drawable.reindeer_pinchin0019, new Point(0, 0)); + offsets.put(R.drawable.santa_shake0006, new Point(245, 474)); + offsets.put(R.drawable.snowman_shake0019, new Point(74, 0)); + offsets.put(R.drawable.santa_idle0019, new Point(415, 434)); + offsets.put(R.drawable.snowman_swipedown0011, new Point(394, 381)); + offsets.put(R.drawable.snowman_pinchin0020, new Point(167, 189)); + offsets.put(R.drawable.santa_idle0043, new Point(415, 434)); + offsets.put(R.drawable.snowman_swipeleft0013, new Point(415, 221)); + offsets.put(R.drawable.reindeer_swipeup0023, new Point(193, 338)); + offsets.put(R.drawable.santa_pinchout20011, new Point(0, 0)); + offsets.put(R.drawable.elf_swiperight0003, new Point(435, 425)); + offsets.put(R.drawable.reindeer_swipedown0014, new Point(343, 709)); + offsets.put(R.drawable.santa_swipeleft0020, new Point(351, 467)); + offsets.put(R.drawable.snowman_swipeleft0023, new Point(429, 221)); + offsets.put(R.drawable.reindeer_swipeup0021, new Point(268, 354)); + offsets.put(R.drawable.snowman_tap0009, new Point(79, 221)); + offsets.put(R.drawable.elf_shake0009, new Point(201, 285)); + offsets.put(R.drawable.santa_swipeleft0003, new Point(374, 516)); + offsets.put(R.drawable.snowman_swipeleft0022, new Point(429, 221)); + offsets.put(R.drawable.elf_pinchout0013, new Point(0, 0)); + offsets.put(R.drawable.santa_tap0015, new Point(270, 412)); + offsets.put(R.drawable.snowman_pinchout0002, new Point(412, 283)); + offsets.put(R.drawable.elf_swipedown0010, new Point(397, 556)); + offsets.put(R.drawable.elf_pinchin_ball0011, new Point(521, 426)); + offsets.put(R.drawable.reindeer_swipedown0012, new Point(378, 709)); + offsets.put(R.drawable.santa_pinchin0002, new Point(358, 435)); + offsets.put(R.drawable.reindeer_tap0004, new Point(346, 339)); + offsets.put(R.drawable.snowman_shake0015, new Point(83, 0)); + offsets.put(R.drawable.santa_shake0016, new Point(322, 420)); + offsets.put(R.drawable.snowman_pinchin0014, new Point(90, 1245)); + offsets.put(R.drawable.reindeer_swiperight0023, new Point(330, 341)); + offsets.put(R.drawable.santa_pinchin0019, new Point(224, 529)); + offsets.put(R.drawable.reindeer_swipeleft0018, new Point(384, 355)); + offsets.put(R.drawable.reindeer_shake0015, new Point(384, 23)); + offsets.put(R.drawable.snowman_pinchin0011, new Point(90, 641)); + offsets.put(R.drawable.santa_swipe_right20011, new Point(412, 394)); + offsets.put(R.drawable.santa_pinchin0004, new Point(270, 435)); + offsets.put(R.drawable.snowman_shake0021, new Point(68, 11)); + offsets.put(R.drawable.reindeer_swipeleft0012, new Point(291, 300)); + offsets.put(R.drawable.elf_idle0018, new Point(435, 437)); + offsets.put(R.drawable.santa_swipeup0006, new Point(429, 334)); + offsets.put(R.drawable.reindeer_pinchout0006, new Point(299, 285)); + offsets.put(R.drawable.santa_pinchin0001, new Point(415, 435)); + offsets.put(R.drawable.santa_swipeup0020, new Point(425, 462)); + offsets.put(R.drawable.elf_swipeleft0007, new Point(362, 460)); + offsets.put(R.drawable.snowman_tap0015, new Point(87, 221)); + offsets.put(R.drawable.elf_swiperight0007, new Point(506, 517)); + offsets.put(R.drawable.elf_swipeup0016, new Point(476, 200)); + offsets.put(R.drawable.elf_swipeleft0020, new Point(435, 389)); + offsets.put(R.drawable.santa_swipedown0009, new Point(429, 635)); + offsets.put(R.drawable.santa_swipe_right20002, new Point(420, 435)); + offsets.put(R.drawable.elf_swipeleft0015, new Point(369, 460)); + offsets.put(R.drawable.elf_swipeleft0002, new Point(414, 441)); + offsets.put(R.drawable.elf_swipeleft0008, new Point(393, 460)); + offsets.put(R.drawable.snowman_pinchout0018, new Point(237, 580)); + offsets.put(R.drawable.santa_tap0002, new Point(358, 435)); + offsets.put(R.drawable.santa_tap0019, new Point(270, 423)); + offsets.put(R.drawable.elf_pinchout0007, new Point(0, 0)); + offsets.put(R.drawable.snowman_swiperight0018, new Point(429, 221)); + offsets.put(R.drawable.snowman_pinchout0014, new Point(237, 580)); + offsets.put(R.drawable.elf_pinchin_ball0006, new Point(487, 762)); + offsets.put(R.drawable.snowman_pinchout0011, new Point(255, 577)); + offsets.put(R.drawable.snowman_swiperight0022, new Point(417, 221)); + offsets.put(R.drawable.reindeer_swiperight0021, new Point(325, 361)); + offsets.put(R.drawable.snowman_idle0007, new Point(429, 217)); + offsets.put(R.drawable.santa_swipedown0013, new Point(266, 0)); + offsets.put(R.drawable.santa_pinchout20002, new Point(0, 0)); + offsets.put(R.drawable.santa_swipeup0019, new Point(422, 428)); + offsets.put(R.drawable.snowman_swipeleft0016, new Point(429, 221)); + offsets.put(R.drawable.elf_swipeup0004, new Point(435, 200)); + offsets.put(R.drawable.santa_swipeleft0006, new Point(209, 565)); + offsets.put(R.drawable.santa_idle0005, new Point(415, 431)); + offsets.put(R.drawable.reindeer_swipeup0014, new Point(210, 37)); + offsets.put(R.drawable.elf_shake0010, new Point(285, 309)); + offsets.put(R.drawable.reindeer_swipeleft0008, new Point(290, 260)); + offsets.put(R.drawable.snowman_swipeup0016, new Point(219, 21)); + offsets.put(R.drawable.reindeer_swipeup0003, new Point(342, 275)); + offsets.put(R.drawable.reindeer_swiperight0009, new Point(121, 685)); + offsets.put(R.drawable.reindeer_swiperight0017, new Point(249, 332)); + offsets.put(R.drawable.elf_swipeup0015, new Point(476, 311)); + offsets.put(R.drawable.elf_swipeup0013, new Point(397, 259)); + offsets.put(R.drawable.santa_shake0024, new Point(355, 435)); + offsets.put(R.drawable.santa_shake0002, new Point(328, 456)); + offsets.put(R.drawable.reindeer_swipeleft0004, new Point(333, 279)); + offsets.put(R.drawable.snowman_shake0016, new Point(76, 0)); + offsets.put(R.drawable.santa_swipedown0014, new Point(262, 0)); + offsets.put(R.drawable.reindeer_swipedown0019, new Point(384, 601)); + offsets.put(R.drawable.elf_pinchin_ball0031, new Point(435, 458)); + offsets.put(R.drawable.santa_idle0046, new Point(415, 435)); + offsets.put(R.drawable.elf_tap0021, new Point(435, 440)); + offsets.put(R.drawable.elf_tap0019, new Point(435, 440)); + offsets.put(R.drawable.elf_pinchin_ball0020, new Point(520, 898)); + offsets.put(R.drawable.santa_tap0005, new Point(270, 509)); + offsets.put(R.drawable.santa_idle0009, new Point(416, 429)); + offsets.put(R.drawable.santa_temp_down01, new Point(415, 435)); + offsets.put(R.drawable.elf_pinchout0019, new Point(50, 0)); + offsets.put(R.drawable.snowman_tap0006, new Point(146, 221)); + offsets.put(R.drawable.elf_swiperight0021, new Point(427, 451)); + offsets.put(R.drawable.santa_swipeup0021, new Point(399, 471)); + offsets.put(R.drawable.elf_idle0019, new Point(435, 438)); + offsets.put(R.drawable.elf_swiperight0010, new Point(888, 568)); + offsets.put(R.drawable.elf_swipeup0001, new Point(435, 440)); + offsets.put(R.drawable.reindeer_swipedown0021, new Point(371, 437)); + offsets.put(R.drawable.snowman_swipeleft0019, new Point(429, 221)); + offsets.put(R.drawable.reindeer_shake0020, new Point(384, 99)); + offsets.put(R.drawable.snowman_tap0008, new Point(79, 221)); + offsets.put(R.drawable.santa_idle0020, new Point(415, 434)); + offsets.put(R.drawable.snowman_pinchout0015, new Point(237, 580)); + offsets.put(R.drawable.snowman_tap0024, new Point(429, 221)); + offsets.put(R.drawable.snowman_swipeup0004, new Point(429, 133)); + offsets.put(R.drawable.reindeer_swipeleft0001, new Point(342, 337)); + offsets.put(R.drawable.snowman_shake0007, new Point(108, 0)); + offsets.put(R.drawable.santa_swipeleft0015, new Point(415, 416)); + offsets.put(R.drawable.elf_tap0012, new Point(221, 272)); + offsets.put(R.drawable.elf_pinchout0003, new Point(250, 0)); + offsets.put(R.drawable.reindeer_shake0022, new Point(342, 357)); + offsets.put(R.drawable.reindeer_shake0005, new Point(384, 13)); + offsets.put(R.drawable.snowman_swipeleft0021, new Point(429, 221)); + offsets.put(R.drawable.reindeer_swipedown0006, new Point(384, 516)); + offsets.put(R.drawable.elf_swiperight0018, new Point(0, 538)); + offsets.put(R.drawable.elf_idle0008, new Point(435, 437)); + offsets.put(R.drawable.reindeer_swipeup0017, new Point(277, 119)); + offsets.put(R.drawable.elf_pinchin_ball0022, new Point(513, 738)); + offsets.put(R.drawable.elf_swipeup0018, new Point(454, 400)); + offsets.put(R.drawable.santa_swipeup0010, new Point(429, 266)); + offsets.put(R.drawable.snowman_pinchout0009, new Point(290, 553)); + offsets.put(R.drawable.elf_pinchin_ball0010, new Point(521, 653)); + offsets.put(R.drawable.snowman_tap0011, new Point(79, 221)); + offsets.put(R.drawable.santa_pinchout20014, new Point(0, 0)); + offsets.put(R.drawable.elf_swipeleft0006, new Point(330, 460)); + offsets.put(R.drawable.elf_swipeleft0004, new Point(372, 441)); + offsets.put(R.drawable.elf_tap0001, new Point(435, 440)); + offsets.put(R.drawable.snowman_swiperight0020, new Point(429, 221)); + offsets.put(R.drawable.reindeer_swiperight0015, new Point(0, 335)); + offsets.put(R.drawable.snowman_shake0008, new Point(110, 0)); + offsets.put(R.drawable.santa_idle0023, new Point(415, 435)); + offsets.put(R.drawable.elf_swipeup0009, new Point(357, 152)); + offsets.put(R.drawable.elf_swipeup0002, new Point(386, 400)); + offsets.put(R.drawable.snowman_swipedown0010, new Point(335, 435)); + offsets.put(R.drawable.santa_swipe_right20015, new Point(415, 353)); + offsets.put(R.drawable.reindeer_swipeleft0023, new Point(344, 337)); + offsets.put(R.drawable.santa_pinchout20003, new Point(0, 0)); + offsets.put(R.drawable.snowman_swiperight0013, new Point(429, 221)); + offsets.put(R.drawable.snowman_swipedown0015, new Point(429, 261)); + offsets.put(R.drawable.snowman_swipeup0014, new Point(346, 21)); + offsets.put(R.drawable.snowman_swipedown0008, new Point(207, 344)); + offsets.put(R.drawable.reindeer_pinchout0012, new Point(124, 69)); + offsets.put(R.drawable.santa_temp_zoom_in01, new Point(415, 435)); + offsets.put(R.drawable.reindeer_pinchin0021, new Point(0, 0)); + offsets.put(R.drawable.santa_tap0017, new Point(270, 423)); + offsets.put(R.drawable.snowman_shake0006, new Point(110, 0)); + offsets.put(R.drawable.reindeer_tap0006, new Point(342, 337)); + offsets.put(R.drawable.elf_idle0024, new Point(435, 440)); + offsets.put(R.drawable.santa_idle0034, new Point(416, 429)); + offsets.put(R.drawable.santa_swipeleft0005, new Point(258, 546)); + offsets.put(R.drawable.elf_pinchin_ball0027, new Point(459, 400)); + offsets.put(R.drawable.reindeer_tap0005, new Point(342, 337)); + offsets.put(R.drawable.elf_swipedown0020, new Point(435, 470)); + offsets.put(R.drawable.elf_idle0011, new Point(435, 436)); + offsets.put(R.drawable.snowman_swipeup0001, new Point(429, 221)); + offsets.put(R.drawable.santa_swipedown0001, new Point(415, 435)); + offsets.put(R.drawable.elf_shake0008, new Point(318, 362)); + offsets.put(R.drawable.reindeer_pinchout0022, new Point(228, 197)); + offsets.put(R.drawable.reindeer_pinchout0014, new Point(92, 30)); + offsets.put(R.drawable.snowman_swipedown0002, new Point(400, 266)); + offsets.put(R.drawable.reindeer_swiperight0001, new Point(342, 337)); + offsets.put(R.drawable.santa_swipedown0019, new Point(0, 0)); + offsets.put(R.drawable.santa_swipeleft0024, new Point(429, 424)); + offsets.put(R.drawable.reindeer_swiperight0005, new Point(354, 337)); + offsets.put(R.drawable.santa_pinchout20023, new Point(0, 0)); + offsets.put(R.drawable.snowman_swipeup0002, new Point(429, 211)); + offsets.put(R.drawable.santa_idle0022, new Point(415, 435)); + offsets.put(R.drawable.elf_swipeleft0010, new Point(317, 460)); + offsets.put(R.drawable.snowman_tap0007, new Point(95, 221)); + offsets.put(R.drawable.santa_swipedown0002, new Point(358, 435)); + offsets.put(R.drawable.snowman_pinchout0016, new Point(237, 580)); + offsets.put(R.drawable.santa_idle0018, new Point(415, 433)); + offsets.put(R.drawable.reindeer_shake0010, new Point(383, 13)); + offsets.put(R.drawable.santa_tap0014, new Point(270, 320)); + offsets.put(R.drawable.santa_shake0020, new Point(386, 420)); + offsets.put(R.drawable.snowman_swipeup0017, new Point(231, 33)); + offsets.put(R.drawable.elf_swipeup0023, new Point(435, 445)); + offsets.put(R.drawable.elf_tap0007, new Point(221, 272)); + offsets.put(R.drawable.snowman_idle0021, new Point(429, 219)); + offsets.put(R.drawable.elf_pinchin_ball0013, new Point(519, 169)); + offsets.put(R.drawable.santa_tap0021, new Point(270, 435)); + offsets.put(R.drawable.elf_pinchin_ball0018, new Point(506, 385)); + offsets.put(R.drawable.santa_pinchin0006, new Point(171, 275)); + offsets.put(R.drawable.reindeer_swipedown0015, new Point(349, 709)); + offsets.put(R.drawable.santa_swipe_right20007, new Point(341, 418)); + offsets.put(R.drawable.reindeer_swiperight0022, new Point(304, 370)); + offsets.put(R.drawable.santa_swipeleft0002, new Point(398, 476)); + offsets.put(R.drawable.santa_swipedown0004, new Point(340, 535)); + offsets.put(R.drawable.elf_idle0023, new Point(435, 440)); + offsets.put(R.drawable.santa_tap0020, new Point(270, 443)); + offsets.put(R.drawable.elf_tap0023, new Point(435, 440)); + offsets.put(R.drawable.reindeer_swipedown0016, new Point(357, 709)); + offsets.put(R.drawable.snowman_swipedown0005, new Point(285, 401)); + offsets.put(R.drawable.reindeer_tap0009, new Point(342, 337)); + offsets.put(R.drawable.snowman_swipeup0021, new Point(429, 220)); + offsets.put(R.drawable.elf_swipedown0006, new Point(435, 475)); + offsets.put(R.drawable.reindeer_swipeleft0011, new Point(284, 285)); + offsets.put(R.drawable.snowman_shake0014, new Point(87, 3)); + offsets.put(R.drawable.snowman_idle0006, new Point(429, 218)); + offsets.put(R.drawable.santa_swipe_right20004, new Point(350, 428)); + offsets.put(R.drawable.reindeer_swipeleft0005, new Point(326, 235)); + offsets.put(R.drawable.snowman_idle0004, new Point(429, 219)); + offsets.put(R.drawable.elf_shake0001, new Point(435, 440)); + offsets.put(R.drawable.santa_pinchout20013, new Point(0, 0)); + offsets.put(R.drawable.reindeer_tap0023, new Point(342, 337)); + offsets.put(R.drawable.elf_swipedown0022, new Point(435, 463)); + offsets.put(R.drawable.elf_swipeup0017, new Point(456, 380)); + offsets.put(R.drawable.snowman_pinchout0013, new Point(237, 580)); + offsets.put(R.drawable.santa_swipeleft0016, new Point(299, 540)); + offsets.put(R.drawable.snowman_pinchout0010, new Point(272, 568)); + offsets.put(R.drawable.snowman_tap0003, new Point(277, 248)); + offsets.put(R.drawable.santa_shake0001, new Point(355, 435)); + offsets.put(R.drawable.elf_swiperight0009, new Point(769, 641)); + offsets.put(R.drawable.santa_swipe_right20016, new Point(415, 370)); + offsets.put(R.drawable.elf_pinchout0016, new Point(0, 0)); + offsets.put(R.drawable.santa_idle0010, new Point(416, 429)); + offsets.put(R.drawable.elf_swiperight0006, new Point(441, 476)); + offsets.put(R.drawable.elf_swipeup0007, new Point(492, 165)); + offsets.put(R.drawable.elf_idle0017, new Point(435, 437)); + offsets.put(R.drawable.santa_swipeleft0008, new Point(127, 618)); + offsets.put(R.drawable.santa_pinchout20021, new Point(0, 0)); + offsets.put(R.drawable.reindeer_pinchin0013, new Point(0, 0)); + offsets.put(R.drawable.santa_idle0013, new Point(416, 429)); + offsets.put(R.drawable.snowman_swipedown0009, new Point(266, 281)); + offsets.put(R.drawable.santa_tap0023, new Point(415, 435)); + offsets.put(R.drawable.snowman_swipedown0014, new Point(429, 411)); + offsets.put(R.drawable.elf_tap0003, new Point(427, 434)); + offsets.put(R.drawable.snowman_pinchin0003, new Point(193, 109)); + offsets.put(R.drawable.santa_swipeleft0012, new Point(429, 558)); + offsets.put(R.drawable.snowman_idle0005, new Point(429, 218)); + offsets.put(R.drawable.snowman_idle0010, new Point(429, 217)); + offsets.put(R.drawable.santa_swipedown0016, new Point(429, 402)); + offsets.put(R.drawable.reindeer_swiperight0010, new Point(61, 1026)); + offsets.put(R.drawable.snowman_pinchout0012, new Point(237, 580)); + offsets.put(R.drawable.elf_idle0005, new Point(435, 438)); + offsets.put(R.drawable.reindeer_tap0002, new Point(346, 339)); + offsets.put(R.drawable.elf_tap0004, new Point(401, 413)); + offsets.put(R.drawable.santa_idle0030, new Point(416, 430)); + offsets.put(R.drawable.santa_swipeup0024, new Point(415, 435)); + offsets.put(R.drawable.elf_pinchin_ball0023, new Point(521, 583)); + offsets.put(R.drawable.reindeer_pinchin0001, new Point(0, 0)); + offsets.put(R.drawable.reindeer_pinchout0009, new Point(212, 177)); + offsets.put(R.drawable.reindeer_pinchout0001, new Point(342, 337)); + offsets.put(R.drawable.santa_swipeleft0022, new Point(398, 448)); + offsets.put(R.drawable.reindeer_swiperight0006, new Point(363, 644)); + offsets.put(R.drawable.snowman_tap0010, new Point(79, 221)); + offsets.put(R.drawable.elf_pinchout0024, new Point(444, 455)); + offsets.put(R.drawable.elf_pinchout0001, new Point(435, 440)); + offsets.put(R.drawable.snowman_swipedown0023, new Point(429, 221)); + offsets.put(R.drawable.santa_swipe_right20003, new Point(347, 435)); + offsets.put(R.drawable.snowman_swipeleft0020, new Point(429, 221)); + offsets.put(R.drawable.reindeer_shake0024, new Point(342, 339)); + offsets.put(R.drawable.snowman_pinchin0022, new Point(226, 197)); + offsets.put(R.drawable.snowman_shake0020, new Point(73, 5)); + offsets.put(R.drawable.santa_tap0013, new Point(270, 412)); + offsets.put(R.drawable.elf_swipeleft0003, new Point(393, 440)); + offsets.put(R.drawable.snowman_shake0024, new Point(382, 216)); + offsets.put(R.drawable.santa_tap0007, new Point(270, 586)); + offsets.put(R.drawable.snowman_shake0013, new Point(88, 0)); + offsets.put(R.drawable.snowman_tap0021, new Point(118, 221)); + offsets.put(R.drawable.elf_swipeup0010, new Point(378, 84)); + offsets.put(R.drawable.elf_swipedown0011, new Point(397, 560)); + offsets.put(R.drawable.snowman_pinchin0023, new Point(299, 207)); + offsets.put(R.drawable.elf_swiperight0019, new Point(83, 515)); + offsets.put(R.drawable.reindeer_swipeup0008, new Point(210, 47)); + offsets.put(R.drawable.snowman_tap0012, new Point(79, 221)); + offsets.put(R.drawable.reindeer_swipeleft0015, new Point(338, 400)); + offsets.put(R.drawable.reindeer_tap0011, new Point(342, 337)); + offsets.put(R.drawable.elf_swiperight0013, new Point(0, 730)); + offsets.put(R.drawable.santa_idle0028, new Point(415, 431)); + offsets.put(R.drawable.snowman_idle0024, new Point(429, 221)); + offsets.put(R.drawable.snowman_pinchin0015, new Point(1280/2, 1280/2)); + offsets.put(R.drawable.santa_pinchin0010, new Point(91, 146)); + offsets.put(R.drawable.snowman_pinchin0002, new Point(374, 193)); + offsets.put(R.drawable.elf_swipeup0014, new Point(468, 315)); + offsets.put(R.drawable.reindeer_swipeleft0020, new Point(384, 342)); + offsets.put(R.drawable.elf_pinchin_ball0003, new Point(460, 584)); + offsets.put(R.drawable.santa_swipeleft0001, new Point(415, 435)); + offsets.put(R.drawable.elf_pinchin_ball0021, new Point(500, 990)); + offsets.put(R.drawable.reindeer_swipeleft0014, new Point(317, 357)); + offsets.put(R.drawable.reindeer_tap0019, new Point(342, 337)); + offsets.put(R.drawable.reindeer_swipeleft0017, new Point(376, 371)); + offsets.put(R.drawable.reindeer_tap0018, new Point(342, 337)); + offsets.put(R.drawable.santa_tap0024, new Point(415, 435)); + offsets.put(R.drawable.snowman_pinchout0017, new Point(237, 580)); + offsets.put(R.drawable.santa_tap0010, new Point(270, 536)); + offsets.put(R.drawable.reindeer_swiperight0019, new Point(384, 389)); + offsets.put(R.drawable.elf_shake0019, new Point(231, 285)); + offsets.put(R.drawable.snowman_pinchin0016, new Point(167, 913)); + offsets.put(R.drawable.elf_swipeleft0001, new Point(435, 440)); + offsets.put(R.drawable.snowman_shake0022, new Point(64, 16)); + offsets.put(R.drawable.elf_pinchout0009, new Point(0, 0)); + offsets.put(R.drawable.santa_shake0012, new Point(355, 435)); + offsets.put(R.drawable.santa_pinchin0013, new Point(136, 219)); + offsets.put(R.drawable.elf_swipeleft0014, new Point(395, 460)); + offsets.put(R.drawable.santa_swipeup0002, new Point(418, 418)); + offsets.put(R.drawable.elf_swipedown0008, new Point(434, 515)); + offsets.put(R.drawable.elf_swipedown0007, new Point(435, 495)); + offsets.put(R.drawable.snowman_tap0001, new Point(429, 221)); + offsets.put(R.drawable.snowman_pinchout0007, new Point(325, 506)); + offsets.put(R.drawable.santa_idle0037, new Point(416, 430)); + offsets.put(R.drawable.santa_swipedown0012, new Point(265, 264)); + offsets.put(R.drawable.santa_idle0015, new Point(415, 431)); + offsets.put(R.drawable.santa_pinchout20019, new Point(0, 0)); + offsets.put(R.drawable.reindeer_swiperight0014, new Point(0, 335)); + offsets.put(R.drawable.reindeer_swipeleft0006, new Point(318, 177)); + offsets.put(R.drawable.santa_swipe_right20022, new Point(415, 435)); + offsets.put(R.drawable.santa_swipedown0020, new Point(0, 0)); + offsets.put(R.drawable.reindeer_tap0001, new Point(342, 337)); + offsets.put(R.drawable.elf_idle0013, new Point(435, 436)); + offsets.put(R.drawable.reindeer_swipeup0024, new Point(342, 337)); + offsets.put(R.drawable.santa_swipeup0013, new Point(312, 193)); + offsets.put(R.drawable.reindeer_pinchout0005, new Point(318, 308)); + offsets.put(R.drawable.santa_shake0008, new Point(255, 477)); + offsets.put(R.drawable.santa_pinchin0011, new Point(96, 154)); + offsets.put(R.drawable.reindeer_swipeleft0016, new Point(353, 389)); + offsets.put(R.drawable.snowman_swipeup0006, new Point(429, 33)); + offsets.put(R.drawable.snowman_shake0012, new Point(91, 0)); + offsets.put(R.drawable.elf_shake0017, new Point(201, 183)); + offsets.put(R.drawable.reindeer_swipedown0020, new Point(384, 510)); + offsets.put(R.drawable.santa_idle0042, new Point(415, 433)); + offsets.put(R.drawable.reindeer_pinchout0002, new Point(342, 337)); + offsets.put(R.drawable.santa_idle0044, new Point(415, 434)); + offsets.put(R.drawable.elf_swiperight0024, new Point(435, 440)); + offsets.put(R.drawable.santa_idle0006, new Point(415, 431)); + offsets.put(R.drawable.reindeer_pinchin0009, new Point(0, 0)); + offsets.put(R.drawable.santa_swipeleft0019, new Point(429, 428)); + offsets.put(R.drawable.reindeer_swipedown0011, new Point(384, 709)); + offsets.put(R.drawable.elf_shake0005, new Point(201, 183)); + offsets.put(R.drawable.snowman_swipeleft0010, new Point(429, 221)); + offsets.put(R.drawable.santa_idle0025, new Point(415, 434)); + offsets.put(R.drawable.reindeer_shake0006, new Point(384, 14)); + offsets.put(R.drawable.santa_tap0006, new Point(270, 557)); + offsets.put(R.drawable.santa_pinchout20008, new Point(0, 0)); + offsets.put(R.drawable.elf_pinchin_ball0002, new Point(447, 512)); + offsets.put(R.drawable.snowman_swipeup0009, new Point(429, 21)); + offsets.put(R.drawable.elf_swiperight0005, new Point(407, 458)); + offsets.put(R.drawable.santa_idle0039, new Point(415, 431)); + offsets.put(R.drawable.elf_swipeup0019, new Point(434, 440)); + offsets.put(R.drawable.elf_swipeleft0011, new Point(295, 460)); + offsets.put(R.drawable.reindeer_pinchout0008, new Point(246, 219)); + offsets.put(R.drawable.snowman_shake0023, new Point(382, 216)); + offsets.put(R.drawable.snowman_swiperight0021, new Point(429, 221)); + offsets.put(R.drawable.santa_pinchout20022, new Point(0, 0)); + offsets.put(R.drawable.elf_pinchin_ball0019, new Point(520, 618)); + offsets.put(R.drawable.snowman_shake0004, new Point(122, 0)); + offsets.put(R.drawable.elf_swipeup0024, new Point(435, 440)); + offsets.put(R.drawable.reindeer_pinchout0011, new Point(148, 99)); + offsets.put(R.drawable.santa_swipe_right20014, new Point(416, 340)); + offsets.put(R.drawable.elf_pinchin_ball0015, new Point(515, 95)); + offsets.put(R.drawable.santa_idle0002, new Point(415, 434)); + offsets.put(R.drawable.santa_pinchout20007, new Point(0, 0)); + offsets.put(R.drawable.santa_pinchin0014, new Point(170, 275)); + offsets.put(R.drawable.santa_swipedown0003, new Point(340, 460)); + offsets.put(R.drawable.snowman_pinchout0024, new Point(429, 221)); + offsets.put(R.drawable.santa_shake0009, new Point(243, 477)); + offsets.put(R.drawable.elf_tap0002, new Point(435, 440)); + offsets.put(R.drawable.santa_swipeleft0023, new Point(429, 429)); + offsets.put(R.drawable.elf_shake0015, new Point(263, 285)); + offsets.put(R.drawable.santa_swipe_right20008, new Point(336, 417)); + offsets.put(R.drawable.reindeer_tap0016, new Point(342, 337)); + offsets.put(R.drawable.elf_shake0020, new Point(324, 362)); + offsets.put(R.drawable.elf_shake0003, new Point(176, 324)); + offsets.put(R.drawable.reindeer_swipeup0011, new Point(210, 34)); + offsets.put(R.drawable.reindeer_tap0015, new Point(342, 337)); + offsets.put(R.drawable.santa_tap0016, new Point(270, 443)); + offsets.put(R.drawable.reindeer_pinchin0012, new Point(0, 0)); + offsets.put(R.drawable.elf_swipeleft0005, new Point(351, 460)); + offsets.put(R.drawable.elf_swipeup0022, new Point(435, 458)); + offsets.put(R.drawable.snowman_swipeleft0009, new Point(429, 221)); + offsets.put(R.drawable.santa_swipeup0014, new Point(311, 178)); + offsets.put(R.drawable.elf_pinchin_ball0026, new Point(467, 340)); + offsets.put(R.drawable.elf_swipedown0017, new Point(435, 470)); + offsets.put(R.drawable.santa_idle0012, new Point(416, 429)); + offsets.put(R.drawable.reindeer_swipedown0003, new Point(352, 366)); + offsets.put(R.drawable.santa_swipeleft0021, new Point(270, 462)); + offsets.put(R.drawable.santa_pinchin0024, new Point(415, 435)); + offsets.put(R.drawable.santa_pinchout20018, new Point(0, 0)); + offsets.put(R.drawable.reindeer_swipeup0022, new Point(221, 344)); + offsets.put(R.drawable.snowman_swiperight0019, new Point(429, 221)); + offsets.put(R.drawable.santa_idle0026, new Point(415, 433)); + offsets.put(R.drawable.reindeer_pinchout0013, new Point(106, 46)); + offsets.put(R.drawable.snowman_swipedown0003, new Point(359, 311)); + offsets.put(R.drawable.elf_swiperight0014, new Point(0, 768)); + offsets.put(R.drawable.snowman_tap0005, new Point(213, 221)); + offsets.put(R.drawable.snowman_swiperight0023, new Point(429, 221)); + offsets.put(R.drawable.reindeer_shake0007, new Point(383, 15)); + offsets.put(R.drawable.elf_swiperight0012, new Point(1280/2, 1280/2)); + offsets.put(R.drawable.snowman_pinchin0018, new Point(167, 370)); + offsets.put(R.drawable.santa_idle0045, new Point(415, 434)); + offsets.put(R.drawable.santa_swipeup0004, new Point(426, 385)); + offsets.put(R.drawable.santa_swipeleft0010, new Point(165, 589)); + offsets.put(R.drawable.elf_swipeleft0021, new Point(435, 375)); + offsets.put(R.drawable.reindeer_swiperight0013, new Point(0, 569)); + offsets.put(R.drawable.reindeer_swiperight0024, new Point(342, 337)); + offsets.put(R.drawable.reindeer_swipeleft0024, new Point(342, 337)); + offsets.put(R.drawable.elf_idle0004, new Point(435, 438)); + offsets.put(R.drawable.snowman_tap0014, new Point(83, 221)); + offsets.put(R.drawable.reindeer_pinchin0005, new Point(0, 0)); + offsets.put(R.drawable.santa_shake0011, new Point(326, 453)); + offsets.put(R.drawable.santa_swipedown0015, new Point(257, 0)); + offsets.put(R.drawable.reindeer_swipeup0012, new Point(210, 35)); + offsets.put(R.drawable.snowman_swipedown0004, new Point(320, 356)); + offsets.put(R.drawable.reindeer_tap0017, new Point(342, 337)); + offsets.put(R.drawable.reindeer_pinchin0002, new Point(0, 0)); + offsets.put(R.drawable.santa_idle0033, new Point(416, 429)); + offsets.put(R.drawable.elf_pinchout0002, new Point(376, 324)); + offsets.put(R.drawable.reindeer_pinchin0006, new Point(0, 0)); + offsets.put(R.drawable.elf_pinchin_ball0009, new Point(500, 990)); + offsets.put(R.drawable.santa_swipeup0015, new Point(267, 203)); + offsets.put(R.drawable.snowman_swipeleft0018, new Point(429, 221)); + offsets.put(R.drawable.reindeer_swipeup0005, new Point(344, 186)); + offsets.put(R.drawable.reindeer_swipeup0001, new Point(342, 337)); + offsets.put(R.drawable.santa_pinchin0012, new Point(111, 178)); + offsets.put(R.drawable.santa_pinchout20009, new Point(0, 0)); + offsets.put(R.drawable.santa_pinchout20016, new Point(0, 0)); + offsets.put(R.drawable.santa_tap0003, new Point(270, 435)); + offsets.put(R.drawable.elf_idle0020, new Point(435, 438)); + offsets.put(R.drawable.elf_swipeleft0018, new Point(435, 441)); + offsets.put(R.drawable.santa_swipedown0024, new Point(0, 435)); + offsets.put(R.drawable.snowman_shake0009, new Point(107, 0)); + offsets.put(R.drawable.santa_pinchout20017, new Point(0, 0)); + offsets.put(R.drawable.elf_idle0003, new Point(435, 439)); + offsets.put(R.drawable.snowman_shake0018, new Point(72, 0)); + offsets.put(R.drawable.elf_swipeup0008, new Point(378, 188)); + offsets.put(R.drawable.reindeer_pinchout0019, new Point(118, 62)); + offsets.put(R.drawable.snowman_swipeup0019, new Point(376, 133)); + offsets.put(R.drawable.elf_swiperight0004, new Point(395, 453)); + offsets.put(R.drawable.elf_shake0014, new Point(318, 362)); + offsets.put(R.drawable.elf_swiperight0015, new Point(0, 572)); + offsets.put(R.drawable.elf_pinchout0010, new Point(0, 0)); + offsets.put(R.drawable.snowman_swipedown0022, new Point(429, 221)); + offsets.put(R.drawable.reindeer_pinchin0017, new Point(0, 0)); + offsets.put(R.drawable.snowman_pinchout0008, new Point(307, 532)); + offsets.put(R.drawable.santa_swipeleft0011, new Point(415, 435)); + offsets.put(R.drawable.elf_swiperight0016, new Point(0, 623)); + offsets.put(R.drawable.reindeer_swiperight0002, new Point(342, 337)); + offsets.put(R.drawable.elf_pinchin_ball0004, new Point(472, 655)); + offsets.put(R.drawable.elf_swipeleft0016, new Point(444, 441)); + offsets.put(R.drawable.snowman_swiperight0002, new Point(139, 221)); + offsets.put(R.drawable.snowman_swiperight0004, new Point(224, 221)); + offsets.put(R.drawable.santa_pinchout20024, new Point(0, 0)); + offsets.put(R.drawable.santa_swipe_right20024, new Point(415, 435)); + offsets.put(R.drawable.santa_pinchin0023, new Point(358, 435)); + offsets.put(R.drawable.reindeer_pinchout0020, new Point(147, 97)); + offsets.put(R.drawable.santa_swipeup0008, new Point(429, 283)); + offsets.put(R.drawable.elf_pinchin_ball0030, new Point(435, 480)); + offsets.put(R.drawable.snowman_swipeup0015, new Point(253, 21)); + offsets.put(R.drawable.santa_swipedown0017, new Point(0, 0)); + offsets.put(R.drawable.elf_pinchin_ball0032, new Point(435, 445)); + offsets.put(R.drawable.snowman_swipedown0017, new Point(429, 129)); + offsets.put(R.drawable.santa_pinchout20005, new Point(0, 0)); + offsets.put(R.drawable.snowman_swipeleft0014, new Point(429, 221)); + offsets.put(R.drawable.reindeer_swiperight0011, new Point(26, 1021)); + offsets.put(R.drawable.reindeer_shake0009, new Point(384, 15)); + offsets.put(R.drawable.snowman_idle0012, new Point(429, 217)); + offsets.put(R.drawable.reindeer_swiperight0007, new Point(313, 629)); + offsets.put(R.drawable.snowman_idle0015, new Point(429, 217)); + offsets.put(R.drawable.santa_tap0004, new Point(270, 443)); + offsets.put(R.drawable.reindeer_pinchin0007, new Point(0, 0)); + offsets.put(R.drawable.santa_pinchin0021, new Point(270, 435)); + offsets.put(R.drawable.santa_swipe_right20012, new Point(426, 350)); + offsets.put(R.drawable.elf_swiperight0001, new Point(435, 440)); + offsets.put(R.drawable.snowman_pinchin0019, new Point(167, 234)); + offsets.put(R.drawable.reindeer_shake0017, new Point(384, 14)); + offsets.put(R.drawable.santa_swipe_right20006, new Point(346, 420)); + offsets.put(R.drawable.snowman_pinchout0023, new Point(382, 243)); + offsets.put(R.drawable.elf_shake0022, new Point(336, 324)); + offsets.put(R.drawable.santa_swipe_right20018, new Point(415, 389)); + offsets.put(R.drawable.snowman_swiperight0010, new Point(235, 221)); + offsets.put(R.drawable.santa_swipe_right20013, new Point(420, 336)); + offsets.put(R.drawable.snowman_swipeleft0015, new Point(429, 221)); + offsets.put(R.drawable.elf_idle0022, new Point(435, 439)); + offsets.put(R.drawable.santa_shake0007, new Point(257, 475)); + offsets.put(R.drawable.elf_swiperight0008, new Point(611, 565)); + offsets.put(R.drawable.santa_pinchin0020, new Point(235, 505)); + offsets.put(R.drawable.snowman_swipeleft0017, new Point(429, 221)); + offsets.put(R.drawable.elf_swipeleft0017, new Point(422, 440)); + offsets.put(R.drawable.santa_pinchin0003, new Point(268, 435)); + offsets.put(R.drawable.snowman_pinchout0004, new Point(377, 390)); + offsets.put(R.drawable.santa_tap0001, new Point(415, 435)); + offsets.put(R.drawable.santa_tap0018, new Point(270, 404)); + offsets.put(R.drawable.snowman_swipedown0019, new Point(429, 262)); + offsets.put(R.drawable.santa_idle0004, new Point(415, 432)); + offsets.put(R.drawable.reindeer_swipeup0004, new Point(342, 197)); + offsets.put(R.drawable.reindeer_swiperight0020, new Point(383, 352)); + offsets.put(R.drawable.santa_pinchin0022, new Point(270, 435)); + offsets.put(R.drawable.snowman_swipeup0018, new Point(214, 71)); + offsets.put(R.drawable.reindeer_swipeup0002, new Point(342, 321)); + offsets.put(R.drawable.elf_tap0022, new Point(435, 440)); + offsets.put(R.drawable.reindeer_swipeleft0009, new Point(284, 276)); + offsets.put(R.drawable.santa_idle0047, new Point(415, 435)); + offsets.put(R.drawable.snowman_swiperight0014, new Point(428, 221)); + offsets.put(R.drawable.reindeer_shake0012, new Point(384, 14)); + offsets.put(R.drawable.elf_pinchout0021, new Point(184, 0)); + offsets.put(R.drawable.snowman_pinchin0017, new Point(167, 596)); + offsets.put(R.drawable.santa_swipe_right20019, new Point(415, 435)); + offsets.put(R.drawable.reindeer_shake0011, new Point(383, 13)); + offsets.put(R.drawable.santa_tap0009, new Point(269, 567)); + offsets.put(R.drawable.elf_pinchin_ball0005, new Point(462, 727)); + offsets.put(R.drawable.snowman_pinchin0013, new Point(90, 1008)); + offsets.put(R.drawable.santa_swipeup0011, new Point(429, 221)); + offsets.put(R.drawable.reindeer_pinchin0010, new Point(0, 0)); + offsets.put(R.drawable.elf_swipedown0019, new Point(435, 474)); + offsets.put(R.drawable.snowman_tap0018, new Point(98, 221)); + offsets.put(R.drawable.elf_shake0007, new Point(244, 285)); + offsets.put(R.drawable.elf_idle0015, new Point(435, 436)); + offsets.put(R.drawable.santa_pinchin0008, new Point(111, 178)); + offsets.put(R.drawable.snowman_idle0008, new Point(429, 217)); + offsets.put(R.drawable.elf_swipedown0024, new Point(435, 440)); + offsets.put(R.drawable.reindeer_swipedown0022, new Point(354, 384)); + offsets.put(R.drawable.reindeer_tap0007, new Point(342, 337)); + offsets.put(R.drawable.elf_swipedown0013, new Point(397, 628)); + offsets.put(R.drawable.elf_pinchin_ball0028, new Point(434, 440)); + offsets.put(R.drawable.snowman_swipeleft0008, new Point(429, 221)); + offsets.put(R.drawable.snowman_tap0023, new Point(169, 221)); + offsets.put(R.drawable.reindeer_tap0012, new Point(342, 337)); + offsets.put(R.drawable.elf_tap0009, new Point(132, 248)); + offsets.put(R.drawable.elf_swipedown0004, new Point(435, 434)); + offsets.put(R.drawable.santa_shake0004, new Point(204, 478)); + offsets.put(R.drawable.reindeer_swipedown0002, new Point(344, 344)); + offsets.put(R.drawable.elf_pinchout0005, new Point(0, 0)); + offsets.put(R.drawable.snowman_swipeleft0002, new Point(429, 221)); + offsets.put(R.drawable.elf_swipedown0021, new Point(435, 467)); + offsets.put(R.drawable.reindeer_tap0021, new Point(342, 337)); + offsets.put(R.drawable.snowman_shake0011, new Point(95, 0)); + offsets.put(R.drawable.elf_pinchin_ball0017, new Point(520, 222)); + offsets.put(R.drawable.santa_shake0018, new Point(393, 420)); + offsets.put(R.drawable.reindeer_swiperight0004, new Point(348, 337)); + offsets.put(R.drawable.snowman_swipeleft0012, new Point(429, 221)); + offsets.put(R.drawable.reindeer_swipeup0009, new Point(210, 38)); + offsets.put(R.drawable.reindeer_shake0003, new Point(384, 193)); + offsets.put(R.drawable.elf_idle0016, new Point(435, 437)); + offsets.put(R.drawable.santa_swipeup0017, new Point(274, 245)); + offsets.put(R.drawable.santa_swipeup0009, new Point(429, 271)); + + } + +} diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/RetryableAsyncTask.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/RetryableAsyncTask.java new file mode 100644 index 000000000..5155fe33c --- /dev/null +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/RetryableAsyncTask.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.dasherdancer; + +import android.os.AsyncTask; +import android.util.Log; + +/** + * Async task that supports a full retry operation. + */ +public abstract class RetryableAsyncTask extends AsyncTask { + + private static final String TAG = "RetryableAT"; + + abstract boolean shouldRetry(); + + abstract void onPrepareForRetry(); + + C retrySelf(A[] params) { + if (shouldRetry()) { + onPrepareForRetry(); + return doInBackground(params); + } else { + Log.d(TAG, "Should not retry, canceling task"); + + cancel(true); + return null; + } + } + +} diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Santa.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Santa.java index 3f920a538..428d7d42c 100644 --- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Santa.java +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Santa.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -263,7 +263,31 @@ public int[] getFrames(int animationKey) { return sFrames[animationKey]; } - @Override + @Override + public int getSoundResource(int animationid) { + switch (animationid) { + case Character.ANIM_PINCH_IN: + return R.raw.santa_pinchin; + case Character.ANIM_PINCH_OUT: + return R.raw.santa_pinchout; + case Character.ANIM_SHAKE: + return R.raw.santa_shake; + case Character.ANIM_SWIPE_UP: + return R.raw.santa_swipeup; + case Character.ANIM_SWIPE_LEFT: + return R.raw.santa_swipeleft; + case Character.ANIM_SWIPE_RIGHT: + return R.raw.santa_swiperight; + case Character.ANIM_SWIPE_DOWN: + return R.raw.santa_swipedown; + case Character.ANIM_TAP: + return R.raw.santa_tap; + } + + return -1; + } + + @Override public String getCharacterName() { return "s"; } diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Snowman.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Snowman.java index b80e793c1..436d32a43 100644 --- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Snowman.java +++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Snowman.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -213,7 +213,31 @@ public int[] getFrames(int animationKey) { return sFrames[animationKey]; } - @Override + @Override + public int getSoundResource(int animationid) { + switch (animationid) { + case Character.ANIM_PINCH_IN: + return R.raw.snowman_pinchin; + case Character.ANIM_PINCH_OUT: + return R.raw.snowman_pinchout; + case Character.ANIM_SHAKE: + return R.raw.snowman_shake; + case Character.ANIM_SWIPE_UP: + return R.raw.snowman_swipeup; + case Character.ANIM_SWIPE_DOWN: + return R.raw.snowman_swipedown; + case Character.ANIM_SWIPE_LEFT: + return R.raw.snowman_swipeleft; + case Character.ANIM_SWIPE_RIGHT: + return R.raw.snowman_swiperight; + case Character.ANIM_TAP: + return R.raw.snowman_tap; + } + + return -1; + } + + @Override public String getCharacterName() { return "t"; } diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer.png b/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer.png index 8adbd5a79..1d3025f60 100644 Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer.png and b/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer.png differ diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer_p.png b/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer_p.png index b3287bd84..83b08e228 100644 Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer_p.png and b/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer_p.png differ diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_select_character.png b/dasherdancer/src/main/res/drawable-hdpi/btn_select_character.png index ad9d15a74..2096884d1 100644 Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_select_character.png and b/dasherdancer/src/main/res/drawable-hdpi/btn_select_character.png differ diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_select_character_pressed.png b/dasherdancer/src/main/res/drawable-hdpi/btn_select_character_pressed.png index 3ac4e48b5..242373190 100644 Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_select_character_pressed.png and b/dasherdancer/src/main/res/drawable-hdpi/btn_select_character_pressed.png differ diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_x_out.png b/dasherdancer/src/main/res/drawable-hdpi/btn_x_out.png index 0c07d16cb..855e3f9a1 100644 Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_x_out.png and b/dasherdancer/src/main/res/drawable-hdpi/btn_x_out.png differ diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_x_out_pressed.png b/dasherdancer/src/main/res/drawable-hdpi/btn_x_out_pressed.png index e8fbe8fe8..e3bc0aa24 100644 Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_x_out_pressed.png and b/dasherdancer/src/main/res/drawable-hdpi/btn_x_out_pressed.png differ diff --git a/dasherdancer/src/main/res/drawable-hdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-hdpi/ic_launcher.png index 63fddf6e5..81b9be3d0 100644 Binary files a/dasherdancer/src/main/res/drawable-hdpi/ic_launcher.png and b/dasherdancer/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_left.png b/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_left.png index 36ba0582e..02ed25381 100644 Binary files a/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_left.png and b/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_left.png differ diff --git a/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_right.png b/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_right.png index 22e17faaa..b103b4254 100644 Binary files a/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_right.png and b/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_right.png differ diff --git a/dasherdancer/src/main/res/drawable-hdpi/img_mint_loading_spinner.png b/dasherdancer/src/main/res/drawable-hdpi/img_mint_loading_spinner.png index ad10a84c1..57b3bb83d 100644 Binary files a/dasherdancer/src/main/res/drawable-hdpi/img_mint_loading_spinner.png and b/dasherdancer/src/main/res/drawable-hdpi/img_mint_loading_spinner.png differ diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer.png b/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer.png index a8223660d..82a9ff4a0 100644 Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer.png and b/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer.png differ diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer_p.png b/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer_p.png index 012ec450c..a20b3ed09 100644 Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer_p.png and b/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer_p.png differ diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_select_character.png b/dasherdancer/src/main/res/drawable-mdpi/btn_select_character.png index 07c2b2425..a781313c8 100644 Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_select_character.png and b/dasherdancer/src/main/res/drawable-mdpi/btn_select_character.png differ diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_select_character_pressed.png b/dasherdancer/src/main/res/drawable-mdpi/btn_select_character_pressed.png index d3007b335..3cca47b3e 100644 Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_select_character_pressed.png and b/dasherdancer/src/main/res/drawable-mdpi/btn_select_character_pressed.png differ diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_x_out.png b/dasherdancer/src/main/res/drawable-mdpi/btn_x_out.png index 173dd9af4..d9390095e 100644 Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_x_out.png and b/dasherdancer/src/main/res/drawable-mdpi/btn_x_out.png differ diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_x_out_pressed.png b/dasherdancer/src/main/res/drawable-mdpi/btn_x_out_pressed.png index a3aa8a45f..21aa3f789 100644 Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_x_out_pressed.png and b/dasherdancer/src/main/res/drawable-mdpi/btn_x_out_pressed.png differ diff --git a/dasherdancer/src/main/res/drawable-mdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-mdpi/ic_launcher.png index 69e443b8c..32c863e73 100644 Binary files a/dasherdancer/src/main/res/drawable-mdpi/ic_launcher.png and b/dasherdancer/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_left.png b/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_left.png index cf2884ffb..e2e8a3b38 100644 Binary files a/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_left.png and b/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_left.png differ diff --git a/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_right.png b/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_right.png index 47e24e564..713ccd03e 100644 Binary files a/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_right.png and b/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_right.png differ diff --git a/dasherdancer/src/main/res/drawable-mdpi/img_mint_loading_spinner.png b/dasherdancer/src/main/res/drawable-mdpi/img_mint_loading_spinner.png index 45d0fdcfe..e9da7ea44 100644 Binary files a/dasherdancer/src/main/res/drawable-mdpi/img_mint_loading_spinner.png and b/dasherdancer/src/main/res/drawable-mdpi/img_mint_loading_spinner.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0001.png index 621bf3fe9..94f95aecf 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0001.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0002.png index 5b032ba21..412dfe295 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0002.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0003.png index 78df727b6..cf9e02a5b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0003.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0004.png index d06f5bb0c..620a0aa44 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0004.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0005.png index 96a5b2cee..b51da9fd5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0005.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0006.png index ab93fb42c..c6e933880 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0006.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0007.png index a9cc24e3e..ee4245d31 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0007.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0008.png index 28fe82578..883d3b586 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0008.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0009.png index 92f75957d..1a1270206 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0009.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0010.png index 4035690fe..5c0b7e84e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0010.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0011.png index 6be2ad95d..90e40dcb0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0011.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0012.png index 4cb6b311a..07695b481 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0012.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0013.png index 6be2ad95d..90e40dcb0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0013.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0014.png index 4035690fe..5c0b7e84e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0014.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0015.png index 3fb7ecafd..7bfbfcb5a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0015.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0016.png index 92f75957d..1a1270206 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0016.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0017.png index bc91b74b8..66e8e0c53 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0017.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0018.png index a9cc24e3e..ee4245d31 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0018.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0019.png index 3f1c99136..2f203cbe3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0019.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0020.png index b85944579..5c75cf597 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0020.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0021.png index 37464b038..4fa74bc7e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0021.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0022.png index f93e3a806..5c74674e2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0022.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0023.png index 5b032ba21..412dfe295 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0023.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0024.png index e0d068825..8a83611f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0024.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0001.png index 908d5e464..80a5c5837 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0001.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0002.png index 6b7416753..15d15f762 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0002.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0003.png index f065f5455..3c6168006 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0003.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0004.png index cb048ba00..2ba8e4fde 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0004.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0005.png index 2d07753bf..3fa93bb24 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0005.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0006.png index 6bce31a51..d84f537be 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0006.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0007.png index 51261dfd4..32e0375b0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0007.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0008.png index 1b383a8dd..a8c173a42 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0008.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0009.png index ab49ad520..44cd5b441 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0009.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0010.png index bbdcd4439..8cbd83128 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0010.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0011.png index ee6cbbb41..3550486b6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0011.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0012.png index e3f1541cf..849d221ec 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0012.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0013.png index a5f464b28..8015878a1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0013.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0014.png index 6f8cb9a26..11537b3d0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0014.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0015.png index 95157c370..c19b764ce 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0015.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0016.png index 333a01f18..9d27f7eac 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0016.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0017.png index a8e3e235b..5b3f5762e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0017.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0018.png index 595400797..205d82532 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0018.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0019.png index ebe25c7d7..9e3e83989 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0019.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0020.png index 917f659e0..480a04871 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0020.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0021.png index 40c6a4692..2a5f2d74e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0021.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0022.png index 04f6eafb4..cc484c86e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0022.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0023.png index e2939bc15..4dd50f2fc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0023.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0024.png index 934316592..3d3ea7d53 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0024.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0025.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0025.png index d8fd29edf..bbcc71487 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0025.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0025.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0026.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0026.png index c46c1e9af..69fb85970 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0026.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0026.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0027.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0027.png index 3818c7865..f4de473fa 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0027.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0027.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0028.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0028.png index d0dc54e35..5ed5575c0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0028.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0028.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0029.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0029.png index cb8bee0dd..092d542d5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0029.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0029.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0030.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0030.png index 9bd7dfdb3..e4c9c1140 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0030.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0030.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0031.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0031.png index 1081a6ce6..84fc59117 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0031.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0031.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0032.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0032.png index ebbfe0fa6..81f86d9b8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0032.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0032.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0001.png index 574dad317..6d25b2cac 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0001.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0002.png index 1b62088d9..800f33621 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0002.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0003.png index 0a3555ecb..c2e27669b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0003.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0004.png index f830acc38..29bd14df8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0004.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0005.png index 8cdbe12a2..010e09741 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0005.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0006.png index 0385480c6..c53e31c7c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0006.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0007.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0007.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0008.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0008.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0009.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0009.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0010.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0010.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0011.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0011.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0012.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0012.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0013.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0013.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0014.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0014.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0015.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0015.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0016.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0016.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0017.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0017.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0018.png index 2999b0510..74480b7b1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0018.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0019.png index d917dc91f..9cc241ab7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0019.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0020.png index 4bb4408fe..adc450730 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0020.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0021.png index f3699e2b2..8d4debf29 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0021.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0022.png index d6eb12ad1..d7ec46d7b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0022.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0023.png index 30b88baa2..edeff0123 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0023.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0024.png index e8aa47e39..e382bbbc7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0024.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0001.png index 995bd0b79..5b4a94851 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0001.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0002.png index 7b535b22d..a3f2f9d06 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0002.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0003.png index e0cab467f..fdbd52bc7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0003.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0004.png index 4818f79aa..db8d53c29 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0004.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0005.png index 8a552da60..28d1c80be 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0005.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0006.png index 0341331be..9c9cf74ab 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0006.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0007.png index 7d54c3c73..2b2215568 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0007.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0008.png index 1b4961c81..fe940deca 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0008.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0009.png index 8ab076220..aecc2ad63 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0009.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0010.png index 1bf77a142..bfe288c47 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0010.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0011.png index 284b1a5df..85dce3d2e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0011.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0012.png index 5b7c199cf..02b67ca83 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0012.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0013.png index 78b3bbd6e..6a803c330 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0013.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0014.png index c9ad0c741..753499c0a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0014.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0015.png index 43370b68b..d83366615 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0015.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0016.png index 75a8b07ef..321438892 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0016.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0017.png index 112711199..fd2479b7b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0017.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0018.png index 63d6cca85..8e0281ed2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0018.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0019.png index 36f6e4d65..483b3036d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0019.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0020.png index 4ef227643..e5085bdba 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0020.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0021.png index 3fb31afdc..cef9c1354 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0021.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0022.png index 79fe62d02..672378eac 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0022.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0023.png index a3b1e4f6e..7aca2229a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0023.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0024.png index 995bd0b79..5b4a94851 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0024.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0001.png index 6c015a13f..b0fd67ccd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0001.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0002.png index 6c015a13f..b0fd67ccd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0002.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0003.png index 2684ceaad..dfb22a254 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0003.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0004.png index 71aafff24..26e45cb0b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0004.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0005.png index a73c2f7c7..4df528e5e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0005.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0006.png index 57bc51cc8..dbf0b8d89 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0006.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0007.png index 6fd0a821b..4fd2af759 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0007.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0008.png index 07d509d3f..0a8a85cd2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0008.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0009.png index 43c6c6054..ec4325210 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0009.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0010.png index f0e359804..79c800f36 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0010.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0011.png index 6480b5922..d8be60ec6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0011.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0012.png index 607d6ad08..30874db6a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0012.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0013.png index 18c720550..8645683d5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0013.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0014.png index 607d6ad08..30874db6a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0014.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0015.png index 20b16ced0..ee9787e97 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0015.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0016.png index 21fd456af..e36ebc46e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0016.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0017.png index bc7f2b711..7db8b0f99 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0017.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0018.png index 9af289f23..76e4be217 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0018.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0019.png index 7ebf72e0e..8d776a382 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0019.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0020.png index 80d361e0c..3b2f1d7f4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0020.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0021.png index dce325e68..3156a8e58 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0021.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0022.png index 46d6514b4..f65a9b9f9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0022.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0023.png index ded5d1fa9..6554688fc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0023.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0024.png index 6c015a13f..b0fd67ccd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0024.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0001.png index 4f21e029f..f06559b9d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0001.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0002.png index 38959c3e2..0131c1ffb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0002.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0003.png index c011059ed..b42068432 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0003.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0004.png index 3aa531f94..a0d795250 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0004.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0005.png index 6b5d74791..c2bbc4216 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0005.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0006.png index d5aff98cc..a5837a1ba 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0006.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0007.png index 94bd587fa..eb5c49577 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0007.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0008.png index 0af1342f4..112f593a2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0008.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0009.png index 7cda28487..26a108729 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0009.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0010.png index 1f987632f..086615b38 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0010.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0011.png index 31b0451a7..57dcb2b88 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0011.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0012.png index c58c11a9f..bac1ca7e1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0012.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0013.png index c2d445643..7a1d49a0d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0013.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0014.png index 392d3f55b..2f9da7ade 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0014.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0015.png index e37e17aa8..9861bc8bc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0015.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0016.png index 5f4340ba4..5d6b31d37 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0016.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0017.png index 91ccdb925..9674e671a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0017.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0018.png index 17eca8553..c7ae94d19 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0018.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0019.png index b5f0495e1..1ec399f0e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0019.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0020.png index c07361a4b..1a2d595b4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0020.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0021.png index 47f4c9cc0..b2becf4fe 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0021.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0022.png index 0764e73a2..4bc4a6ec5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0022.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0023.png index 225cf224e..588081709 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0023.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0024.png index 7dc00269d..6fcaaa144 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0024.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0001.png index 6c015a13f..b0fd67ccd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0001.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0002.png index 6853f69e0..8993eea29 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0002.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0003.png index 29602c492..29f0aae38 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0003.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0004.png index d8321aac6..45eb903d4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0004.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0005.png index 7160a4927..b369630db 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0005.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0006.png index 19af0c4f3..61a4152f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0006.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0007.png index e021c5ad4..64cb16ea1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0007.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0008.png index f5a46a69b..6f960429a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0008.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0009.png index 519e907ee..bc06f7e48 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0009.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0010.png index 39c1e787f..b34f08de5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0010.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0011.png index d7b2f9fae..a6a25e2ca 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0011.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0012.png index 1309106bd..ac576dd6e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0012.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0013.png index f212a3a97..0c449831f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0013.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0014.png index 2040054ba..0398ba227 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0014.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0015.png index 4f6c7d842..de32f8d06 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0015.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0016.png index 23f8f1959..7769a5323 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0016.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0017.png index 880f02f38..662943263 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0017.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0018.png index 4f103a178..e855e0cef 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0018.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0019.png index c8c2af3ae..f7b3a465b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0019.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0020.png index 26b52aec2..aa92d8935 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0020.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0021.png index fe2eb30a0..f56d1fe0a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0021.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0022.png index 36f31eee7..b8385e1ae 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0022.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0023.png index 0380fbe24..db4186a4f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0023.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0024.png index 6c015a13f..b0fd67ccd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0024.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0001.png index 6c015a13f..b0fd67ccd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0001.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0002.png index 1d57e3626..faa4acf3a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0002.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0003.png index 3cfd41a38..419187e05 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0003.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0004.png index 9f638e37a..f31a4fb78 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0004.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0005.png index e47e5c521..460cc03a4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0005.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0006.png index 695faa88a..5b0d6b602 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0006.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0007.png index c84b7557b..32ff349fb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0007.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0008.png index e1d6221d5..6e80367be 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0008.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0009.png index 7ccea8b23..5789a4428 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0009.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0010.png index e3ccda35d..fd280dcb4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0010.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0011.png index 5cc80843e..bc1af4aee 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0011.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0012.png index b19ba8400..e7e7a0ea9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0012.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0013.png index 634c8d7c0..ac6552846 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0013.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0014.png index ff68c2f24..f708e30ce 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0014.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0015.png index 05b59097f..64b4df555 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0015.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0016.png index d4cee897e..2fe52ed16 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0016.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0017.png index 4c0a70cc8..46cf70a1d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0017.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0018.png index 501a1067a..4129bd521 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0018.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0019.png index 826acff7a..e25c5cc55 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0019.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0020.png index b10414eba..e8278edba 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0020.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0021.png index c4361924c..566f24bb9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0021.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0022.png index 123161f94..4689b8d5e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0022.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0023.png index dddf711b0..9eb5ebd5f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0023.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0024.png index 6c015a13f..b0fd67ccd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0024.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0001.png index e0d068825..8a83611f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0001.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0002.png index 5dd751adc..2f692e781 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0002.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0003.png index b1d5d528a..854652627 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0003.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0004.png index fdf4a6389..c8ebdbf72 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0004.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0005.png index 65a5dc934..f8b92f62e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0005.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0006.png index 83a7a34f1..597b0ba81 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0006.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0007.png index a217e428e..fb70ff1b7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0007.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0008.png index 2a905d350..94f7f75f7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0008.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0009.png index 47e8e1827..2619feb4c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0009.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0010.png index 0d585b2b1..1bfc96a39 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0010.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0011.png index 38ad8e972..d7f31df4d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0011.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0012.png index 9d5efd509..4f1ee3bb0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0012.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0013.png index 42bfac5a8..0dc9c8ce5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0013.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0014.png index efe5bb92a..bc83db46d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0014.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0015.png index 19a995fdc..57859c090 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0015.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0016.png index e9e7bf8c8..dd254f35e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0016.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0017.png index b85340d40..333d82db7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0017.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0018.png index 648514c89..611f7dce0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0018.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0019.png index e0d068825..8a83611f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0019.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0020.png index e0d068825..8a83611f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0020.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0021.png index e0d068825..8a83611f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0021.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0022.png index e0d068825..8a83611f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0022.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0023.png index e0d068825..8a83611f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0023.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0024.png index e0d068825..8a83611f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0024.png and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer.png index 2c58a3006..6b48f637b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0001.png index 2cedb55dc..5d4cad829 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0001.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0002.png index 1149dbacb..3356fa97d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0002.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0003.png index b3d9869bb..480e878ff 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0003.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0004.png index 64e4a54fb..a78bd7c7a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0004.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0005.png index d824c90cd..5cb1cc55b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0005.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0006.png index 958a041e5..29ba172ab 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0006.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0007.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0007.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0008.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0008.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0009.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0009.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0010.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0010.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0011.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0011.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0012.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0012.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0013.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0013.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0014.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0014.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0015.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0015.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0016.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0016.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0017.png index 8dbcfb53b..90d5dbbe1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0017.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0018.png index e3c49f3f1..680647af0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0018.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0019.png index 52c3f3362..12bda1ca5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0019.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0020.png index b5adfacab..707b01f0a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0020.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0021.png index 43eac7e6d..8ff63c7c9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0021.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0022.png index 1bad9963c..596454dab 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0022.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0023.png index 4111d37c1..7d7513ac1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0023.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0024.png index 2cedb55dc..5d4cad829 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0024.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0001.png index 830e7ec19..784f02415 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0001.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0002.png index e46105e42..16197997d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0002.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0003.png index 4839b18dc..bbeefade8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0003.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0004.png index bf07ed93e..f3ace0568 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0004.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0005.png index 93a997407..abbb3fbbf 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0005.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0006.png index 7fc12dcd3..f7c3fdf27 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0006.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0007.png index 32cd889b8..6579580f9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0007.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0008.png index 1f90e40c2..c506d911b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0008.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0009.png index 833c55ba9..b28269911 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0009.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0010.png index 8f75a31ad..4ac6cee0f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0010.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0011.png index 9c52013d5..7a8bbbc40 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0011.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0012.png index 33f09b80d..6d3ddeac5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0012.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0013.png index 23f28d835..99befae30 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0013.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0014.png index d21b17eca..0ce8255a7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0014.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0015.png index 0efb5086c..a775650bb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0015.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0016.png index d6a3f4b50..bfa4e593b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0016.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0017.png index c1c32baaa..b06ac7382 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0017.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0018.png index f620c53a8..aad3b7772 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0018.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0019.png index 4a5d25b49..bdd811f42 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0019.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0020.png index 0e9742247..b352ee2a5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0020.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0021.png index 3d9af5468..b06df2506 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0021.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0022.png index 1dcbcc7b7..e6a580914 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0022.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0023.png index 0f188bf7f..74f9e1190 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0023.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0024.png index 2ef561eba..0a660cf58 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0024.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0001.png index 830e7ec19..784f02415 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0001.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0002.png index 4594b943e..8d64fabf6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0002.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0003.png index c83543cb6..e1e2008a1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0003.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0004.png index 814b93848..f1e46c6be 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0004.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0005.png index 2a715538e..1b25232a0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0005.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0006.png index a264994c8..8ed921916 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0006.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0007.png index 0429b1936..e8073fe28 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0007.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0008.png index 18a2a34cc..6401bcea2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0008.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0009.png index 88e2bfe36..a3f5d53b4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0009.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0010.png index efda24d8d..52f758fc1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0010.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0011.png index 5482728dc..605ddc173 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0011.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0012.png index 9cbb19786..f55daef1f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0012.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0013.png index 4bf71379e..94871905c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0013.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0014.png index ec16c4e17..8af4928fc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0014.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0015.png index 7b53fec0c..f359287ec 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0015.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0016.png index ccbfa9b96..ee2d73a63 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0016.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0017.png index cc6e34a0b..86993ba10 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0017.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0018.png index 0aafee8ee..e7948415c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0018.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0019.png index 9b07dd74a..14ca97314 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0019.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0020.png index 89103de3e..6aab48a1f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0020.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0021.png index 7b54ef65e..de5eee9c4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0021.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0022.png index 30031462f..b2275c982 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0022.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0023.png index 7567ca448..e46aa534c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0023.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0024.png index 84dab29eb..e62227ecb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0024.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0001.png index 7ee857bf1..99d732f1d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0001.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0002.png index 18f90ec03..c6b696d64 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0002.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0003.png index 87e47c927..b5eb97148 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0003.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0004.png index 6d224b4fc..f98d39c48 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0004.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0005.png index e97e9ecef..7f5b0083c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0005.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0006.png index e54f86e6a..ec8ffe517 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0006.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0007.png index 48e8322bb..2d12d9076 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0007.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0008.png index 34ae3f298..4ed596c40 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0008.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0009.png index e7e360688..c4d245b08 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0009.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0010.png index 88535ab0b..0fa8eadc8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0010.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0011.png index 8e255b902..cd816dcd7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0011.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0012.png index 54e841f0c..0c988d687 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0012.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0013.png index 65d2f1eef..d1c64f7dc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0013.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0014.png index 97d3f55ce..19ec638e5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0014.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0015.png index 8608a2ddd..88cf06a2f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0015.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0016.png index 5a7498679..6932f0706 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0016.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0017.png index 75c86b9c5..228111c04 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0017.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0018.png index 86b47538f..3a2d06b43 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0018.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0019.png index 04c722a93..b97f62c49 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0019.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0020.png index 45e3b6894..b0581c5dc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0020.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0021.png index ca44daada..2f6b5fef6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0021.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0022.png index 5c1dcb057..b2a681bc3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0022.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0023.png index 673a0bd61..60c6c96d6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0023.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0024.png index 7ee857bf1..99d732f1d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0024.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0001.png index 5ba59356c..43bbb47c0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0001.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0002.png index e2856daf1..46b3c813e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0002.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0003.png index 70cb533cc..cdcd4dc04 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0003.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0004.png index 49817f5ea..788e8db3c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0004.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0005.png index 9d19bda8d..efff0bf16 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0005.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0006.png index a06978f25..e31ecd9b8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0006.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0007.png index cd3d22836..2ecc6c4cf 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0007.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0008.png index 70f84a1f1..5e8650b6b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0008.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0009.png index edefd69a4..0c6da43c8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0009.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0010.png index 4afde9c36..1cfe26ba6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0010.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0011.png index 5587d4c3e..a0d58b1be 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0011.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0012.png index b14f1c889..1eca1ce52 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0012.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0013.png index c6551763f..483f487e5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0013.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0014.png index 5dec7ae46..70c6eb3e1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0014.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0015.png index 91e65169e..b0767ad75 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0015.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0016.png index 9f675e46f..5ca1d4ee1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0016.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0017.png index 7c2c129d0..76dcc8a23 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0017.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0018.png index 29dd9b771..54afb1fac 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0018.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0019.png index 339a577c0..6b698277f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0019.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0020.png index 42182f2ec..dc56dbb5f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0020.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0021.png index 8842f06a6..fbe5f1426 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0021.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0022.png index 5a7aa4b69..7b6d5683c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0022.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0023.png index 99264dfdd..0fce46f06 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0023.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0024.png index fe22f7718..e0116e686 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0024.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0001.png index 982154340..61f04a2aa 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0001.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0002.png index bc8068d5d..c93c5bb1a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0002.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0003.png index 549240003..bf052a21f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0003.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0004.png index a7ddb6ce9..e7365b7e3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0004.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0005.png index 46db354b1..5e038a0ac 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0005.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0006.png index f3bcda2f8..eb8b5f7f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0006.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0007.png index fce370011..666553e12 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0007.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0008.png index 574e0702d..50f3da53d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0008.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0009.png index 569c3815f..c70f1394a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0009.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0010.png index f276e09ba..0c20589ce 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0010.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0011.png index 146a1757a..acacc104d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0011.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0012.png index 52b0c4b9f..51a7ff712 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0012.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0013.png index 14ba9bfae..d70004240 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0013.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0014.png index 92d26654b..78f8ea98d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0014.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0015.png index edde12d31..8bad379ef 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0015.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0016.png index 27f08791d..c4f426bd6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0016.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0017.png index eaaf575b6..0dbbfcfc1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0017.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0018.png index 56429a9d1..4d327a806 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0018.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0019.png index c74ee5812..b0cac4496 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0019.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0020.png index 67e41e2d7..edb73c9bd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0020.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0021.png index c9aece9f2..036b1573e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0021.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0022.png index dc43e63c9..a724ae8af 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0022.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0023.png index 6963c23cc..669f86734 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0023.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0024.png index 1899123e2..1f10ab2b8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0024.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0001.png index d64816178..ff2acfb36 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0001.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0002.png index 57a84edbf..47fdf6615 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0002.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0003.png index f48d1fc48..3b1a6f029 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0003.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0004.png index 241d5a35a..410ba89d2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0004.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0005.png index 46f0ed0b7..44177d633 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0005.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0006.png index 98f952071..b360fab9c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0006.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0007.png index dc5600df5..e94d8d901 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0007.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0008.png index 42100e713..55727cd20 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0008.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0009.png index 492e60dfc..b53bebf97 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0009.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0010.png index 9bd1330d3..1c95ccadd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0010.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0011.png index 6e566c090..ac19b013e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0011.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0012.png index ade635c49..b380ac6f6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0012.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0013.png index e80f37ea7..5803b61a2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0013.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0014.png index 4a1c1afd7..3c32b7169 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0014.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0015.png index 3561ef789..aa5d5b283 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0015.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0016.png index eeaebdc47..274878412 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0016.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0017.png index c368484c3..c630a4a5a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0017.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0018.png index bb89d546e..dcbadb862 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0018.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0019.png index 0b389636f..2583ea212 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0019.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0020.png index 7de27dace..f9caf963a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0020.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0021.png index c236bb770..a541f2de8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0021.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0022.png index 9ea3b715b..8bc1a40d3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0022.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0023.png index af8da2178..3b6550aad 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0023.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0024.png index d64816178..ff2acfb36 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0024.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0001.png index 8ff93c534..60daa3838 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0001.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0002.png index 4d4a01f6b..2d58d9ae5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0002.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0003.png index dbe41b1fb..22a54a845 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0003.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0004.png index a95c86df7..9400ded12 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0004.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0005.png index 7abea52b2..f86447ecb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0005.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0006.png index ec5840be0..c56f60f92 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0006.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0007.png index 374c9b36b..bdac81883 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0007.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0008.png index d82439ca0..dd5f57904 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0008.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0009.png index b3e6b2863..b6c18af33 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0009.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0010.png index 879518dcf..ffbc11112 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0010.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0011.png index 879518dcf..ffbc11112 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0011.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0012.png index 879518dcf..ffbc11112 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0012.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0013.png index 879518dcf..ffbc11112 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0013.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0014.png index 879518dcf..ffbc11112 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0014.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0015.png index 879518dcf..ffbc11112 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0015.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0016.png index 879518dcf..ffbc11112 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0016.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0017.png index 879518dcf..ffbc11112 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0017.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0018.png index 879518dcf..ffbc11112 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0018.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0019.png index 33de42a1c..80cd8e223 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0019.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0020.png index 66115d214..8a255ee1f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0020.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0021.png index 960e98481..25eb24120 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0021.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0022.png index 73b97d383..b488259f6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0022.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0023.png index 7abea52b2..f86447ecb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0023.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0024.png index 7abea52b2..f86447ecb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0024.png and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa.png b/dasherdancer/src/main/res/drawable-nodpi/santa.png index 3a841f400..b05646944 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa.png and b/dasherdancer/src/main/res/drawable-nodpi/santa.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0001.png index 102722b18..bfb074b0f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0001.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0002.png index 9f9fc55ed..8b5aa8235 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0002.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0003.png index 82a4c5c9e..fe8ac4f4d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0003.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0004.png index 1f4a08467..3edbc97c5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0004.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0005.png index c5e523443..6abb852e6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0005.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0006.png index 85c89a641..3bf6d5270 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0006.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0007.png index 4d798347e..1dbf8f30b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0007.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0008.png index 3fd4d9606..da5abeacc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0008.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0009.png index 3572acaf8..41c68436c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0009.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0010.png index af84d9629..44bae0589 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0010.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0011.png index e39def95e..d4560d0ea 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0011.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0012.png index 013f016ef..c2f874e7b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0012.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0013.png index 06ed3ac9e..aea9c39ae 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0013.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0014.png index 3fd4d9606..da5abeacc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0014.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0015.png index ceee35f70..7d43baa1f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0015.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0016.png index b4042be37..1bd2b3aac 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0016.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0017.png index 1adf5a89b..878c787e4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0017.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0018.png index 989f81194..11a274d56 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0018.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0019.png index e85baea3b..2d073197a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0019.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0020.png index 34a58af74..cfad5b9aa 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0020.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0021.png index 4d3dc9274..5bf934280 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0021.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0022.png index ea1447017..b5cdbb670 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0022.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0023.png index 102722b18..bfb074b0f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0023.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0024.png index 102722b18..bfb074b0f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0024.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0025.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0025.png index 9f9fc55ed..8b5aa8235 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0025.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0025.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0026.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0026.png index 82a4c5c9e..fe8ac4f4d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0026.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0026.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0027.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0027.png index 9b18d9452..7e97cfd20 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0027.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0027.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0028.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0028.png index 01c33d262..22eceaf88 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0028.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0028.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0029.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0029.png index 2e78fadae..882b1f0f3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0029.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0029.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0030.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0030.png index 10472432f..11073c725 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0030.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0030.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0031.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0031.png index 533cf7729..1ba1d987b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0031.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0031.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0032.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0032.png index 3fab52715..87e79d70f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0032.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0032.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0033.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0033.png index b89ea34d9..924fec05a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0033.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0033.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0034.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0034.png index e39def95e..d4560d0ea 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0034.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0034.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0035.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0035.png index 013f016ef..c2f874e7b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0035.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0035.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0036.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0036.png index 2e43de83b..b18cdac62 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0036.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0036.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0037.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0037.png index 2197b3bab..a1bddba42 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0037.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0037.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0038.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0038.png index cde8afd61..9840eec9f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0038.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0038.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0039.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0039.png index 06b86d4fd..57531a97c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0039.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0039.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0040.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0040.png index b9af1764b..a8f0eb9cc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0040.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0040.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0041.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0041.png index 679f6b5c2..9fa4616b0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0041.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0041.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0042.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0042.png index 700492ad3..a9d4d3cc1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0042.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0042.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0043.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0043.png index 86115612c..44213ee01 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0043.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0043.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0044.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0044.png index 02987dc27..a09c00118 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0044.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0044.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0045.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0045.png index b89ec1801..fb7b432d3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0045.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0045.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0046.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0046.png index 2727003ce..75bac3198 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0046.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0046.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0047.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0047.png index 82d3a741a..3afcd7d11 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0047.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0047.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0048.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0048.png index 102722b18..bfb074b0f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0048.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0048.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0001.png index 08c890615..27eb6a522 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0001.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0002.png index 21bca6749..f58b525a3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0002.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0003.png index a54326bd7..2df8a66fb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0003.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0004.png index fddb8394a..65d9796a0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0004.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0005.png index f12f2a404..f2c3fe53e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0005.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0006.png index daef24b46..7abe331ba 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0006.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0007.png index 17fdee8fe..59f4dede0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0007.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0008.png index 7a1fc1629..975f28065 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0008.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0009.png index a7d6ef94e..e41791b09 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0009.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0010.png index 3fca71da3..37287cea7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0010.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0011.png index a7d6ef94e..e41791b09 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0011.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0012.png index 7a1fc1629..975f28065 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0012.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0013.png index dbe2a5aa1..311199f31 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0013.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0014.png index 479e0172c..356014435 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0014.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0015.png index f12f2a404..f2c3fe53e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0015.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0016.png index fddb8394a..65d9796a0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0016.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0017.png index 2f8b96e1c..7824e3452 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0017.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0018.png index 208be4a9a..0c437f9a0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0018.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0019.png index 875c78baa..752a60e5f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0019.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0020.png index 1145d6584..cbd64c18d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0020.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0021.png index 2f8b96e1c..7824e3452 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0021.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0022.png index ee3e61751..ad8c620cf 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0022.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0023.png index 21bca6749..f58b525a3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0023.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0024.png index 08c890615..27eb6a522 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0024.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20001.png index c9aae9f64..a55be8392 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20001.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20002.png index 56d246020..7dcd141e8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20002.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20003.png index 174b81809..dc8a7b794 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20003.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20004.png index d0099e780..7525f124a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20004.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20005.png index 14cc6880c..61d56da13 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20005.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20006.png index 54e897363..1909dcbe5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20006.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20007.png index 4a3840dcc..aee9edf69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20007.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20008.png index 4a3840dcc..aee9edf69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20008.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20009.png index 4a3840dcc..aee9edf69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20009.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20010.png index 4a3840dcc..aee9edf69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20010.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20011.png index 4a3840dcc..aee9edf69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20011.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20012.png index 4a3840dcc..aee9edf69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20012.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20013.png index 4a3840dcc..aee9edf69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20013.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20014.png index 4a3840dcc..aee9edf69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20014.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20015.png index 4a3840dcc..aee9edf69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20015.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20016.png index 4a3840dcc..aee9edf69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20016.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20017.png index aa712e8f1..a1a947ab5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20017.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20018.png index 88d88d15c..458c8b824 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20018.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20019.png index eb122aea6..da82308b7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20019.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20020.png index ea436c4d9..0fda3dad3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20020.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20021.png index 03e41b506..0c5e64e11 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20021.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20022.png index c9aae9f64..a55be8392 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20022.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20023.png index 60e96c96d..9161eabb9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20023.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20024.png index 60e96c96d..9161eabb9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20024.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0001.png index 778276d99..50f9af05f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0001.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0002.png index af3b404c4..98b0d43f5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0002.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0003.png index 5b5098769..9cf08c45e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0003.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0004.png index 106621aed..c1d040a69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0004.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0005.png index 7623f11b7..b722b86e9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0005.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0006.png index d5dedecb1..649e153b7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0006.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0007.png index 54e805a37..1b0749bc3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0007.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0008.png index be5e55303..40830e5fe 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0008.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0009.png index db142d92c..cacb48dff 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0009.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0010.png index e05e09b1d..12b0f569d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0010.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0011.png index ae9893a13..83cc89f8c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0011.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0012.png index def5a9fcd..72c637ee5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0012.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0013.png index 3fb9bdfa5..36660d947 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0013.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0014.png index 4910d2156..05daf15db 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0014.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0015.png index 9557cc69e..fdfe39e1b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0015.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0016.png index 570bdeb52..73501c350 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0016.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0017.png index d93d78a05..78488e76e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0017.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0018.png index a982fefa3..8be870e9b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0018.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0019.png index 821e2ab95..5f8d9e4b5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0019.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0020.png index 4547b1ee3..ccb49b095 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0020.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0021.png index 473a6e941..46ef5d376 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0021.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0022.png index 4521a781c..2da4e5d89 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0022.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0023.png index 0abe1e5c4..6ad211a65 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0023.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0024.png index fe6814992..c7392e893 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0024.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20001.png index 97b489b38..9fcbb5f4d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20001.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20002.png index b22a952a5..5b73ced1c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20002.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20003.png index 4addeffaa..b5e539dac 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20003.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20004.png index 28b1e6306..d1a1ac1fb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20004.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20005.png index d8d638a42..4d6ae75e3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20005.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20006.png index 2039bae01..0f6480570 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20006.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20007.png index a6838a7ed..10e1b643b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20007.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20008.png index 6e98cf2c5..b8cf633b2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20008.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20009.png index 934941169..03c112002 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20009.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20010.png index 90ff48772..8631ebb24 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20010.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20011.png index 8dcaa68f4..1c48bbd0f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20011.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20012.png index 35bf196c7..a44bb40e8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20012.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20013.png index 3aeeef3d5..e6d0e0039 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20013.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20014.png index 7948cc674..50a3af0e1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20014.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20015.png index 23200c132..f51eb8d81 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20015.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20016.png index e8b87690b..0c8072a06 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20016.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20017.png index 30435cdbc..c9541257c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20017.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20018.png index 0ba926107..61e2b88ce 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20018.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20019.png index 4c73f421f..2b1dd6af0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20019.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20020.png index 7680c785a..fdfa6fdeb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20020.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20021.png index 131b6515b..8b203339e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20021.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20022.png index 15eb5fa1b..fc2bcc581 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20022.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20023.png index 07dd2edc0..b9d0b0616 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20023.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20024.png index 2ee120091..997b8bf03 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20024.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0001.png index 4be7d4ebf..06ec147d2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0001.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0002.png index 76596cc99..7ea2044cd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0002.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0003.png index 2ad329636..c9ed9b8e6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0003.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0004.png index 1b6c5d225..be955a4af 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0004.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0005.png index e11a8aa87..8c8d03ea3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0005.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0006.png index 88e4bc07a..844c65eb5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0006.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0007.png index f75588a2a..f14901245 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0007.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0008.png index 34186f016..0bcd253c4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0008.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0009.png index fb4ea9246..d093c3fcf 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0009.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0010.png index e90d5263e..19d3fbe19 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0010.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0011.png index 58cb7e3a4..44a6d85b6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0011.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0012.png index 0e3f870fe..bb3a5c3db 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0012.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0013.png index 26b0c828f..c77a42607 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0013.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0014.png index 1a0a66110..572df483c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0014.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0015.png index 0406d0382..38531fe7e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0015.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0016.png index d0ea832e6..6d47e6920 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0016.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0017.png index e1fc5d1a6..a385f2dea 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0017.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0018.png index 2db882164..282938ab4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0018.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0019.png index da73020e5..c717e1b20 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0019.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0020.png index bc46e5851..92099b2aa 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0020.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0021.png index 25f515b8a..9ba924804 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0021.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0022.png index 4162d244e..a1ccb0fab 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0022.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0023.png index 25c367638..63cb7f4cf 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0023.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0024.png index e7d1c2be2..89c6dfd20 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0024.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0001.png index 08c890615..27eb6a522 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0001.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0002.png index 7f2903769..973100411 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0002.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0003.png index 6a8cc022d..814a1bf95 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0003.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0004.png index e0acb9987..e36555876 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0004.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0005.png index 057582c05..f1fa32652 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0005.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0006.png index 9d21e1197..62ec78241 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0006.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0007.png index 0fdcd05fc..a8e0bbc70 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0007.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0008.png index c790ac482..104f38353 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0008.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0009.png index adf586712..5cc955aef 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0009.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0010.png index 0fdcd05fc..a8e0bbc70 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0010.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0011.png index 08c890615..27eb6a522 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0011.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0012.png index 21419e3be..7c9007abb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0012.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0013.png index 62604f651..1f8118e4f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0013.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0014.png index bae14b90f..578ab964a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0014.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0015.png index 6aa78c735..334627e2e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0015.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0016.png index c7c273884..1e911c305 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0016.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0017.png index 8d36347fc..a19228138 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0017.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0018.png index 6210d55fd..aad9e90fa 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0018.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0019.png index c16779688..7e90eb31f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0019.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0020.png index 73a0c7874..34fddd029 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0020.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0021.png index be4ef2f80..3ecb2c48a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0021.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0022.png index 281655078..fe0113704 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0022.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0023.png index 39803863c..e452c22a0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0023.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0024.png index eaa2eca85..2d1cd260c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0024.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0001.png index 954d87a71..bb358b4dd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0001.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0002.png index 0143c40dc..23f6ad695 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0002.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0003.png index 47a84854a..9a01b59a4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0003.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0004.png index c2053aa22..3085dee90 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0004.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0005.png index a248bb4a5..e31cad11c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0005.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0006.png index 8029858b0..14c01a807 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0006.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0007.png index 3c9d01ce9..d89c3d81b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0007.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0008.png index 2988b8280..7730f513c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0008.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0009.png index 6389aab82..978847c8a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0009.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0010.png index cbd109b3a..158087844 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0010.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0011.png index c6b18bbcc..d8d8fa060 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0011.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0012.png index c7509ad6b..5be51fd8c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0012.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0013.png index 657d880b3..6c1857302 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0013.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0014.png index 0b57a0fe1..06320ee0d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0014.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0015.png index 3d2a65b56..a45f5da0c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0015.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0016.png index fb04b6f00..56c5f9e2f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0016.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0017.png index 5ab839edb..df42bbf58 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0017.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0018.png index 644b2cbd4..b5326579e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0018.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0019.png index b51d9b301..b80ebf2a0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0019.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0020.png index 002d8d30e..1fc24e789 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0020.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0021.png index 932faeb6a..a51d37b8a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0021.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0022.png index 0195e1cc0..c5dc64adf 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0022.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0023.png index 3709e5469..87fb96a74 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0023.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0024.png index 954d87a71..bb358b4dd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0024.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0001.png index 08c890615..27eb6a522 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0001.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0002.png index 21bca6749..f58b525a3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0002.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0003.png index 43be5fded..6b7f489ee 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0003.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0004.png index b1692428f..38a74f9d1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0004.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0005.png index 4c4cc8fef..e63149f85 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0005.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0006.png index d625e6cf3..57c2ae73c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0006.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0007.png index c63398e50..20404e3e4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0007.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0008.png index b2db5f1f5..84ba5c006 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0008.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0009.png index ab0601585..ce3a71b88 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0009.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0010.png index 0149442c7..31b462a1e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0010.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0011.png index 4750b3fc9..b3eedb129 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0011.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0012.png index 6cde27909..5a955c0b4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0012.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0013.png index ba4e67ff4..cd55a3aa6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0013.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0014.png index 0e63da339..0a6ecc665 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0014.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0015.png index d2da3f83e..f0d6c085f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0015.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0016.png index cd63c16ca..5d305e645 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0016.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0017.png index 51d062151..a53674d13 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0017.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0018.png index c24efb737..5bf27686c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0018.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0019.png index af54faebd..26ff714ff 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0019.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0020.png index cd63c16ca..5d305e645 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0020.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0021.png index 43be5fded..6b7f489ee 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0021.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0022.png index 63c685b7c..f7982abbb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0022.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0023.png index 08c890615..27eb6a522 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0023.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0024.png index 08c890615..27eb6a522 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0024.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_down01.png b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_down01.png index b0c2be127..a79f7db96 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_down01.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_down01.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_left01.png b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_left01.png index cf8f2db40..0c04c3288 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_left01.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_left01.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_shake01.png b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_shake01.png index 3d38f6815..6189272de 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_shake01.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_shake01.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_tap01.png b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_tap01.png index ea45198e3..273b5e60e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_tap01.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_tap01.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_zoom_in01.png b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_zoom_in01.png index c5507106c..ed3754214 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_zoom_in01.png and b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_zoom_in01.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0001.png index 8fc8923c0..1d3987069 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0001.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0002.png index 0c3e6960e..5e0c7236d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0002.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0003.png index 83355be7d..5fd6911b7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0003.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0004.png index 49d294c2c..7f082922e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0004.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0005.png index 12e3cbb3c..22d8cb860 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0005.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0006.png index f2abd8477..12b31aced 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0006.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0007.png index a0d27e5d6..6ac94e979 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0007.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0008.png index 12de9ed3a..474601a54 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0008.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0009.png index f146291c7..c6dabc4a5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0009.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0010.png index 300046251..98de221f9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0010.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0011.png index 89ef95ef1..3289ce734 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0011.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0012.png index 89ef95ef1..3289ce734 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0012.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0013.png index 89ef95ef1..3289ce734 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0013.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0014.png index 300046251..98de221f9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0014.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0015.png index f146291c7..c6dabc4a5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0015.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0016.png index 7689f8897..eed113255 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0016.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0017.png index 95090dfcf..23b9790a2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0017.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0018.png index a956d7d56..6947ec9db 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0018.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0019.png index ae39cc69b..229bee2de 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0019.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0020.png index 6b5afa8f8..7c4569266 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0020.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0021.png index bc0534aa4..f0d01873a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0021.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0022.png index 4fba28a45..486eb938e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0022.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0023.png index d19d70747..608282335 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0023.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0024.png index 8fc8923c0..1d3987069 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0024.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0001.png index 486ae2471..b65d4f57b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0001.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0002.png index d20f97f72..58b1f84c7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0002.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0003.png index 7e592d3fc..1d3183774 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0003.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0004.png index ec2562363..f2b4fe1cf 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0004.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0005.png index af168962e..4bd7a161b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0005.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0006.png index 7a51a79a9..2699c0c6a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0006.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0007.png index 6a940b77e..c13e7f25a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0007.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0008.png index 0cddbb24d..20d504d55 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0008.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0009.png index 1a5811a17..4cfea1faf 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0009.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0010.png index ab9fa2211..1239f44aa 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0010.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0011.png index 472d011f4..85232cd73 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0011.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0012.png index 0ba683011..1d391970e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0012.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0013.png index 777eaab2b..2f748fcd7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0013.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0014.png index 7f584c1d2..048d04204 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0014.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0015.png index 1309106bd..ac576dd6e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0015.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0016.png index 54708811d..584777ae8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0016.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0017.png index 7badec902..8d7b11eda 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0017.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0018.png index 169e0c27f..b63ca2bd3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0018.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0019.png index 5d52f872c..5ae211e94 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0019.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0020.png index 0e1a30913..ad97fe43f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0020.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0021.png index ae37dfb06..dc8ccaf66 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0021.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0022.png index 14b5ab0fc..c8de7729c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0022.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0023.png index 381854784..8ef10cdf6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0023.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0024.png index 1ab37b1c9..09f6aa1b2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0024.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0001.png index ea1fc3986..2e00c5bd2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0001.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0002.png index 2dde60adb..96881ef08 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0002.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0003.png index 021d7ba06..52010c4d9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0003.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0004.png index 138580b99..1e0f9f859 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0004.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0005.png index d530ce175..2bdf8e8df 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0005.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0006.png index 8b2e78482..7cf21d804 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0006.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0007.png index 896c630e1..0b446ac4b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0007.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0008.png index e6f8d21a3..d1d481899 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0008.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0009.png index ec94972ea..14c582643 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0009.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0010.png index e3debca3b..43fd8ed8d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0010.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0011.png index 150d0c2c2..0b7adde5a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0011.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0012.png index 63bc2af3e..de5da306d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0012.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0013.png index d0ee2d37f..5d8106dbc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0013.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0014.png index d0ee2d37f..5d8106dbc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0014.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0015.png index d0ee2d37f..5d8106dbc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0015.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0016.png index d0ee2d37f..5d8106dbc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0016.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0017.png index d0ee2d37f..5d8106dbc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0017.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0018.png index d0ee2d37f..5d8106dbc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0018.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0019.png index d0ee2d37f..5d8106dbc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0019.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0020.png index 01d5bfcb2..7cd9f68f2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0020.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0021.png index 336ac57c3..435a512b9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0021.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0022.png index 72eb25f69..6bdaa33de 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0022.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0023.png index 6fa2cb0af..74f0822d4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0023.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0024.png index 8b0f03bf4..c9b2c0b69 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0024.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0001.png index fdeeb1fa3..c4154de4c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0001.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0002.png index 3b11a200e..7256dfa8d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0002.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0003.png index dd6e1eadb..350a889dd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0003.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0004.png index 6e3d0fa26..a35704b17 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0004.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0005.png index 23b651dd3..62b6e1214 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0005.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0006.png index ec0e6f3c7..c7e7688d5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0006.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0007.png index 4964b5cc7..85afa2e0a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0007.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0008.png index 6cd93a245..a7c6eca9f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0008.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0009.png index 3bb106cf4..595ec03b8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0009.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0010.png index 319b9b188..856d815b4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0010.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0011.png index 330533867..bf04496fd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0011.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0012.png index 88ce3c018..29b2d9ee1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0012.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0013.png index cd267adaa..afcd11258 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0013.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0014.png index 519af9c1b..badd9c1c0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0014.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0015.png index 83fc3423e..cedcf4de0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0015.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0016.png index 30e8b240b..effdf9f1f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0016.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0017.png index 739827087..4800cd38a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0017.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0018.png index d98c2fb5b..104b1e0ff 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0018.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0019.png index 047e5bebd..3bfd9130f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0019.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0020.png index 8f26a95e2..6edc315a0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0020.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0021.png index 19efdb4ac..63c93f3eb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0021.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0022.png index 16466a4e1..bdbb386d6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0022.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0023.png index 90a674f13..b7434a433 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0023.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0024.png index 1601b4338..49a10aab1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0024.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0001.png index 8fc8923c0..1d3987069 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0001.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0002.png index 196f67494..cd37eec21 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0002.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0003.png index 763eaafec..5743045cb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0003.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0004.png index 19b798a46..e5e1095dc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0004.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0005.png index 85b444cfa..0f6784358 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0005.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0006.png index 832414b89..7cbca825e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0006.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0007.png index a3f9dd6dd..bd84dfb8b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0007.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0008.png index 5eb7ed211..e427d5e88 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0008.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0009.png index c870a5fad..e8710ab06 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0009.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0010.png index a750a0230..964cd6ce4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0010.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0011.png index acfa3c121..8a24ef392 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0011.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0012.png index f13b9fe1d..4adfda3fd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0012.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0013.png index 7a9466346..9e7348ad4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0013.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0014.png index c1ee27c20..21b98c8cc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0014.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0015.png index 450888074..394e0d7cd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0015.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0016.png index 1023c800d..f7952ffc0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0016.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0017.png index be2652f9a..9d08a8255 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0017.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0018.png index fc130a338..08f7b7899 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0018.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0019.png index db29ef2cc..eac4e4040 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0019.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0020.png index 8bd2714df..0aeaf72bc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0020.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0021.png index 8d4cab9c4..b14b4511a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0021.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0022.png index 8fc8923c0..1d3987069 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0022.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0023.png index 8fc8923c0..1d3987069 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0023.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0024.png index 196f67494..cd37eec21 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0024.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0001.png index 30b13f2c2..9b7f85894 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0001.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0002.png index c5c86a2d1..dbc337fe5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0002.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0003.png index 4f7ea58e0..e657d2903 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0003.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0004.png index 4ca59c42a..b15914714 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0004.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0005.png index df727f66c..1e3bedd52 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0005.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0006.png index 9d068cdba..7b8aabda2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0006.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0007.png index 183d27482..0dbec439e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0007.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0008.png index bd21dfcd0..e7b90c2ef 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0008.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0009.png index 5ec92c718..7d25f1bb5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0009.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0010.png index 5cb194613..18f6c7536 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0010.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0011.png index 957bed986..0b81dbc67 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0011.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0012.png index aefd11f88..907979322 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0012.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0013.png index 789d831c2..763274575 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0013.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0014.png index 1733eba70..728dbb141 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0014.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0015.png index 0f84c9121..f43273163 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0015.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0016.png index 0073e2e01..89f3c4db5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0016.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0017.png index 34483780f..1b9f41a56 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0017.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0018.png index b93793aea..1dd8b48f5 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0018.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0019.png index 641995e82..aa8a9a3a1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0019.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0020.png index 7cd3c91ad..26622996e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0020.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0021.png index cc6fcd582..39ad103da 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0021.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0022.png index 0537efbea..7abd36583 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0022.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0023.png index ec69020ce..eddb0ee8c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0023.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0024.png index 6129865ec..84292efb3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0024.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0001.png index 8f757df57..4db4543cd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0001.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0002.png index 343185af8..c2e29ee6c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0002.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0003.png index 255ef6cf5..cbfd2e48d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0003.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0004.png index 747cf600e..18295dde2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0004.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0005.png index 34d505aff..8f4478a73 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0005.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0006.png index 9ab1f3e6b..2cd023026 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0006.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0007.png index d97424f94..6615863d1 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0007.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0008.png index f62558e0a..66108e150 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0008.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0009.png index 5217e1a29..a760331e9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0009.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0010.png index e717eedd4..2b3019fdf 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0010.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0011.png index d8cccb176..c90844ca6 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0011.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0012.png index b5866a4fb..3b71d5f24 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0012.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0013.png index 5777d5e01..ab404dde9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0013.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0014.png index 67311b0b5..4f53fba79 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0014.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0015.png index b1a4dfa8e..d1faa4584 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0015.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0016.png index 9435c6933..97a1b7e64 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0016.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0017.png index 6653ada95..941d943a8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0017.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0018.png index e2e5ad263..d6494b982 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0018.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0019.png index 361cbeec0..ec24cfa51 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0019.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0020.png index 25d5ed75d..1bdae5156 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0020.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0021.png index 34445ac58..6d8a347bb 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0021.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0022.png index 4887e5c19..742c0102e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0022.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0023.png index 22839c67d..8c1be9b75 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0023.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0024.png index 8f757df57..4db4543cd 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0024.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0001.png index 8fc8923c0..1d3987069 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0001.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0002.png index 15eb8101a..8f63bdca0 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0002.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0003.png index 5e914e985..94214d660 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0003.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0004.png index 067606d99..0e081017c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0004.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0005.png index 9f30e72f5..f86cd0844 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0005.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0006.png index c53e80c10..3d5dd5fe8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0006.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0007.png index ee58e233c..a684bcf2e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0007.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0008.png index 964a01a45..6addfe0a3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0008.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0009.png index 964a01a45..6addfe0a3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0009.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0010.png index 964a01a45..6addfe0a3 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0010.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0011.png index cff9ac554..bde75b83d 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0011.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0012.png index 0ff5a2e36..4a1906f40 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0012.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0013.png index d732c80d1..77843d46b 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0013.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0014.png index 43a5b8e47..3efa8149a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0014.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0015.png index 784c26be1..9d31686fc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0015.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0016.png index 381b5cef1..2baea85d9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0016.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0017.png index afa69e037..2d55dbc9e 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0017.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0018.png index 86cd903ae..c10291f25 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0018.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0019.png index 66666c734..0f5c2544f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0019.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0020.png index 103f9947a..4f5d51f6f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0020.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0021.png index 7982f4d8b..fcde4be21 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0021.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0022.png index 2506c82cb..f81981d18 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0022.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0023.png index 66420e2c3..99272ee12 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0023.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0024.png index 8fc8923c0..1d3987069 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0024.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0024.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0001.png index f0a1cd493..80b4b82ce 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0001.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0001.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0002.png index 65d655508..446465d79 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0002.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0002.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0003.png index 96afe1a96..c39466ba8 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0003.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0003.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0004.png index fc78fd9f8..f07d134fe 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0004.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0004.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0005.png index 09ed3a3f8..62d506096 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0005.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0005.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0006.png index 336d46103..0b399f173 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0006.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0006.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0007.png index 5d657d0cb..ce61d84ae 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0007.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0007.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0008.png index 20ee98019..a2bde4207 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0008.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0008.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0009.png index 5e5a464ff..166b7d69f 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0009.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0009.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0010.png index 8819f4721..dbe56831c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0010.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0010.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0011.png index ca37f4781..478aa5e08 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0011.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0011.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0012.png index 5a944a695..7e9a46bba 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0012.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0012.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0013.png index 87bd76a32..8f0688617 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0013.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0013.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0014.png index 00c7f17bc..610068a5a 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0014.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0014.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0015.png index 08d8602c0..7b08196fc 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0015.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0015.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0016.png index 1eb8ba8b4..2fbe13019 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0016.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0016.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0017.png index 6124f6dd6..03760142c 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0017.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0017.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0018.png index 5edebf86f..31737cea2 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0018.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0018.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0019.png index bd6f40734..eef6f3ed7 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0019.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0019.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0020.png index d9af99f8f..8723e1522 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0020.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0020.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0021.png index 8b9f2fb45..a1275eea9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0021.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0021.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0022.png index 2fa345787..f8358d217 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0022.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0022.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0023.png index b0a7aba3a..4ac803fb4 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0023.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0023.png differ diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0024.png index 58301c7e0..3b88a60b9 100644 Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0024.png and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0024.png differ diff --git a/dasherdancer/src/main/res/drawable-v21/dasher_ripple.xml b/dasherdancer/src/main/res/drawable-v21/dasher_ripple.xml index 67e022209..2fa9183a8 100644 --- a/dasherdancer/src/main/res/drawable-v21/dasher_ripple.xml +++ b/dasherdancer/src/main/res/drawable-v21/dasher_ripple.xml @@ -1,3 +1,19 @@ + + diff --git a/dasherdancer/src/main/res/drawable-v21/dasher_ripple_small.xml b/dasherdancer/src/main/res/drawable-v21/dasher_ripple_small.xml index 50ab5debd..976e06c22 100644 --- a/dasherdancer/src/main/res/drawable-v21/dasher_ripple_small.xml +++ b/dasherdancer/src/main/res/drawable-v21/dasher_ripple_small.xml @@ -1,3 +1,19 @@ + + diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer.png b/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer.png index 2050120fa..f933ab119 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer.png and b/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer.png differ diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer_p.png b/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer_p.png index cae06c682..fe1398816 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer_p.png and b/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer_p.png differ diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character.png b/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character.png index c02828653..ccf41abd6 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character.png and b/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character.png differ diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character_pressed.png b/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character_pressed.png index 794c3cb5f..4efc909ca 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character_pressed.png and b/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character_pressed.png differ diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out.png b/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out.png index bc5da3542..26668139a 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out.png and b/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out.png differ diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out_pressed.png b/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out_pressed.png index 598b9d0c8..d667af4e7 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out_pressed.png and b/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out_pressed.png differ diff --git a/dasherdancer/src/main/res/drawable-xhdpi/elf.png b/dasherdancer/src/main/res/drawable-xhdpi/elf.png index bfdff002b..ec7528836 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/elf.png and b/dasherdancer/src/main/res/drawable-xhdpi/elf.png differ diff --git a/dasherdancer/src/main/res/drawable-xhdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-xhdpi/ic_launcher.png index df82a166d..07c6e0aec 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/ic_launcher.png and b/dasherdancer/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_left.png b/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_left.png index 0724f6e65..b5be517e4 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_left.png and b/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_left.png differ diff --git a/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_right.png b/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_right.png index e151aa236..13603a4e4 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_right.png and b/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_right.png differ diff --git a/dasherdancer/src/main/res/drawable-xhdpi/img_mint_loading_spinner.png b/dasherdancer/src/main/res/drawable-xhdpi/img_mint_loading_spinner.png index 96911bff7..187443948 100644 Binary files a/dasherdancer/src/main/res/drawable-xhdpi/img_mint_loading_spinner.png and b/dasherdancer/src/main/res/drawable-xhdpi/img_mint_loading_spinner.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer.png index 28738e251..a2eeaaf54 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer_p.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer_p.png index b810e7035..d06ebcc25 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer_p.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer_p.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character.png index fce126edf..56643e626 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character_pressed.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character_pressed.png index cc6568d2f..20e7ab8cf 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character_pressed.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character_pressed.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out.png index e3af85425..f4a29369f 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out_pressed.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out_pressed.png index d61aa5601..60e7acd18 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out_pressed.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out_pressed.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/ic_launcher.png index 91475edc4..149bdd41d 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/ic_launcher.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/ic_launcher.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/img_mint_loading_spinner.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/img_mint_loading_spinner.png index 8b1a16985..9f929fd25 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/img_mint_loading_spinner.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/img_mint_loading_spinner.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/reindeer.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/reindeer.png index 2c58a3006..177c658b2 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/reindeer.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/reindeer.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/santa.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/santa.png index 3a841f400..e2d4fe35b 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/santa.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/santa.png differ diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/snowman.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/snowman.png index c8b6e4d73..6753a837d 100644 Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/snowman.png and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/snowman.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer.png b/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer.png index ec65de817..3df1c3698 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer.png and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer_p.png b/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer_p.png index 94c36a676..249d8db38 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer_p.png and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer_p.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character.png b/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character.png index 5bc4bf761..a7045f5fa 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character.png and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character_pressed.png b/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character_pressed.png index 2a1e05a4c..07b87339b 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character_pressed.png and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character_pressed.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out.png b/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out.png index c0a791bf7..8e0db4418 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out.png and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out_pressed.png b/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out_pressed.png index 209349e0f..b05fa8510 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out_pressed.png and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out_pressed.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-xxhdpi/ic_launcher.png index 91475edc4..149bdd41d 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/ic_launcher.png and b/dasherdancer/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/img_mint_loading_spinner.png b/dasherdancer/src/main/res/drawable-xxhdpi/img_mint_loading_spinner.png index 5970d6b81..8d722578d 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/img_mint_loading_spinner.png and b/dasherdancer/src/main/res/drawable-xxhdpi/img_mint_loading_spinner.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/reindeer.png b/dasherdancer/src/main/res/drawable-xxhdpi/reindeer.png index 2c58a3006..177c658b2 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/reindeer.png and b/dasherdancer/src/main/res/drawable-xxhdpi/reindeer.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/santa.png b/dasherdancer/src/main/res/drawable-xxhdpi/santa.png index 3a841f400..e2d4fe35b 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/santa.png and b/dasherdancer/src/main/res/drawable-xxhdpi/santa.png differ diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/snowman.png b/dasherdancer/src/main/res/drawable-xxhdpi/snowman.png index c8b6e4d73..6753a837d 100644 Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/snowman.png and b/dasherdancer/src/main/res/drawable-xxhdpi/snowman.png differ diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer.png b/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer.png index ec65de817..3df1c3698 100644 Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer.png and b/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer.png differ diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer_p.png b/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer_p.png index 94c36a676..249d8db38 100644 Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer_p.png and b/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer_p.png differ diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-xxxhdpi/ic_launcher.png index 91475edc4..149bdd41d 100644 Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/ic_launcher.png and b/dasherdancer/src/main/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/reindeer.png b/dasherdancer/src/main/res/drawable-xxxhdpi/reindeer.png index 2c58a3006..177c658b2 100644 Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/reindeer.png and b/dasherdancer/src/main/res/drawable-xxxhdpi/reindeer.png differ diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/santa.png b/dasherdancer/src/main/res/drawable-xxxhdpi/santa.png index 3a841f400..e2d4fe35b 100644 Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/santa.png and b/dasherdancer/src/main/res/drawable-xxxhdpi/santa.png differ diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/snowman.png b/dasherdancer/src/main/res/drawable-xxxhdpi/snowman.png index c8b6e4d73..6753a837d 100644 Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/snowman.png and b/dasherdancer/src/main/res/drawable-xxxhdpi/snowman.png differ diff --git a/dasherdancer/src/main/res/drawable/btn_main_menu.xml b/dasherdancer/src/main/res/drawable/btn_main_menu.xml index 819fea8c5..f566392ac 100644 --- a/dasherdancer/src/main/res/drawable/btn_main_menu.xml +++ b/dasherdancer/src/main/res/drawable/btn_main_menu.xml @@ -1,4 +1,20 @@ + + diff --git a/dasherdancer/src/main/res/drawable/btn_select_character_pressable.xml b/dasherdancer/src/main/res/drawable/btn_select_character_pressable.xml index ae98f86fb..e8281498b 100644 --- a/dasherdancer/src/main/res/drawable/btn_select_character_pressable.xml +++ b/dasherdancer/src/main/res/drawable/btn_select_character_pressable.xml @@ -1,6 +1,22 @@ + + - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/drawable/btn_x_out_pressable.xml b/dasherdancer/src/main/res/drawable/btn_x_out_pressable.xml index 408a9bfad..10714d997 100644 --- a/dasherdancer/src/main/res/drawable/btn_x_out_pressable.xml +++ b/dasherdancer/src/main/res/drawable/btn_x_out_pressable.xml @@ -1,6 +1,22 @@ + + - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/drawable/dasher_ripple.xml b/dasherdancer/src/main/res/drawable/dasher_ripple.xml index 180e6992b..9da4add54 100644 --- a/dasherdancer/src/main/res/drawable/dasher_ripple.xml +++ b/dasherdancer/src/main/res/drawable/dasher_ripple.xml @@ -1,4 +1,20 @@ + + diff --git a/dasherdancer/src/main/res/drawable/dasher_ripple_small.xml b/dasherdancer/src/main/res/drawable/dasher_ripple_small.xml index 27adb1e1e..071654f55 100644 --- a/dasherdancer/src/main/res/drawable/dasher_ripple_small.xml +++ b/dasherdancer/src/main/res/drawable/dasher_ripple_small.xml @@ -1,4 +1,20 @@ + + diff --git a/dasherdancer/src/main/res/layout/activity_character.xml b/dasherdancer/src/main/res/layout/activity_character.xml index 799dc5394..860d1f3da 100644 --- a/dasherdancer/src/main/res/layout/activity_character.xml +++ b/dasherdancer/src/main/res/layout/activity_character.xml @@ -1,3 +1,19 @@ + + - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/layout/activity_dasher_dancer.xml b/dasherdancer/src/main/res/layout/activity_dasher_dancer.xml index c1d01a778..f8fe68e0f 100644 --- a/dasherdancer/src/main/res/layout/activity_dasher_dancer.xml +++ b/dasherdancer/src/main/res/layout/activity_dasher_dancer.xml @@ -1,3 +1,19 @@ + + - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/raw/reindeer_swipedown.mp3 b/dasherdancer/src/main/res/raw/reindeer_swipedown.mp3 new file mode 100644 index 000000000..5f718f79b Binary files /dev/null and b/dasherdancer/src/main/res/raw/reindeer_swipedown.mp3 differ diff --git a/dasherdancer/src/main/res/raw/reindeer_swipedown.wav b/dasherdancer/src/main/res/raw/reindeer_swipedown.wav deleted file mode 100644 index 348c2bd05..000000000 Binary files a/dasherdancer/src/main/res/raw/reindeer_swipedown.wav and /dev/null differ diff --git a/dasherdancer/src/main/res/values-hdpi/dasher_dancer_values.xml b/dasherdancer/src/main/res/values-hdpi/dasher_dancer_values.xml index 3ca7d661e..ce3ebd1c2 100644 --- a/dasherdancer/src/main/res/values-hdpi/dasher_dancer_values.xml +++ b/dasherdancer/src/main/res/values-hdpi/dasher_dancer_values.xml @@ -1,6 +1,22 @@ + + 2 - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values-mdpi/dasher_dancer_values.xml b/dasherdancer/src/main/res/values-mdpi/dasher_dancer_values.xml index 0e540c993..c53725d30 100644 --- a/dasherdancer/src/main/res/values-mdpi/dasher_dancer_values.xml +++ b/dasherdancer/src/main/res/values-mdpi/dasher_dancer_values.xml @@ -1,6 +1,22 @@ + + 4 - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values-sw600dp-mdpi/dasher_dancer_values.xml b/dasherdancer/src/main/res/values-sw600dp-mdpi/dasher_dancer_values.xml index 3ca7d661e..ce3ebd1c2 100644 --- a/dasherdancer/src/main/res/values-sw600dp-mdpi/dasher_dancer_values.xml +++ b/dasherdancer/src/main/res/values-sw600dp-mdpi/dasher_dancer_values.xml @@ -1,6 +1,22 @@ + + 2 - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values-sw600dp-tvdpi/dasher_dancer_values.xml b/dasherdancer/src/main/res/values-sw600dp-tvdpi/dasher_dancer_values.xml index 3ca7d661e..ce3ebd1c2 100644 --- a/dasherdancer/src/main/res/values-sw600dp-tvdpi/dasher_dancer_values.xml +++ b/dasherdancer/src/main/res/values-sw600dp-tvdpi/dasher_dancer_values.xml @@ -1,6 +1,22 @@ + + 2 - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values-sw600dp-xhdpi/dasher_dancer_values.xml b/dasherdancer/src/main/res/values-sw600dp-xhdpi/dasher_dancer_values.xml index 54fc80742..3c608b1aa 100644 --- a/dasherdancer/src/main/res/values-sw600dp-xhdpi/dasher_dancer_values.xml +++ b/dasherdancer/src/main/res/values-sw600dp-xhdpi/dasher_dancer_values.xml @@ -1,6 +1,22 @@ + + 1 - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values-sw600dp/dasher_dancer_values.xml b/dasherdancer/src/main/res/values-sw600dp/dasher_dancer_values.xml index 54fc80742..3c608b1aa 100644 --- a/dasherdancer/src/main/res/values-sw600dp/dasher_dancer_values.xml +++ b/dasherdancer/src/main/res/values-sw600dp/dasher_dancer_values.xml @@ -1,6 +1,22 @@ + + 1 - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values-sw720dp/dasher_dancer_values.xml b/dasherdancer/src/main/res/values-sw720dp/dasher_dancer_values.xml index 3ca7d661e..ce3ebd1c2 100644 --- a/dasherdancer/src/main/res/values-sw720dp/dasher_dancer_values.xml +++ b/dasherdancer/src/main/res/values-sw720dp/dasher_dancer_values.xml @@ -1,6 +1,22 @@ + + 2 - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values-xhdpi/dasher_dancer_values.xml b/dasherdancer/src/main/res/values-xhdpi/dasher_dancer_values.xml index 3ca7d661e..ce3ebd1c2 100644 --- a/dasherdancer/src/main/res/values-xhdpi/dasher_dancer_values.xml +++ b/dasherdancer/src/main/res/values-xhdpi/dasher_dancer_values.xml @@ -1,6 +1,22 @@ + + 2 - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values-xxhdpi/dasher_dancer_values.xml b/dasherdancer/src/main/res/values-xxhdpi/dasher_dancer_values.xml index 3ca7d661e..ce3ebd1c2 100644 --- a/dasherdancer/src/main/res/values-xxhdpi/dasher_dancer_values.xml +++ b/dasherdancer/src/main/res/values-xxhdpi/dasher_dancer_values.xml @@ -1,6 +1,22 @@ + + 2 - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values-xxxhdpi/dasher_dancer_values.xml b/dasherdancer/src/main/res/values-xxxhdpi/dasher_dancer_values.xml index 54fc80742..3c608b1aa 100644 --- a/dasherdancer/src/main/res/values-xxxhdpi/dasher_dancer_values.xml +++ b/dasherdancer/src/main/res/values-xxxhdpi/dasher_dancer_values.xml @@ -1,6 +1,22 @@ + + 1 - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values/colors.xml b/dasherdancer/src/main/res/values/colors.xml index c669fc595..9791a6cef 100644 --- a/dasherdancer/src/main/res/values/colors.xml +++ b/dasherdancer/src/main/res/values/colors.xml @@ -1,3 +1,19 @@ + + #FFF9CE1D #FF4FC3F7 diff --git a/dasherdancer/src/main/res/values/game_ids.xml b/dasherdancer/src/main/res/values/game_ids.xml index 2530db809..42c5df163 100644 --- a/dasherdancer/src/main/res/values/game_ids.xml +++ b/dasherdancer/src/main/res/values/game_ids.xml @@ -1,7 +1,23 @@ + + CgkIioKF2qwCEAIQGw CgkIioKF2qwCEAIQHA CgkIioKF2qwCEAIQHQ CgkIioKF2qwCEAIQHg - \ No newline at end of file + diff --git a/dasherdancer/src/main/res/values/strings.xml b/dasherdancer/src/main/res/values/strings.xml index 073e5e546..c218d3327 100644 --- a/dasherdancer/src/main/res/values/strings.xml +++ b/dasherdancer/src/main/res/values/strings.xml @@ -1,3 +1,19 @@ + + - Dasher Dancer + Dasher Dancer diff --git a/dasherdancer/src/main/res/values/strings_analytics.xml b/dasherdancer/src/main/res/values/strings_analytics.xml index d7e7ab1a7..9213f448e 100644 --- a/dasherdancer/src/main/res/values/strings_analytics.xml +++ b/dasherdancer/src/main/res/values/strings_analytics.xml @@ -1,16 +1,32 @@ + + - Dasher Dancer - Dasher Dancer Characters - Changed - Dasher Dancer Interaction - Shake - Swipe Left - Swipe Right - Swipe Up - Swipe Down - Pinch In - Pinch Out - Tap - Dasher Dancer Character Select - \ No newline at end of file + Dasher Dancer + Dasher Dancer Characters + Changed + Dasher Dancer Interaction + Shake + Swipe Left + Swipe Right + Swipe Up + Swipe Down + Pinch In + Pinch Out + Tap + Dasher Dancer Character Select + diff --git a/doodles/.gitignore b/doodles/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/doodles/.gitignore @@ -0,0 +1 @@ +/build diff --git a/doodles/build.gradle b/doodles/build.gradle new file mode 100644 index 000000000..23109ee45 --- /dev/null +++ b/doodles/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.tools + + defaultConfig { + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile rootProject.ext.appCompat + compile rootProject.ext.supportAnnotations + compile rootProject.ext.firebaseConfig + + compile project(':common') +} diff --git a/doodles/src/main/AndroidManifest.xml b/doodles/src/main/AndroidManifest.xml new file mode 100644 index 000000000..df7748116 --- /dev/null +++ b/doodles/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/doodles/src/main/assets/dseg7.ttf b/doodles/src/main/assets/dseg7.ttf new file mode 100644 index 000000000..348c74b0e Binary files /dev/null and b/doodles/src/main/assets/dseg7.ttf differ diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/Config.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/Config.java new file mode 100644 index 000000000..2167fe198 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/Config.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles; + +import com.google.firebase.remoteconfig.FirebaseRemoteConfig; + +/** + * Get Firebase Remote config values easily. + */ +public class Config { + + /** Density of swimming obstacles **/ + public final double SWIMMING_OBSTACLE_DENSITY; + + public Config() { + FirebaseRemoteConfig config = FirebaseRemoteConfig.getInstance(); + + SWIMMING_OBSTACLE_DENSITY = config.getDouble("SwimmingObstacleDensity"); + } + +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/PineappleActivity.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/PineappleActivity.java new file mode 100644 index 000000000..0a09f4cf6 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/PineappleActivity.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles; + +import android.app.Fragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; + +import com.google.android.apps.santatracker.doodles.shared.DoodleConfig; +import com.google.android.apps.santatracker.doodles.shared.GameFragment; +import com.google.android.apps.santatracker.doodles.shared.LaunchDecisionMaker; +import com.google.android.apps.santatracker.doodles.shared.PineappleDebugLogger; +import com.google.android.apps.santatracker.invites.AppInvitesFragment; +import com.google.android.apps.santatracker.util.MeasurementManager; +import com.google.firebase.analytics.FirebaseAnalytics; + +/** + * Main activity to route to the various doodle games. + */ +public class PineappleActivity extends FragmentActivity { + private static final String TAG = PineappleActivity.class.getSimpleName(); + private PineappleDebugLogger logger; + private AppInvitesFragment appInvitesFragment; + private FirebaseAnalytics mAnalytics; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_view); + + // Check for game direct launch + DoodleConfig config; + if (getIntent() != null && getIntent().hasExtra(LaunchDecisionMaker.START_GAME_KEY)) { + config = new DoodleConfig(getIntent().getExtras(), null); + } else { + throw new IllegalStateException("Extra START_GAME_KEY required"); + } + + // [ANALYTICS] + mAnalytics = FirebaseAnalytics.getInstance(this); + String gameKey = getIntent().getStringExtra(LaunchDecisionMaker.START_GAME_KEY); + switch (gameKey) { + case LaunchDecisionMaker.WATERPOLO_GAME_VALUE: + MeasurementManager.recordScreenView(mAnalytics, + getString(R.string.analytics_screen_waterpolo)); + break; + case LaunchDecisionMaker.RUNNING_GAME_VALUE: + MeasurementManager.recordScreenView(mAnalytics, + getString(R.string.analytics_screen_running)); + break; + case LaunchDecisionMaker.SWIMMING_GAME_VALUE: + MeasurementManager.recordScreenView(mAnalytics, + getString(R.string.analytics_screen_swimming)); + break; + } + + appInvitesFragment = AppInvitesFragment.getInstance(this); + + logger = new PineappleDebugLogger(); + Fragment fragment = LaunchDecisionMaker.makeFragment(this, config, logger); + FragmentManager fragmentManager = getFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.add(R.id.activity_wrapper, fragment, "menu"); + fragmentTransaction.commit(); + } + + @Override + public void onBackPressed() { + // Get the current game fragment + final Fragment fragment = getFragmentManager().findFragmentById(R.id.activity_wrapper); + + if (fragment instanceof GameFragment) { + GameFragment gameFragment = (GameFragment) fragment; + + // Pause the game, or go back to the home screen if the game is paused already + if (gameFragment.isGamePaused() || !gameFragment.isFinishedLoading() || gameFragment.isGameOver()) { + super.onBackPressed(); + } else { + gameFragment.onBackPressed(); + } + } else { + super.onBackPressed(); + } + } + + public AppInvitesFragment getAppInvitesFragment() { + return appInvitesFragment; + } +} + diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/BackgroundActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/BackgroundActor.java new file mode 100644 index 000000000..d8ce592d8 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/BackgroundActor.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.pursuit; + +import android.content.res.Resources; +import android.graphics.Canvas; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.Camera; +import com.google.android.apps.santatracker.doodles.shared.Sprites; + +/** + * A background actor that follows the camera. + */ +public class BackgroundActor extends Actor { + + private AnimatedSprite backgroundSprite; + + private AnimatedSprite treeSprite; + private AnimatedSprite umbrellaSprite; + + private Camera camera; + + public BackgroundActor(Resources resources, Camera camera) { + this.camera = camera; + + backgroundSprite = + AnimatedSprite.fromFrames(resources, Sprites.snowballrunner_background); + treeSprite = + AnimatedSprite.fromFrames(resources, Sprites.snowball_runner_trees1); + umbrellaSprite = + AnimatedSprite.fromFrames(resources, Sprites.snowball_runner_trees2); + + backgroundSprite.setAnchor(backgroundSprite.frameWidth / 2, 0); + } + + @Override + public void draw(Canvas canvas) { + backgroundSprite.setScale(scale, scale); + float h = backgroundSprite.frameHeight * scale * (960f / 980f); + + // Always draws the background at 0, 0, where the camera is. + // Draws the background sprite three times so the background is not cut off on larger + // devices where the device dimension exceeds the background sprite's size. + backgroundSprite.setPosition(position.x, camera.position.y + -camera.position.y % h); + backgroundSprite.draw(canvas); + + backgroundSprite.setPosition(position.x, camera.position.y + h + (-camera.position.y % h)); + backgroundSprite.draw(canvas); + + backgroundSprite.setPosition(position.x, camera.position.y - h + (-camera.position.y % h)); + backgroundSprite.draw(canvas); + } + + public void drawTop(Canvas canvas) { + float h = backgroundSprite.frameHeight * scale; + + // Makes repeating trees and umbrellas with integer division. + float rightTreeY = h * 0.5f + ((h * 2) * ((int) ((camera.position.y + h) / (h * 2)))); + float rightUmbrellaY = h * 1.5f + ((h * 2) * ((int) ((camera.position.y) / (h * 2)))); + + float leftTreeY = (h * 2) * ((int) ((camera.position.y + (h * 1.5f)) / (h * 2))); + float leftUmbrellaY = + h + ((h * 2) * ((int) ((camera.position.y + (h * 0.5f)) / (h * 2)))); + + treeSprite.setScale(scale, scale); + treeSprite.setPosition(PursuitModel.HALF_WIDTH - (scale * treeSprite.frameWidth) * 0.35f, + rightTreeY + (h * 0.08f) - ((camera.position.y - rightTreeY) / h) * h * 0.12f); + treeSprite.draw(canvas); + + treeSprite.setScale(-scale, scale); + treeSprite.setPosition(-(scale * treeSprite.frameWidth) * 0.3f, + leftTreeY + (h * 0.08f) - ((camera.position.y - leftTreeY) / h) * h * 0.12f); + treeSprite.draw(canvas); + + umbrellaSprite.setScale(scale, scale); + umbrellaSprite.setPosition( + PursuitModel.HALF_WIDTH - (scale * umbrellaSprite.frameWidth) * 0.3f, + rightUmbrellaY - ((camera.position.y - rightUmbrellaY) / h) * h * 0.07f); + umbrellaSprite.draw(canvas); + + umbrellaSprite.setScale(-scale, scale); + umbrellaSprite.setPosition(-(scale * umbrellaSprite.frameWidth) * 0.5f, + leftUmbrellaY - ((camera.position.y - leftUmbrellaY) / h) * h * 0.07f); + umbrellaSprite.draw(canvas); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PlayerActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PlayerActor.java new file mode 100644 index 000000000..792f7caa4 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PlayerActor.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.pursuit; + +import android.content.res.Resources; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.Sprites; + +/** + * The player actor that has two more animation states than runner actor: celebrating running and + * sweating running. + */ +public class PlayerActor extends RunnerActor { + boolean isSweating; + boolean isCelebrating; + + protected AnimatedSprite celebrateSprite; + protected AnimatedSprite sweatSprite; + + public PlayerActor(Resources resources, int lane) { + super(resources, RunnerType.STRAWBERRY, lane); + isSweating = false; + isCelebrating = false; + + sweatSprite = AnimatedSprite.fromFrames(resources, Sprites.snowballrun_running_losing); + celebrateSprite = AnimatedSprite.fromFrames(resources, Sprites.snowballrun_running_normal); + + setSpriteAnchorUpright(sweatSprite); + setSpriteAnchorUpright(celebrateSprite); + } + + @Override + public void setRunnerState(RunnerState state) { + super.setRunnerState(state); + if (state == RunnerState.RUNNING) { + if (isCelebrating) { + currentSprite = celebrateSprite; + } else if (isSweating) { + currentSprite = sweatSprite; + } else { + currentSprite = runningSprite; + } + } + } + + public void setSweat(boolean sweat) { + if (this.isSweating == sweat) { + return; + } + + this.isSweating = sweat; + + if (state != RunnerState.RUNNING || isCelebrating) { + return; + } + + if (sweat) { + sweatSprite.setFrameIndex(runningSprite.getFrameIndex()); + currentSprite = sweatSprite; + } else { + runningSprite.setFrameIndex(sweatSprite.getFrameIndex() % runningSprite.getNumFrames()); + currentSprite = runningSprite; + } + } + + public void setCelebrate(boolean celebrate) { + if (this.isCelebrating == celebrate) { + return; + } + + this.isCelebrating = celebrate; + + if (state != RunnerState.RUNNING) { + return; + } + + if (celebrate) { + celebrateSprite.setFrameIndex(runningSprite.getFrameIndex()); + currentSprite = celebrateSprite; + } else { + runningSprite.setFrameIndex(celebrateSprite.getFrameIndex() % runningSprite.getNumFrames()); + currentSprite = runningSprite; + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PowerUpActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PowerUpActor.java new file mode 100644 index 000000000..4ce390fed --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PowerUpActor.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.pursuit; + +import android.content.res.Resources; +import android.graphics.Canvas; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite.AnimatedSpriteListener; +import com.google.android.apps.santatracker.doodles.shared.Sprites; + +/** + * A power up that speeds up the player. + */ +public class PowerUpActor extends Actor { + private static final int Z_INDEX = 0; + public static final float RADIUS_WORLD = 25f; + + private boolean isPickedUp; + + private AnimatedSprite sprite; + + public PowerUpActor(float x, float y, Resources resources) { + zIndex = Z_INDEX; + position.x = x; + position.y = y; + isPickedUp = false; + + sprite = AnimatedSprite.fromFrames(resources, Sprites.running_powerup); + sprite.setFPS(18); + sprite.setAnchor(sprite.frameWidth / 2, sprite.frameHeight / 2); + sprite.setLoop(false); + sprite.addListener(new AnimatedSpriteListener() { + @Override + public void onFinished() { + super.onFinished(); + hidden = true; + } + }); + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + if (isPickedUp) { + sprite.update(deltaMs); + } + } + + public void pickUp() { + isPickedUp = true; + } + + public boolean isPickedUp() { + return isPickedUp; + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + if (hidden) { + return; + } + float framesPercent = ((float) sprite.getFrameIndex()) / sprite.getNumFrames(); + sprite.setPosition(position.x, position.y + (3f * framesPercent * scale * sprite.frameHeight)); + sprite.setScale(scale, scale); + sprite.draw(canvas); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitFragment.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitFragment.java new file mode 100644 index 000000000..03ccfa613 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitFragment.java @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.pursuit; + +import android.content.Context; +import android.graphics.Point; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.v4.content.ContextCompat; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.pursuit.PursuitModel.ScoreListener; +import com.google.android.apps.santatracker.doodles.pursuit.PursuitModel.State; +import com.google.android.apps.santatracker.doodles.pursuit.PursuitModel.StateChangedListener; +import com.google.android.apps.santatracker.doodles.shared.AndroidUtils; +import com.google.android.apps.santatracker.doodles.shared.DoodleConfig; +import com.google.android.apps.santatracker.doodles.shared.EventBus; +import com.google.android.apps.santatracker.doodles.shared.EventBus.EventBusListener; +import com.google.android.apps.santatracker.doodles.shared.GameFragment; +import com.google.android.apps.santatracker.doodles.shared.GameType; +import com.google.android.apps.santatracker.doodles.shared.HistoryManager; +import com.google.android.apps.santatracker.doodles.shared.PineappleLogger; +import com.google.android.apps.santatracker.doodles.shared.UIUtil; +import com.google.android.apps.santatracker.doodles.shared.sound.SoundManager; +import com.google.android.apps.santatracker.util.MeasurementManager; +import com.google.firebase.analytics.FirebaseAnalytics; + +import java.text.NumberFormat; +import java.util.Locale; + +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.RUNNING_GAME_TYPE; + +/** + * Fragment for the second version of the running game. + * Manages input & threads, delegates to PursuitModel & PursuitView for the rest. + */ +public class PursuitFragment extends GameFragment implements EventBusListener { + private static final String TAG = PursuitFragment.class.getSimpleName(); + + private static final long GAME_OVER_DELAY_MILLISECONDS = 1000; + private static final long GAME_OVER_SHORT_DELAY_MILLISECONDS = 150; + + private PursuitView gameView; + private TextView countdownView; + private PursuitModel model; + private boolean mIsGameOver = false; + + public PursuitFragment() { + super(); + } + + public PursuitFragment(Context context, DoodleConfig doodleConfig, PineappleLogger logger) { + super(context, doodleConfig, logger); + } + + @Override + public void update(float deltaMs) { + if (!isPaused) { + model.update(deltaMs); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + if (context == null) { + return null; + } + + historyManager = new HistoryManager(context, new HistoryManager.HistoryListener() { + @Override + public void onFinishedLoading() { + } + @Override + public void onFinishedSaving() { + } + }); + + wrapper = new FrameLayout(context); + + titleView = getTitleView(R.drawable.snowballrunner_loadingscreen, R.string.running); + wrapper.addView(titleView); + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + loadGame(); + } + }); + return wrapper; + } + + @Override + protected void firstPassLoadOnUiThread() { + wrapper.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return onTouchEvent(event); + } + }); + + countdownView = new TextView(context); + countdownView.setGravity(Gravity.CENTER); + countdownView.setTextColor(context.getResources().getColor(R.color.ui_text_yellow)); + countdownView.setTypeface(Typeface.DEFAULT_BOLD); + countdownView.setText("0"); + countdownView.setVisibility(View.INVISIBLE); + Locale locale = context.getResources().getConfiguration().locale; + countdownView.setText(NumberFormat.getInstance(locale).format(3)); + Point screenDimens = AndroidUtils.getScreenSize(); + UIUtil.fitToBounds(countdownView, screenDimens.x / 10, screenDimens.y / 10); + + final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); + gameView = new PursuitView(context); + wrapper.addView(gameView, 0, lp); + + wrapper.addView(countdownView, 1, lp); + scoreView = getScoreView(); + wrapper.addView(scoreView, 2, lp); + pauseView = getPauseView(); + pauseView.hidePauseButton(); + wrapper.addView(pauseView, 3, lp); + } + + @Override + protected void secondPassLoadOnBackgroundThread() { + super.secondPassLoadOnBackgroundThread(); + EventBus.getInstance().register(this); + + model = new PursuitModel(context.getResources(), getActivity().getApplicationContext()); + gameView.setModel(model); + model.setStateListener(new StateChangedListener() { + @Override + public void onStateChanged(State state) { + if (state == State.SETUP) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + hideTitle(); + pauseView.showPauseButton(); + } + }); + } else if (state == State.SUCCESS) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + if (model == null) { + return; + } + mIsGameOver = true; + float timeInSeconds = model.getScore(); + int starCount = 4 - model.getFinishingPlace(); + + long delay = GAME_OVER_SHORT_DELAY_MILLISECONDS; + if (model.getFinishingPlace() == 1) { + delay = GAME_OVER_DELAY_MILLISECONDS; + } + + Double bestTimeInSeconds = historyManager.getBestScore(GameType.PURSUIT); + Integer bestStarCount = historyManager.getBestStarCount(GameType.PURSUIT); + + if (bestTimeInSeconds == null || timeInSeconds < bestTimeInSeconds) { + bestTimeInSeconds = (double) timeInSeconds; + historyManager.setBestScore(GameType.PURSUIT, bestTimeInSeconds); + historyManager.save(); + } + + if (bestStarCount == null || starCount > bestStarCount) { + bestStarCount = starCount; + historyManager.setBestStarCount(GameType.PURSUIT, bestStarCount); + historyManager.save(); + } + + pauseView.hidePauseButton(); + + final int finalStarCount = starCount; + final double finalBestTimeInSeconds = bestTimeInSeconds; + + scoreView.postDelayed(new Runnable() { + @Override + public void run() { + if (finalStarCount >= 1) { + scoreView.addStar(); + } + if (finalStarCount >= 2) { + scoreView.addStar(); + } + if (finalStarCount >= 3) { + scoreView.addStar(); + } + scoreView.updateBestScore(AndroidUtils.getText(context.getResources(), + R.string.pursuit_score, finalBestTimeInSeconds)); + scoreView.setShareDrawable(getShareImageDrawable(finalStarCount)); + updateShareText(); + + scoreView.animateToEndState(); + } + }, delay); + } + }); + + // [ANALYTICS] + FirebaseAnalytics analytics = FirebaseAnalytics.getInstance(getActivity()); + MeasurementManager.recordRunningEnd(analytics, + 4 - model.getFinishingPlace(), + (int) model.getScore()); + } else if (state == State.FAIL) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + pauseView.hidePauseButton(); + mIsGameOver = true; + + scoreView.postDelayed(new Runnable() { + @Override + public void run() { + scoreView.setHeaderText(null); + + updateShareText(); + scoreView.setShareDrawable(getShareImageDrawable(0)); + scoreView.animateToEndState(); + } + }, GAME_OVER_DELAY_MILLISECONDS); + }}); + + // [ANALYTICS] + FirebaseAnalytics analytics = FirebaseAnalytics.getInstance(getActivity()); + MeasurementManager.recordRunningEnd(analytics, 0, 0); + } else if (state == State.READY) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + mIsGameOver = false; + pauseView.showPauseButton(); + } + }); + } + } + }); + + model.setScoreListener(new ScoreListener() { + @Override + public void newScore(final float timeInSeconds) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + scoreView.updateCurrentScore( + AndroidUtils.getText(context.getResources(), + R.string.pursuit_score, timeInSeconds), false); + } + }); + } + }); + model.setCountdownView(countdownView); + } + @Override + protected void finalPassLoadOnUiThread() { + soundManager = SoundManager.getInstance(); + loadSounds(); + + onFinishedLoading(); + startHandlers(); + } + + @Override + protected void loadSounds() { + super.loadSounds(); + soundManager.loadShortSound(context, R.raw.bmx_cheering); + soundManager.loadShortSound(context, R.raw.jumping_jump); + soundManager.loadShortSound(context, R.raw.present_throw_character_appear); + soundManager.loadShortSound(context, R.raw.running_foot_loop_fast, true, 2f); + soundManager.loadShortSound(context, R.raw.running_foot_power_up); + soundManager.loadShortSound(context, R.raw.running_foot_power_up_fast, false, 0.4f); + soundManager.loadShortSound(context, R.raw.running_foot_power_squish); + soundManager.loadShortSound(context, R.raw.present_throw_block); + } + + @Override + protected void replay() { + super.replay(); + model.gameReplay(); + } + + private Drawable getShareImageDrawable(int starCount) { + return ContextCompat.getDrawable(getActivity(), R.drawable.winner); + } + + @Override + protected void onDestroyHelper() { + if (gameView != null) { + gameView.setModel(null); + } + model = null; + } + + @Override + public void onEventReceived(int type, Object data) { + if (isDestroyed) { + return; + } + if (type == EventBus.PLAY_SOUND && soundManager != null) { + int resId = (int) data; + soundManager.play(resId); + } else if (type == EventBus.PAUSE_SOUND && soundManager != null) { + int resId = (int) data; + soundManager.pause(resId); + } else if (type == EventBus.MUTE_SOUNDS && soundManager != null) { + boolean shouldMute = (boolean) data; + if (shouldMute) { + soundManager.mute(); + } else { + soundManager.unmute(); + } + } else if (type == EventBus.GAME_LOADED) { + mIsGameOver = false; + long loadTimeMs = (long) data; + model.titleDurationMs = Math.max(0, model.titleDurationMs - loadTimeMs); + Log.d(TAG, "Waiting " + model.titleDurationMs + "ms and then hiding title."); + } + } + + public boolean onTouchEvent(MotionEvent event) { + if (model != null) { + model.touch(event); + return true; + } + return false; + } + + @Override + protected void resume() { + super.resume(); + if (uiRefreshHandler != null) { + uiRefreshHandler.start(gameView); + } + } + + private void updateShareText() { + } + + @Override + protected String getGameType() { + return RUNNING_GAME_TYPE; + } + + @Override + protected float getScore() { + if (model == null) { + return 0; + } + return model.getScore(); + } + + @Override + protected int getShareImageId() { + return scoreView.getStarCount(); + } + + public boolean isGameOver() { + return mIsGameOver; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitLevel.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitLevel.java new file mode 100644 index 000000000..3adecbd55 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitLevel.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.pursuit; + +import android.content.res.Resources; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +/** + * PursuitLevel is a programmatic representation of a .mp file which contains rows of power ups. + * Lanes devoid of power ups are represented by '.'. + * A power up is represented by 1. + * Example: '.1.' is equivalent to a row with a power up in the middle lane. + */ +public class PursuitLevel { + private List level; + + public PursuitLevel(int resId, Resources resources) { + level = new ArrayList<>(); + BufferedReader reader = new BufferedReader( + new InputStreamReader(resources.openRawResource(resId))); + try { + String line = reader.readLine(); + while (line != null) { + level.add(line.toCharArray()); + line = reader.readLine(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public char[] getRowArray(int row) { + return level.get(row % level.size()); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitModel.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitModel.java new file mode 100644 index 000000000..7af7e0c04 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitModel.java @@ -0,0 +1,1244 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.pursuit; + +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Point; +import android.os.Build; +import android.os.Vibrator; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.widget.TextView; +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.pursuit.RunnerActor.RunnerState; +import com.google.android.apps.santatracker.doodles.pursuit.RunnerActor.RunnerType; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.ActorHelper; +import com.google.android.apps.santatracker.doodles.shared.ActorTween; +import com.google.android.apps.santatracker.doodles.shared.ActorTween.Callback; +import com.google.android.apps.santatracker.doodles.shared.AndroidUtils; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.Camera; +import com.google.android.apps.santatracker.doodles.shared.CameraShake; +import com.google.android.apps.santatracker.doodles.shared.EmptyTween; +import com.google.android.apps.santatracker.doodles.shared.EventBus; +import com.google.android.apps.santatracker.doodles.shared.FakeButtonActor; +import com.google.android.apps.santatracker.doodles.shared.GameFragment; +import com.google.android.apps.santatracker.doodles.shared.Interpolator; +import com.google.android.apps.santatracker.doodles.shared.RectangularInstructionActor; +import com.google.android.apps.santatracker.doodles.shared.Sprites; +import com.google.android.apps.santatracker.doodles.shared.Tween; +import com.google.android.apps.santatracker.doodles.shared.TweenManager; +import com.google.android.apps.santatracker.doodles.shared.UIUtil; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +/** + * All the game logic for the second version of the running game. Mostly consists of managing + * a list of Actors. + */ +public class PursuitModel { + private static final String TAG = PursuitModel.class.getSimpleName(); + + /** + * High-level phases of the game are controlled by a state machine which uses these states. + */ + public enum State { + TITLE, + SETUP, + READY, + RUNNING, + SUCCESS, + FAIL, + } + + /** + * Will be notified when game enters a new state. + */ + public interface StateChangedListener { + void onStateChanged(State state); + } + + /** + * Will be notified when the score changes. + */ + public interface ScoreListener { + void newScore(float timeInSeconds); + } + + /** + * The other fruit the player is racing against. + */ + public class OpponentActor extends RunnerActor { + // Flag that indicates whether the opponent has crossed the finishing line. + // Used for decelerating the opponent. + public boolean isFinished; + + OpponentActor(Resources resources, RunnerType type, int lane) { + super(resources, type, lane); + isFinished = false; + } + } + + // Game-world uses a fixed coordinate system which, for simplicity, matches the resolution of the + // art assets (i.e. 1 pixel in the art == 1 game-world unit). Measurements from art assets + // directly translate to game-world units. Example: player1.png's racket is 57 pixels from the + // bottom, so if the ball is 57 game-world units above the bottom of player's sprite, the ball is + // at the same height as the racket). The view is responsible for scaling to fit the screen. + + // Visualization Constants + public static final int HEIGHT = 960; + public static final int WIDTH = 540; + public static final int HALF_WIDTH = WIDTH / 2; + public static final int HALF_HEIGHT = HEIGHT / 2; + public static final int EXPECTED_PLAYER_WIDTH = (int) (WIDTH * 0.14f); + + // UI Constants + private static final float BUTTON_SCALE = 0.8f; + private static final float TUTORIAL_DURATION = 4f; + private static final int COUNTDOWN_LABEL_COLOR = 0xffffbb39; + + // High level Android variables that lays the foundation for the game. + private final Resources resources; + private final TweenManager tweenManager = new TweenManager(); + private final Vibrator vibrator; + private final EventBus eventBus; + private final Locale locale; + + // Temporary Power-up generation variables that will be replaced by a more robust system. + private float powerUpTimer; + private int mapRow = 0; + private PursuitLevel map; + + // Gameplay Constants. + + // Currently this game is divided into lanes. + // Power ups are added at the center of each discrete lane. + // As the game speed is increased, more lanes are added, increasing the gameplay area. + public static final int NUM_LANES = 3; + public static final int MIN_LANE = 0; + public static final int MAX_LANE = NUM_LANES - 1; + public static final int INITIAL_LANE = NUM_LANES / 2; + public static final int LANE_SIZE = WIDTH / (NUM_LANES + 2); + + // All duration in seconds. + private static final float LANE_SWITCH_DURATION = 0.10f; + public static final float RUNNER_ENTER_DURATION = 1.72f; + private static final float RUNNER_STANDING_DURATION = 0.5f; + private static final float SETUP_DURATION = + RUNNER_ENTER_DURATION + RUNNER_STANDING_DURATION + 0.6f; + + // Speed constants. + public static final float BASE_SPEED = 340f; + + private static final float PLAYER_MINIMUM_SPEED = BASE_SPEED; + private static final float PLAYER_MAXIMUM_SPEED = BASE_SPEED + 450f; + private static final float PLAYER_DECELERATION = 300f; + + private static final float MANGO_SPEED = BASE_SPEED + 250f; + private static final float GRAPE_SPEED = BASE_SPEED + 315f; + private static final float APRICOT_SPEED = BASE_SPEED + 280f; + + private static final float WATERMELON_MINIMUM_SPEED = PLAYER_MINIMUM_SPEED + 100f; + private static final float WATERMELON_MAXIMUM_SPEED = PLAYER_MAXIMUM_SPEED + 25f; + private static final float WATERMELON_SPEED_INCREASE_PER_SECOND = 2.5f; + private static final float WATERMELON_SPEED_DECREASE_PER_SECOND = 6f; + + private static final float OPPONENT_SLOW_DOWN_DURATION = 0.24f; + private static final float OPPONENT_SLOW_DOWN_AMOUNT = 450f; + + private static final float RUNNER_FINISH_DURATION = 5f; + private static final float WATERMELON_FINISH_DURATION = 4f; + + // Size constants. + private static final float STRAWBERRY_RADIUS = 15f; + private static final float MANGO_RADIUS = 28f; + private static final float GRAPE_RADIUS = 12f; + private static final float APRICOT_RADIUS = 22f; + + // Misc. constants. + private static final float POWER_UP_SPEED_BOOST = 320f; + private static final float TOTAL_DISTANCE = 16000f; + private static final int VIBRATION_MS = 60; + + // Positional constants. + private static final float PLAYER_INITIAL_POSITION_Y = HEIGHT * 0.25f; + private static final float OPPONENT_INITIAL_POSITION_Y = HEIGHT * 0.4f; + private static final float RIBBON_INITIALIZATION_POSITION_Y + = PLAYER_INITIAL_POSITION_Y + TOTAL_DISTANCE; + + // Camera constants. + private static final float CAMERA_LOOKAHEAD_INCREASE_PER_SECOND = 0.8f; + private static final float CAMERA_LOOKAHEAD_DECREASE_PER_SECOND = 2.5f; + private static final float CAMERA_MAXIMUM_LOOKAHEAD = -(HEIGHT * 0.25f); + + // Gameplay variables. + private float baseScale; + private State state; + private float laneSwitchTimer = 0f; + private float cameraLookAhead; // The camera trails behind the player when player is going fast. + private boolean watermelonHasEntered = false; + private boolean playerHasStarted = false; + + // Player performance variables. + private float time; + private int finishingPlace; // First place = 1. + + // Listeners. + private StateChangedListener stateListener; + private ScoreListener scoreListener; + + // Public so view can render the actors. + public final List actors = Collections.synchronizedList(new ArrayList()); + public final List ui = Collections.synchronizedList(new ArrayList()); + + private final List powerUps = new ArrayList(); + private final List opponents = new ArrayList(); + + public final CameraShake cameraShake; // Public so view can read the amount of shake. + public final Camera camera; + + // Actors. + public PlayerActor player; + public OpponentActor mango; + public OpponentActor grape; + public OpponentActor apricot; + + public WatermelonActor watermelon; + public RibbonActor ribbon; + + // UI Buttons. + public FakeButtonActor leftButton; + public FakeButtonActor rightButton; + private RectangularInstructionActor instructions; + private TextView countdownView; + + // Background + public BackgroundActor backgroundActor; + + // public so that the GameFragment can update the duration. + public long titleDurationMs = GameFragment.TITLE_DURATION_MS; + + public PursuitModel(Resources resources, Context context) { + this.resources = resources; + + eventBus = EventBus.getInstance(); + + vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + locale = resources.getConfiguration().locale; + + cameraShake = new CameraShake(); + camera = new Camera(WIDTH, HEIGHT); + camera.position.x = -HALF_WIDTH; + + map = new PursuitLevel(R.raw.running, resources); + + initActors(); + showTitle(); + } + + private void initActors() { + // Initialize background + backgroundActor = new BackgroundActor(resources, camera); + backgroundActor.scale = 1.15f; + + player = new PlayerActor(resources, INITIAL_LANE); + player.setRadius(STRAWBERRY_RADIUS); + ribbon = new RibbonActor(0, RIBBON_INITIALIZATION_POSITION_Y, resources); + watermelon = new WatermelonActor(resources); + + // Scale actors to fit screen + baseScale = (1f * EXPECTED_PLAYER_WIDTH) / player.currentSprite.frameWidth; + + player.scale = baseScale * 1.07f; + watermelon.scale = baseScale * 1.6f; + ribbon.scale = baseScale * 1.03f; + + // Add the essential actors to screen + synchronized (actors) { + actors.add(player); + actors.add(ribbon); + actors.add(watermelon); + } + + // Add the opponents + mango = addOpponent(RunnerType.MANGO, 0, OPPONENT_INITIAL_POSITION_Y, MANGO_RADIUS); + grape = addOpponent(RunnerType.GRAPE, 1, OPPONENT_INITIAL_POSITION_Y, GRAPE_RADIUS); + apricot = addOpponent(RunnerType.APRICOT, 2, OPPONENT_INITIAL_POSITION_Y, APRICOT_RADIUS); + + AnimatedSprite runningTutorialSprite = + AnimatedSprite.fromFrames(resources, Sprites.tutorial_running); + runningTutorialSprite.setFPS(7); + + // Initialize and add the UI actors + instructions = new RectangularInstructionActor(resources, runningTutorialSprite); + instructions.hidden = true; + + instructions.scale = 0.54f; + instructions.position.set(HALF_WIDTH - instructions.getScaledWidth() / 2, + HEIGHT * 0.65f - instructions.getScaledHeight() / 2); + + leftButton = new FakeButtonActor( + AnimatedSprite.fromFrames(resources, Sprites.running_button)); + leftButton.rotation = -(float) Math.PI / 2; + leftButton.sprite.setFPS(12); + leftButton.scale = BUTTON_SCALE; + leftButton.position.x = WIDTH * 0.22f - (leftButton.sprite.frameWidth * BUTTON_SCALE / 2); + leftButton.position.y = HEIGHT - 20; + leftButton.alpha = 0; + + rightButton = new FakeButtonActor( + AnimatedSprite.fromFrames(resources, Sprites.running_button)); + rightButton.rotation = (float) Math.PI / 2; + rightButton.sprite.setFPS(12); + rightButton.scale = BUTTON_SCALE; + rightButton.position.x = WIDTH * 0.78f + (rightButton.sprite.frameWidth * BUTTON_SCALE / 2); + rightButton.position.y = HEIGHT - (rightButton.sprite.frameHeight * BUTTON_SCALE) - 20; + rightButton.alpha = 0; + + ui.add(instructions); + ui.add(leftButton); + ui.add(rightButton); + } + + // Resets the gameplay variables for a replay or a first play. + private void resetGame() { + Log.i(TAG, "Reset game."); + + camera.position.y = 0; + + laneSwitchTimer = 0; + + player.setRunnerState(RunnerState.CROUCH); + player.setSweat(false); + player.setCelebrate(false); + + mango.setRunnerState(RunnerState.CROUCH); + mango.isFinished = false; + grape.setRunnerState(RunnerState.CROUCH); + grape.isFinished = false; + apricot.setRunnerState(RunnerState.CROUCH); + apricot.isFinished = false; + + tweenManager.removeAll(); + + watermelonHasEntered = false; + playerHasStarted = false; + cameraLookAhead = 0; + + watermelon.position.y = -HEIGHT * 0.5f; + watermelon.velocity.y = 0; + + player.position.x = 0; + player.position.y = PLAYER_INITIAL_POSITION_Y; + player.velocity.y = 0; + + ribbon.position.y = RIBBON_INITIALIZATION_POSITION_Y; + + synchronized (actors) { + for (PowerUpActor powerUp : powerUps) { + actors.remove(powerUp); + } + } + powerUps.clear(); + + mango.position.y = OPPONENT_INITIAL_POSITION_Y; + grape.position.y = OPPONENT_INITIAL_POSITION_Y; + apricot.position.y = OPPONENT_INITIAL_POSITION_Y; + + mango.velocity.y = 0; + grape.velocity.y = 0; + apricot.velocity.y = 0; + + leftButton.alpha = 1; + rightButton.alpha = 1; + + powerUpTimer = 0; + mapRow = 0; + + time = 0; + finishingPlace = 0; + updateScore(); + + eventBus.sendEvent(EventBus.PAUSE_SOUND, R.raw.running_foot_loop_fast); + } + + private void beginGame() { + mango.setRunnerState(RunnerState.RUNNING); + grape.setRunnerState(RunnerState.RUNNING); + apricot.setRunnerState(RunnerState.RUNNING); + + player.velocity.y = 0; + watermelon.velocity.y = PLAYER_MAXIMUM_SPEED; + + tweenManager.add(new Tween(0.6f) { + @Override + protected void updateValues(float percentDone) { + mango.velocity.y = percentDone * MANGO_SPEED; + grape.velocity.y = percentDone * GRAPE_SPEED; + apricot.velocity.y = percentDone * APRICOT_SPEED; + } + }); + + eventBus.sendEvent(EventBus.PLAY_SOUND, R.raw.running_foot_loop_fast); + eventBus.sendEvent(EventBus.PLAY_SOUND, R.raw.running_foot_power_up); + } + + public void update(float deltaMs) { + synchronized (this) { + float timeInSeconds = deltaMs / 1000f; + + camera.update(deltaMs); + cameraShake.update(deltaMs); + + if (state == State.RUNNING) { + if (!(player.getRunnerState() == RunnerState.RUNNING_LEFT + || player.getRunnerState() == RunnerState.RUNNING_RIGHT)) { + player.setRunnerState(RunnerState.RUNNING); + } + + if (player.getRunnerState() == RunnerState.RUNNING) { + updatePlayerSpeed(timeInSeconds); + } + } + + if (state != State.TITLE) { + for (int i = 0; i < actors.size(); i++) { + actors.get(i).update(deltaMs); + } + + for (int i = 0; i < ui.size(); i++) { + ui.get(i).update(deltaMs); + } + } + + tweenManager.update(deltaMs); + synchronized (actors) { + Collections.sort(actors); + } + + laneSwitchTimer = Math.max(0, laneSwitchTimer - timeInSeconds); + + if (state == State.RUNNING || (state == State.SUCCESS && finishingPlace == 1)) { + updateRunningCamera(timeInSeconds); + } + + if (state == State.RUNNING) { + // Reads the next row of power ups from PursuitLevel and adds them, + // Then resets the timer. + powerUpTimer -= timeInSeconds; + if (powerUpTimer <= 0) { + powerUpTimer = 0.18f - 0.06f * (Math.max(0, player.velocity.y) / PLAYER_MAXIMUM_SPEED); + addPowerUpRow(); + mapRow++; + } + checkPowerUps(); + + updateWatermelon(timeInSeconds); + + // If player is getting close to the watermelon, make the sprite sweat. + if (player.position.y - player.getRadius() + < watermelon.position.y + WatermelonActor.VERTICAL_RADIUS_WORLD * 2.7f) { + player.setSweat(true); + } else { + player.setSweat(false); + } + + // Check success and fail states based on player's location + if (watermelonCollidesWithRunner(player)) { + gameFail(); + } else if (player.position.y > ribbon.position.y) { + gameSuccess(); + } + + // Update the score + time += timeInSeconds; + updateScore(); + } + + checkOpponentsPlayerCollision(); + checkOpponentsFinished(); + checkOpponentsWatermelonCollision(); + } + } + + // If the state is running, update the camera according to the player's position and speed. + // If the player is sufficiently fast, the camera trails behind the player a little. + private void updateRunningCamera(float timeInSeconds) { + float targetCameraLookahead = + CAMERA_MAXIMUM_LOOKAHEAD * Math.max(0, player.velocity.y - PLAYER_MINIMUM_SPEED) + / (PLAYER_MAXIMUM_SPEED - PLAYER_MINIMUM_SPEED); + float deltaCameraLookahead = (targetCameraLookahead - cameraLookAhead); + if (deltaCameraLookahead > 0) { + deltaCameraLookahead *= CAMERA_LOOKAHEAD_DECREASE_PER_SECOND * timeInSeconds; + } else { + deltaCameraLookahead *= CAMERA_LOOKAHEAD_INCREASE_PER_SECOND * timeInSeconds; + } + + cameraLookAhead += deltaCameraLookahead; + camera.position.y = -PLAYER_INITIAL_POSITION_Y + cameraLookAhead + player.position.y; + } + + // Decelerates the player. + private void updatePlayerSpeed(float timeInSeconds) { + if (!playerHasStarted) { + player.velocity.y += timeInSeconds * PLAYER_MINIMUM_SPEED * 1.7f; + if (player.velocity.y > PLAYER_MINIMUM_SPEED) { + playerHasStarted = true; + } + } else { + player.velocity.y = player.velocity.y - PLAYER_DECELERATION * timeInSeconds; + // Give speed lower and upper bound + player.velocity.y = Math.max(player.velocity.y, PLAYER_MINIMUM_SPEED); + player.velocity.y = Math.min(player.velocity.y, PLAYER_MAXIMUM_SPEED); + } + } + + // Changes the watermelon's speed to roughly match the player's. + private void updateWatermelon(float timeInSeconds) { + float targetSpeed = BASE_SPEED + ((player.velocity.y - BASE_SPEED) * 1.08f); + // Give speed lower and upper bound + targetSpeed = Math.max(targetSpeed, WATERMELON_MINIMUM_SPEED); + targetSpeed = Math.min(targetSpeed, WATERMELON_MAXIMUM_SPEED); + + float targetSpeedDelta = targetSpeed - watermelon.velocity.y; + + float watermelonPlayerDistance = + (player.position.y - player.getRadius()) + - (watermelon.position.y + WatermelonActor.VERTICAL_RADIUS_WORLD); + + if (targetSpeedDelta < 0 || !watermelonHasEntered) { + // The watermelon decrease speed is inversely proportional to the distance between the + // watermelon and the player. The closer the player the larger the decrease. + float decreaseFactor = 1 + ((1 / Math.max(1, watermelonPlayerDistance / 40)) * 7f); + float decreaseSpeed = WATERMELON_SPEED_DECREASE_PER_SECOND * decreaseFactor; + watermelon.velocity.y += targetSpeedDelta * Math.min(1, decreaseSpeed * timeInSeconds); + } else if (targetSpeedDelta > 0) { + // The watermelon increase speed is proportional to the distance between the watermelon and + // the player. The further the player the larger the increase. + // The watermelon decrease speed is also affected by the amount of time played. The longer + // the time the greater the increase. + float increaseFactor = Math.max(0.6f, 1 + ((watermelonPlayerDistance - 140) / 240)); + float timeFactor = 0.3f + (0.7f * Math.min(1, time / 20f)); + float increaseSpeed = WATERMELON_SPEED_INCREASE_PER_SECOND * increaseFactor * timeFactor; + watermelon.velocity.y += targetSpeedDelta * Math.min(1, increaseSpeed * timeInSeconds); + } + + if (watermelon.position.y > camera.position.y) { + watermelonHasEntered = true; + } + + if (watermelonHasEntered) { + watermelon.position.y = Math.max(watermelon.position.y, camera.position.y); + watermelon.position.y = Math.min(watermelon.position.y, camera.position.y + - CAMERA_MAXIMUM_LOOKAHEAD * 1.13f); + } + } + + private void updateScore() { + scoreListener.newScore(time); + } + + // Check power ups for collision with the player. + private void checkPowerUps() { + for (int i = powerUps.size() - 1; i >= 0; i--) { + PowerUpActor powerUp = powerUps.get(i); + + // Check if PowerUp collides with the Player. + double powerUpDistance = ActorHelper.distanceBetween(player, powerUp); + if (powerUpDistance < (PowerUpActor.RADIUS_WORLD + player.getRadius()) + && !powerUp.isPickedUp()) { + powerUpPlayer(powerUp); + } + } + } + + // Checks if any of the opponents collide with the player. + // If there is a collision, set the player's position to the runner's. + private void checkOpponentsPlayerCollision() { + // If the player is currently moving just ignore any collision. + if (laneSwitchTimer > 0) { + return; + } + + for (OpponentActor opponent : opponents) { + if (opponent.getLane() == player.getLane()) { + float diffY = player.position.y - opponent.position.y; + float combinedRadius = opponent.getRadius() + player.getRadius(); + + if (0 <= diffY && diffY < combinedRadius) { + // Player is in front of opponent + opponent.position.y = + player.position.y - combinedRadius; + } else if (-combinedRadius < diffY && diffY < 0) { + // Player is behind the opponent + player.position.y = + opponent.position.y - combinedRadius; + } + } + } + } + + // Checks if any of the opponents are touching the watermelon. If so, squish the runner. + private void checkOpponentsWatermelonCollision() { + for (OpponentActor opponent : opponents) { + if (opponent.getRunnerState() == RunnerState.RUNNING + && watermelonCollidesWithRunner(opponent)) { + eventBus.sendEvent(EventBus.PLAY_SOUND, R.raw.running_foot_power_squish); + opponent.setRunnerState(RunnerState.DYING); + opponent.velocity.y = 0; + } + } + } + + private void checkOpponentsFinished() { + for (final OpponentActor opponent : opponents) { + if (opponent.position.y > ribbon.position.y) { + // The opponent crosses the finish line, break the ribbon and decelerate the opponent. + + if (!opponent.isFinished) { + opponent.isFinished = true; + + final float initialSpeed = opponent.velocity.y; + tweenManager.add(new Tween(RUNNER_FINISH_DURATION) { + @Override + protected void updateValues(float percentDone) { + if (opponent.state == RunnerState.RUNNING) { + opponent.velocity.y = (1 - percentDone) * initialSpeed; + if (percentDone > 0.95f) { + opponent.setRunnerState(RunnerState.STANDING); + } + } else { + opponent.velocity.y = 0; + } + } + }); + } + } + } + } + + // TODO: Replace with an ellipse to circle collision model. + public boolean watermelonCollidesWithRunner(RunnerActor actor) { + if (actor.position.y - actor.getRadius() + < watermelon.position.y + WatermelonActor.VERTICAL_RADIUS_WORLD + && actor.getLane() != INITIAL_LANE) { + return true; + } + return actor.position.y - actor.getRadius() + < watermelon.position.y + WatermelonActor.VERTICAL_RADIUS_WORLD * 1.2f + && actor.getLane() == INITIAL_LANE; + } + + private void gameSetup() { + Log.i(TAG, "Game Mode: Setup."); + setState(State.SETUP); + + player.position.y = PLAYER_INITIAL_POSITION_Y; + mango.position.y = OPPONENT_INITIAL_POSITION_Y; + grape.position.y = OPPONENT_INITIAL_POSITION_Y; + apricot.position.y = OPPONENT_INITIAL_POSITION_Y; + + mango.setRunnerState(RunnerState.STANDING); + grape.setRunnerState(RunnerState.STANDING); + apricot.setRunnerState(RunnerState.STANDING); + + final Tween mangoCrouchDelay = new EmptyTween(0.6f) { + @Override + protected void onFinish() { + mango.setRunnerState(RunnerState.CROUCH); + } + }; + tweenManager.add(mangoCrouchDelay); + + final Tween grapeCrouchDelay = new EmptyTween(0.9f) { + @Override + protected void onFinish() { + grape.setRunnerState(RunnerState.CROUCH); + } + }; + tweenManager.add(grapeCrouchDelay); + + final Tween apricotCrouchDelay = new EmptyTween(1.2f) { + @Override + protected void onFinish() { + apricot.setRunnerState(RunnerState.CROUCH); + } + }; + tweenManager.add(apricotCrouchDelay); + + runnerEnter(player); + + watermelon.position.y = HEIGHT * -0.5f; + + final Tween setupDuration = new EmptyTween(SETUP_DURATION) { + @Override + protected void onFinish() { + if (state == State.SETUP) { + gameFirstPlay(); + } + } + }; + tweenManager.add(setupDuration); + } + + private void gameFirstPlay() { + Log.i(TAG, "Game Mode: Tutorial."); + instructions.show(); + tweenManager.add(new EmptyTween(TUTORIAL_DURATION) { + @Override + protected void onFinish() { + instructions.hide(); + } + }); + tweenManager.add(new EmptyTween(TUTORIAL_DURATION + 0.3f) { + @Override + protected void onFinish() { + startCountdownAnimation(); + } + }); + tweenManager.add(new EmptyTween(TUTORIAL_DURATION + 0.3f + 3f) { + @Override + protected void onFinish() { + gameStart(); + countdownView.post(new Runnable() { + @Override + public void run() { + countdownView.setVisibility(View.INVISIBLE); + } + }); + } + }); + player.setLane(INITIAL_LANE); + showButtons(); + setState(State.READY); + } + + public void gameReplay() { + Log.i(TAG, "Game Restart."); + resetGame(); + instructions.hide(); // In case the player hits the replay button before the game begins. + tweenManager.add(new EmptyTween(0.2f) { + @Override + protected void onFinish() { + startCountdownAnimation(); + } + }); + tweenManager.add(new EmptyTween(0.2f + 3f) { + @Override + protected void onFinish() { + gameStart(); + countdownView.post(new Runnable() { + @Override + public void run() { + countdownView.setVisibility(View.INVISIBLE); + } + }); + } + }); + player.setLane(INITIAL_LANE); + setState(State.READY); + } + + private void gameStart() { + Log.i(TAG, "Game Start."); + beginGame(); + setState(State.RUNNING); + } + + private void gameSuccess() { + Log.i(TAG, "You're winner!"); + // Make the watermelon match the player's speed so the player won't get squished. + + hideButtons(); + + int runnersBehindPlayer = 0; + for (RunnerActor opponent : opponents) { + if (player.position.y >= opponent.position.y) { + runnersBehindPlayer++; + } + } + finishingPlace = 4 - runnersBehindPlayer; + + if (finishingPlace == 1) { + // If the player gets first place, stop the watermelon and decelerate the player. + + // Play the strawberry's celebration animation. + player.setCelebrate(true); + final float currentSpeed = player.velocity.y; + final float targetSpeed = BASE_SPEED * 0.75f; + + tweenManager.add(new Tween(RUNNER_FINISH_DURATION) { + @Override + protected void updateValues(float percentDone) { + float diffSpeed = targetSpeed - currentSpeed; + player.velocity.y = currentSpeed + (diffSpeed * percentDone); + } + }); + + tweenManager.add(new Tween(WATERMELON_FINISH_DURATION) { + @Override + protected void updateValues(float percentDone) { + watermelon.velocity.y = currentSpeed * (1 - percentDone); + } + }); + } else { + // If the player does not get first place, stop both the watermelon and the player. + + // If the player finishes fourth, make the strawberry cry. + if (finishingPlace == 4) { + player.setSweat(true); + } + + final float currentSpeed = player.velocity.y; + + tweenManager.add(new Tween(WATERMELON_FINISH_DURATION * 0.5f) { + @Override + protected void updateValues(float percentDone) { + watermelon.velocity.y = currentSpeed * (1 - percentDone); + } + }); + + tweenManager.add(new Tween(RUNNER_FINISH_DURATION) { + @Override + protected void updateValues(float percentDone) { + if (player.getRunnerState() == RunnerState.RUNNING) { + player.velocity.y = currentSpeed * (1 - percentDone); + if (percentDone > 0.95f) { + player.setRunnerState(RunnerState.STANDING); + player.velocity.y = 0; + } + } + } + }); + } + + eventBus.sendEvent(EventBus.PLAY_SOUND, R.raw.bmx_cheering); + eventBus.sendEvent(EventBus.PAUSE_SOUND, R.raw.running_foot_loop_fast); + + setState(State.SUCCESS); + } + + private void gameFail() { + // Change the player's appearance. + player.setRunnerState(RunnerState.DYING); + + // Stops the player. + player.velocity.y = 0; + + hideButtons(); + + // Zoom the camera on the player. + zoomCameraTo(-HALF_WIDTH, player.position.y - HEIGHT * 0.75f, camera.scale, 1.5f); + + eventBus.sendEvent(EventBus.PLAY_SOUND, R.raw.bmx_cheering); + eventBus.sendEvent(EventBus.PAUSE_SOUND, R.raw.running_foot_loop_fast); + + vibrator.vibrate(VIBRATION_MS); + + setState(State.FAIL); + } + + private void showButtons() { + tweenManager.add(new ActorTween(leftButton).withAlpha(1).withDuration(0.5f)); + tweenManager.add(new ActorTween(rightButton).withAlpha(1).withDuration(0.5f)); + } + + private void hideButtons() { + tweenManager.add(new ActorTween(leftButton).withAlpha(0).withDuration(0.5f)); + tweenManager.add(new ActorTween(rightButton).withAlpha(0).withDuration(0.5f)); + } + + private void startCountdownAnimation() { + countdownView.post(new Runnable() { + @Override + public void run() { + countdownView.setVisibility(View.VISIBLE); + } + }); + final NumberFormat numberFormatter = NumberFormat.getInstance(locale); + countdownBump(numberFormatter.format(3)); + tweenManager.add(new EmptyTween(1) { + @Override + protected void onFinish() { + countdownBump(numberFormatter.format(2)); + } + }); + tweenManager.add(new EmptyTween(2) { + @Override + protected void onFinish() { + countdownBump(numberFormatter.format(1)); + } + }); + } + + private void countdownBump(final String text) { + countdownView.post(new Runnable() { + @Override + public void run() { + float countdownStartScale = countdownView.getScaleX() * 1.25f; + float countdownEndScale = countdownView.getScaleX(); + + countdownView.setVisibility(View.VISIBLE); + countdownView.setText(text); + + if (!"Nexus 9".equals(Build.MODEL)) { + ValueAnimator scaleAnimation = UIUtil.animator(200, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float scaleValue = (float) valueAnimator.getAnimatedValue("scale"); + countdownView.setScaleX(scaleValue); + countdownView.setScaleY(scaleValue); + } + }, + UIUtil.floatValue("scale", countdownStartScale, countdownEndScale) + ); + scaleAnimation.start(); + } + } + }); + } + + // Make a row of power ups using the current row from PursuitLevel. + private void addPowerUpRow() { + char[] row = map.getRowArray(mapRow); + float rowPositionY = player.position.y + HEIGHT; + for (int i = 0; i < row.length; i++) { + if (row[i] == '1') { + if (ribbon.position.y > rowPositionY) { + addPowerUp(getLanePositionX(i), rowPositionY); + } + } + } + } + + private PowerUpActor addPowerUp(float x, float y) { + PowerUpActor powerUp = + new PowerUpActor(x, y, resources); + powerUp.scale = baseScale; + synchronized (actors) { + actors.add(powerUp); + } + powerUps.add(powerUp); + return powerUp; + } + + // Creates and adds a OpponentActor to the list of all actors. + private OpponentActor addOpponent(RunnerType type, int lane, float y, float radius) { + OpponentActor opponent = makeOpponent(type, lane, y, radius); + synchronized (actors) { + actors.add(opponent); + } + opponents.add(opponent); + return opponent; + } + + // Creates a OpponentActor. + private OpponentActor makeOpponent(RunnerType type, int lane, float y, float radius) { + OpponentActor opponent = new OpponentActor(resources, type, lane); + opponent.position.x = getLanePositionX(lane); + opponent.position.y = y; + opponent.scale = baseScale; + opponent.setRadius(radius); + return opponent; + } + + // Wait for one second for the title to display and then starts the game. + private void showTitle() { + setState(State.TITLE); + tweenManager.add(new EmptyTween(titleDurationMs / 1000.0f) { + @Override + protected void onFinish() { + if (state == State.TITLE) { + gameSetup(); + } + } + }); + } + + // Handles all incoming motion events. Currently just calls down() and up(). + public void touch(MotionEvent event) { + final int action = event.getActionMasked(); + + int index = event.getActionIndex(); + Point screenSize = AndroidUtils.getScreenSize(); + float touchX = (event.getX(index) / screenSize.x) * PursuitModel.WIDTH; + float touchY = (event.getY(index) / screenSize.y) * PursuitModel.HEIGHT; + + Vector2D worldPos = camera.getWorldCoords(touchX, touchY); + + if (action == MotionEvent.ACTION_DOWN + || action == MotionEvent.ACTION_POINTER_DOWN) { + down(worldPos.x, worldPos.y); + } + } + + // Called every time the user touches down on the screen. + // Currently does not support multi-touch. + private void down(float touchX, float touchY) { + Log.i(TAG, "Touch down at: " + touchX + ", " + touchY); + + if (state == State.RUNNING || state == State.READY) { + int newLane = getLaneNumberFromPositionX(touchX); + if (newLane > player.getLane() && player.getLane() < MAX_LANE) { + rightButton.press(); + movePlayer(player.getLane() + 1); + } else if (newLane < player.getLane() && player.getLane() > MIN_LANE) { + leftButton.press(); + movePlayer(player.getLane() - 1); + } + } + } + + private void movePlayer(final int newLane) { + // The player cannot move if it is already moving. + if (laneSwitchTimer > 0) { + return; + } + + // If an opponent and the player are expected to collide after the lane change, the player does + // not move. + // If the player is slightly in front of an opponent after the lane change, the player moves and + // the opponent moves back slightly. + for (RunnerActor opponent : opponents) { + if (opponent.getLane() == newLane) { + float targetOpponentY = opponent.position.y + opponent.velocity.y * LANE_SWITCH_DURATION; + float targetPlayerY = + player.position.y + (player.velocity.y * LANE_SWITCH_DURATION * 0.8f); + float yDistance = targetOpponentY - targetPlayerY; + float combinedRadius = opponent.getRadius() + player.getRadius(); + + if (0.2f * combinedRadius < yDistance && yDistance < combinedRadius) { + Log.i(TAG, "Cannot switch to lane " + newLane); + eventBus.sendEvent(EventBus.PLAY_SOUND, R.raw.present_throw_block); + bumpPlayer(opponent); + return; + } else if (-1.2f * combinedRadius < yDistance && yDistance <= 0.2f * combinedRadius) { + Log.i(TAG, "Switching to lane " + newLane + " with slowdown"); + slowDownOpponent(opponent); + } + } + } + + // Make the tween + if (state == State.RUNNING) { + tweenManager.add(new ActorTween(player) + .toX(getLanePositionX(newLane)) + .withDuration(LANE_SWITCH_DURATION) + .withInterpolator(Interpolator.LINEAR)); + laneSwitchTimer = LANE_SWITCH_DURATION; + } else { + // If the player is not currently running. Play the running left and right animation when + // switching lanes. + if (player.lane > newLane) { + player.setRunnerState(RunnerState.RUNNING_LEFT); + } else { + player.setRunnerState(RunnerState.RUNNING_RIGHT); + } + tweenManager.add(new ActorTween(player) + .toX(getLanePositionX(newLane)) + .withDuration(LANE_SWITCH_DURATION * 2f) + .withInterpolator(Interpolator.LINEAR) + .whenFinished(new Callback() { + @Override + public void call() { + if (player.getRunnerState() == RunnerState.RUNNING_LEFT + || player.getRunnerState() == RunnerState.RUNNING_RIGHT) { + player.setRunnerState(RunnerState.CROUCH); + } else if (player.getRunnerState() == RunnerState.CROUCH) { + player.setRunnerState(RunnerState.RUNNING); + } + } + })); + laneSwitchTimer = LANE_SWITCH_DURATION * 2f; + } + + player.setLane(newLane); + eventBus.sendEvent(EventBus.PLAY_SOUND, R.raw.jumping_jump); + } + + // Temporarily reduces the speed of an opponent so the player can go in front of it when changing + // lanes. + private void slowDownOpponent(final RunnerActor opponent) { + + final float initialSpeed = opponent.velocity.y; + float targetOpponentY = opponent.position.y + opponent.velocity.y * LANE_SWITCH_DURATION; + float targetPlayerY = + player.position.y + (player.velocity.y * LANE_SWITCH_DURATION * 0.8f); + float diffY = targetOpponentY - targetPlayerY; + float combinedRadius = opponent.getRadius() + player.getRadius(); + + // The further the opponent is head of the opponent, the greater the decrease in speed. + final float slowDownAmount = + OPPONENT_SLOW_DOWN_AMOUNT + + (OPPONENT_SLOW_DOWN_AMOUNT * Math.max(-0.2f, (diffY / combinedRadius))); + + tweenManager.add(new Tween(OPPONENT_SLOW_DOWN_DURATION) { + @Override + protected void updateValues(float percentDone) { + if (opponent.getRunnerState() == RunnerState.RUNNING) { + float percentageSlowdown = 1 - percentDone; + float speed = + initialSpeed - (slowDownAmount * percentageSlowdown); + opponent.velocity.y = speed; + } else { + opponent.velocity.y = 0; + } + } + }); + } + + private void bumpPlayer(RunnerActor opponent) { + float targetX = player.position.x + (opponent.position.x - player.position.x) * 0.25f; + float endX = player.position.x; + + final ActorTween outTween = new ActorTween(player) + .toX(endX) + .withDuration(LANE_SWITCH_DURATION * 0.5f) + .withInterpolator(Interpolator.EASE_IN_AND_OUT); + + final ActorTween inTween = new ActorTween(player) + .toX(targetX) + .withDuration(LANE_SWITCH_DURATION * 0.5f) + .withInterpolator(Interpolator.EASE_IN_AND_OUT) + .whenFinished(new Callback() { + @Override + public void call() { + tweenManager.add(outTween); + } + }); + laneSwitchTimer = LANE_SWITCH_DURATION; + tweenManager.add(inTween); + } + + private ActorTween runnerEnter(final RunnerActor runner) { + // Enter from the left. + runner.setRunnerState(RunnerState.ENTERING); + eventBus.sendEvent(EventBus.PLAY_SOUND, R.raw.present_throw_character_appear); + + // Stop and stand for 0.5 seconds. + final Tween standingDelay = new EmptyTween(RUNNER_STANDING_DURATION) { + @Override + protected void onFinish() { + runner.setRunnerState(RunnerState.CROUCH); + } + }; + + ActorTween tween = new ActorTween(runner) + .withDuration(RUNNER_ENTER_DURATION) + .withInterpolator(Interpolator.LINEAR) + .whenFinished(new Callback() { + @Override + public void call() { + // Crouch down after standing still. + runner.setRunnerState(RunnerState.STANDING); + eventBus.sendEvent(EventBus.PAUSE_SOUND, R.raw.present_throw_character_appear); + tweenManager.add(standingDelay); + } + }); + + tweenManager.add(tween); + return tween; + } + + // Returns the world x of a lane. + private int getLanePositionX(int lane) { + return LANE_SIZE * (lane - INITIAL_LANE); + } + + // Return the lane number corresponding to an area of the screen. + // Warning: This function may return lane numbers that don't exist. Example: By clicking on the + // area that is immediately left of lane 0, -1 is returned. + private int getLaneNumberFromPositionX(float x) { + int lane = INITIAL_LANE + Math.round(x / LANE_SIZE); + Log.i(TAG, "Lane: " + lane); + return lane; + } + + // Called when the player picks up a power up. + private void powerUpPlayer(PowerUpActor powerUpActor) { + powerUpActor.pickUp(); + player.velocity.y += POWER_UP_SPEED_BOOST; + eventBus.sendEvent(EventBus.PLAY_SOUND, R.raw.running_foot_power_up_fast); + } + + public void setState(State newState) { + Log.i(TAG, "State changed to " + newState); + state = newState; + if (stateListener != null) { + stateListener.onStateChanged(newState); + } + } + + private void zoomCameraTo(float x, float y, float scale, float secondsDuration) { + final float x1 = camera.position.x; + final float y1 = camera.position.y; + final float camScale1 = camera.scale; + // Limit (x, y) so that the edge of the camera doesn't go past the normal edges (i.e. the edges + // at scale==1). + final float x2 = x; + final float y2 = y; + final float camScale2 = scale; + + tweenManager.add(new Tween(secondsDuration) { + @Override + protected void updateValues(float percentDone) { + Interpolator interp = Interpolator.EASE_IN_AND_OUT; + + camera.position.x = interp.getValue(percentDone, x1, x2); + camera.position.y = interp.getValue(percentDone, y1, y2); + + // Tween the height, then use that to calculate scale, because tweening scale + // directly leads to a wobbly pan (scale isn't linear). + float height1 = HEIGHT / camScale1; + float height2 = HEIGHT / camScale2; + camera.scale = HEIGHT / interp.getValue(percentDone, height1, height2); + } + }); + } + + public void setStateListener(StateChangedListener stateListener) { + this.stateListener = stateListener; + } + + public void setScoreListener(ScoreListener listener) { + this.scoreListener = listener; + updateScore(); + } + + public void setCountdownView(TextView countdownView) { + this.countdownView = countdownView; + } + + public float getScore() { + return time; // Milliseconds + } + + public int getFinishingPlace() { + return finishingPlace; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitView.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitView.java new file mode 100644 index 000000000..d9bd15acf --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/PursuitView.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.pursuit; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.view.View; +import com.google.android.apps.santatracker.doodles.shared.Actor; + +/** + * Handles rendering for the second version of the running game. + */ +public class PursuitView extends View { + private static final String TAG = PursuitView.class.getSimpleName(); + + private PursuitModel model; + private float currentScale; + private float currentOffsetX = 0; // In game units + private float currentOffsetY = 0; + + public PursuitView(Context context) { + this(context, null); + } + + public PursuitView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public PursuitView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public void setModel(PursuitModel model) { + this.model = model; + } + + @Override + protected void onDraw(Canvas canvas) { + if (model == null) { + return; + } + synchronized (model) { + super.onDraw(canvas); + canvas.save(); + + // Fit-to-screen & center. + currentScale = Math.min(canvas.getWidth() / (float) PursuitModel.WIDTH, + canvas.getHeight() / (float) PursuitModel.HEIGHT); + + currentOffsetX = (canvas.getWidth() / currentScale - PursuitModel.WIDTH) / 2; + currentOffsetY = (canvas.getHeight() / currentScale - PursuitModel.HEIGHT) / 2; + + canvas.scale(currentScale * model.camera.scale, currentScale * model.camera.scale); + canvas.translate(currentOffsetX - model.cameraShake.position.x - model.camera.position.x, + currentOffsetY - model.cameraShake.position.y - model.camera.position.y); + + // Draws the beach and the sidewalk. + model.backgroundActor.draw(canvas); + + // Draws the actors + synchronized (model.actors) { + for (int i = 0; i < model.actors.size(); i++) { + Actor actor = model.actors.get(i); + if (!actor.hidden) { + actor.draw(canvas); + } + } + } + + // Draws tree, umbrellas and their shadows. + model.backgroundActor.drawTop(canvas); + + canvas.restore(); + canvas.save(); + + canvas.scale(currentScale * model.camera.scale, currentScale * model.camera.scale); + canvas.translate(currentOffsetX, currentOffsetY); + + // Draws the UI + for (int i = 0; i < model.ui.size(); i++) { + Actor actor = model.ui.get(i); + if (!actor.hidden) { + actor.draw(canvas); + } + } + + canvas.restore(); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/RibbonActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/RibbonActor.java new file mode 100644 index 000000000..5064afa4d --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/RibbonActor.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.pursuit; + +import android.content.res.Resources; +import android.graphics.Canvas; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.Sprites; + +/** + * The breakable ribbon that acts as the finish line for the running game. + */ +public class RibbonActor extends Actor { + + private static final int Z_INDEX = 0; + + // Assets. + private AnimatedSprite sprite; + + public RibbonActor(float x, float y, Resources resources) { + zIndex = Z_INDEX; + + position.x = x; + position.y = y; + + sprite = AnimatedSprite.fromFrames(resources, Sprites.running_finish_line); + + sprite.setAnchor(sprite.frameWidth / 2, + sprite.frameHeight / 2); + + sprite.setPaused(true); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + sprite.setPosition(position.x, position.y); + sprite.setScale(scale, scale); + sprite.draw(canvas); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/RunnerActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/RunnerActor.java new file mode 100644 index 000000000..d1ad74b53 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/RunnerActor.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.pursuit; + +import android.content.res.Resources; +import android.graphics.Canvas; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite.AnimatedSpriteListener; +import com.google.android.apps.santatracker.doodles.shared.Sprites; + +/** + * A fruit that runs down the screen. + */ +public class RunnerActor extends Actor { + /** + * Currently there are four different kinds of fruits. + */ + + public enum RunnerType { + STRAWBERRY(Sprites.snowballrun_running_normal, R.drawable.snowballrun_running_starting_runner, + Sprites.snowballrun_running_sidestep, Sprites.snowballrun_running_appearing, R.drawable.snowballrun_standing_elf, + Sprites.snowballrun_elf_squish, R.drawable.snowballrun_elf_squished_05), + + APRICOT(Sprites.snowballrun_running_snowman_opponent, R.drawable.snowballrun_running_starting_snowman, + Sprites.empty_frame, Sprites.empty_frame, R.drawable.snowballrun_standing_snowman, + Sprites.running_apricot_squish, R.drawable.snowballrun_snowman_squished_09), + + GRAPE(Sprites.snowballrun_running_elf_opponent, R.drawable.snowballrun_running_starting_elfopponent, + Sprites.empty_frame, Sprites.empty_frame, R.drawable.snowballrun_standing_elfopponent, + Sprites.running_elfopponent_squish, R.drawable.snowballrun_elfopponent_squished_09), + + MANGO(Sprites.snowballrun_running_reindeer_opponent, R.drawable.snowballrun_running_starting_reindeer, + Sprites.empty_frame, Sprites.empty_frame, R.drawable.snowballrun_standing_reindeer, + Sprites.snowballrun_reindeer_squish, R.drawable.snowballrun_reindeer_squished_05); + + public int[] runRes, crouchRes, runLeftRes, enteringRes, standRes, dyingRes, deadRes; + + RunnerType(int[] runRes, int crouchRes, + int[] runLeftRes, int[] enteringRes, int standRes, + int[] dyingRes, int deadRes) { + + this.runRes = runRes; + this.crouchRes = new int[] { crouchRes }; + this.runLeftRes = runLeftRes; + this.enteringRes = enteringRes; + this.standRes = new int[] { standRes }; + this.dyingRes = dyingRes; + this.deadRes = new int[] { deadRes }; + } + } + + // TODO: Because the running left animation is no longer used for the opponents' + // entrance, consider moving RUNNING_LEFT and RUNNING_RIGHT to PlayerActor. + enum RunnerState { + RUNNING, + CROUCH, + ENTERING, + RUNNING_LEFT, + RUNNING_RIGHT, + STANDING, + DYING, + DEAD, + } + + private static final long EYE_BLINK_DELAY_MILLISECONDS = 1300; + private static final int RUNNING_Z_INDEX = 10; + private static final int DEAD_Z_INDEX = 3; + + protected int lane; + + protected RunnerType type; + + protected RunnerState state; + + protected float radius; + + protected AnimatedSprite currentSprite; + + protected AnimatedSprite runningSprite; + protected AnimatedSprite crouchSprite; + protected AnimatedSprite enteringSprite; + protected AnimatedSprite runningLeftSprite; + protected AnimatedSprite runningRightSprite; + protected AnimatedSprite standingSprite; + protected AnimatedSprite deadSprite; + protected AnimatedSprite dyingSprite; + + RunnerActor(Resources resources, RunnerType type, int lane) { + this.lane = lane; + this.type = type; + + runningSprite = AnimatedSprite.fromFrames(resources, type.runRes); + crouchSprite = AnimatedSprite.fromFrames(resources, type.crouchRes); + enteringSprite = AnimatedSprite.fromFrames(resources, type.enteringRes); + runningLeftSprite = AnimatedSprite.fromFrames(resources, type.runLeftRes); + runningRightSprite = AnimatedSprite.fromFrames(resources, type.runLeftRes); + standingSprite = AnimatedSprite.fromFrames(resources, type.standRes); + deadSprite = AnimatedSprite.fromFrames(resources, type.deadRes); + dyingSprite = AnimatedSprite.fromFrames(resources, type.dyingRes); + + enteringSprite.setLoop(false); + enteringSprite.setFPS((int) ((enteringSprite.getNumFrames() + 1) / PursuitModel.RUNNER_ENTER_DURATION)); + + setSpriteAnchorUpright(runningSprite); + setSpriteAnchorWithYOffset(crouchSprite, 0); + setSpriteAnchorUpright(enteringSprite); + setSpriteAnchorUpright(runningLeftSprite); + setSpriteAnchorUpright(runningRightSprite); + setSpriteAnchorUpright(standingSprite); + setSpriteAnchorCenter(deadSprite); + switch (type) { + case STRAWBERRY: + setSpriteAnchorWithYOffset(dyingSprite, 0); + break; + case MANGO: + setSpriteAnchorWithYOffset(dyingSprite, 0); + break; + case GRAPE: + setSpriteAnchorWithYOffset(dyingSprite, 0); + break; + case APRICOT: + setSpriteAnchorWithYOffset(dyingSprite, 0); + break; + } + + currentSprite = runningSprite; + state = RunnerState.RUNNING; + zIndex = RUNNING_Z_INDEX; + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + + if (state == RunnerState.RUNNING) { + currentSprite.setFPS(3 + (int) (5 * velocity.y / PursuitModel.BASE_SPEED)); + } + + currentSprite.update(deltaMs); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + if (currentSprite == null) { + return; + } + + float runnerScale = scale * 1.50f; + currentSprite.setScale(runnerScale, runnerScale); + currentSprite.setPosition(position.x, position.y); + + if (currentSprite == runningRightSprite) { + currentSprite.setScale(-runnerScale, runnerScale); + } + + currentSprite.draw(canvas); + } + + public void setLane(int lane) { + this.lane = lane; + } + + public int getLane() { + return lane; + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public float getRadius() { + return radius; + } + + public void setRunnerState(RunnerState state) { + if (this.state == state) { + return; + } + + this.state = state; + + switch (state) { + case RUNNING: + currentSprite = runningSprite; + break; + case CROUCH: + currentSprite = crouchSprite; + break; + case ENTERING: + currentSprite = enteringSprite; + break; + case RUNNING_LEFT: + currentSprite = runningLeftSprite; + break; + case RUNNING_RIGHT: + currentSprite = runningRightSprite; + break; + case STANDING: + currentSprite = standingSprite; + break; + case DYING: + currentSprite = dyingSprite; + dyingSprite.setLoop(false); + dyingSprite.setFrameIndex(0); + dyingSprite.clearListeners(); + + int frame = 3; + switch(type) { + case APRICOT: + frame = 2; + break; + case GRAPE: + frame = 2; + break; + } + final int finalFrame = frame; + + dyingSprite.addListener(new AnimatedSpriteListener() { + @Override + public void onFrame(int index) { + super.onFrame(index); + if (index == finalFrame) { + setRunnerState(RunnerState.DEAD); + } + } + }); + break; + case DEAD: + currentSprite = deadSprite; + break; + } + + if (state == RunnerState.DEAD) { + zIndex = DEAD_Z_INDEX; + } else { + zIndex = RUNNING_Z_INDEX; + } + } + + public RunnerState getRunnerState() { + return state; + } + + // yOffset is in percentage not game units, or pixels + // yOffset of 0.5f centers the sprite vertically + // yOffset of 0 draws the sprite starting from its y position + + protected static void setSpriteAnchorCenter(AnimatedSprite sprite) { + setSpriteAnchorWithYOffset(sprite, sprite.frameHeight * 0.5f); + } + + protected static void setSpriteAnchorUpright(AnimatedSprite sprite) { + setSpriteAnchorWithYOffset(sprite, 0); + } + + protected static void setSpriteAnchorWithYOffset(AnimatedSprite sprite, float yOffset) { + sprite.setAnchor(sprite.frameWidth * 0.5f, sprite.frameHeight - yOffset); + } + +} + diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/WatermelonActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/WatermelonActor.java new file mode 100644 index 000000000..17e6ffa78 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/pursuit/WatermelonActor.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.pursuit; + +import android.content.res.Resources; +import com.google.android.apps.santatracker.doodles.shared.WatermelonBaseActor; + +/** + * The watermelon that's always behind the player and the other running fruits. + * If the player or the running fruits gets too close to the watermelon, they get squished. + */ +public class WatermelonActor extends WatermelonBaseActor { + + public static final float VERTICAL_RADIUS_WORLD = 90f; + public static final float HORIZONTAL_RADIUS_WORLD = 60f; + + private static final int Z_INDEX = 5; + + public WatermelonActor(Resources resources) { + super(resources); + zIndex = Z_INDEX; + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + + int fps = (int) (10 * velocity.y / PursuitModel.BASE_SPEED); + bodySprite.setFPS(fps); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Actor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Actor.java new file mode 100644 index 000000000..99946c919 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Actor.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.graphics.Canvas; + +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Base class for different characters on the screen. + */ +public class Actor implements Comparable { + public static final float INFINITE_MASS = 0.0f; + public static final String TYPE = "Actor"; + public static final String TYPE_KEY = "type"; + public static final String X_KEY = "x"; + public static final String Y_KEY = "y"; + + public Vector2D positionBeforeFrame; + // Assumes (0, 0) is upper-left corner of screen, with +y down and +x right. + public Vector2D position; + public Vector2D velocity; + + // Doesn't do anything yet (except for TextActors) + public float scale = 1.0f; + + // The rotation of the actor in radians. Positive means clockwise, negative means anticlockwise. + public float rotation = 0.0f; + + // Doesn't do anything yet (except for in tennis) + public boolean hidden = false; + + // Specify z-index so that actors can be sorted before drawing. Higher is in front, lower in back. + public int zIndex = 0; + + // 0: transparent, 1: opaque. + public float alpha = 1; + + // Bounciness. + public float restitution = 1.0f; + public float inverseMass = INFINITE_MASS; + + public Actor() { + this(Vector2D.get(0, 0), Vector2D.get(0, 0)); + } + + public Actor(Vector2D position, Vector2D velocity) { + this.position = position; + this.positionBeforeFrame = Vector2D.get(position); + this.velocity = velocity; + } + + public void update(float deltaMs) { + positionBeforeFrame.set(this.position); + float deltaSeconds = deltaMs / 1000.0f; + this.position.x += velocity.x * deltaSeconds; + this.position.y += velocity.y * deltaSeconds; + } + + public void draw(Canvas canvas) { + // Nothing to do for base class implementation. + } + + @Override + public int compareTo(Actor another) { + int zDiff = zIndex - another.zIndex; + if (zDiff != 0) { + return zDiff; + } else { + // As a fallback, compare the y positions. Obstacles with smaller y values (i.e., higher on + // the screen) should come first. + float positionDiff = position.y - another.position.y; + if (positionDiff > 0) { + return 1; + } else if (positionDiff < 0) { + return -1; + } else { + return 0; + } + } + } + + public JSONObject toJSON() throws JSONException { + return null; + } + + public String getType() { + return TYPE; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ActorHelper.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ActorHelper.java new file mode 100644 index 000000000..cb6039a32 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ActorHelper.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * A collection of helper functions for Actor. + */ +public class ActorHelper { + public static float distanceBetween(Actor a, Actor b) { + return distanceBetween(a.position.x, a.position.y, b.position.x, b.position.y); + } + + public static float distanceBetween(float x1, float y1, float x2, float y2) { + float dx = x1 - x2; + float dy = y1 - y2; + return (float) Math.sqrt(dx * dx + dy * dy); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ActorTween.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ActorTween.java new file mode 100644 index 000000000..707ab27d1 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ActorTween.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * Tweens properties of Actors (currently, position & scale). + * + *

If any of the from-values is left unset, the from value will be initialized on the first + * update of the tween. This allows us to tween from an unspecified value, and have it do so + * smoothly when the tween actually runs, regardless of the actual starting value.

+ */ +public class ActorTween extends Tween { + private static final String TAG = ActorTween.class.getSimpleName(); + + private final Actor actor; + private Interpolator interpolator; + // Use Float objects set to null so that we can detect & support unspecified values. + private Float xStart = null; + private Float yStart = null; + private Float xEnd = null; + private Float yEnd = null; + private Float scaleStart; + private Float scaleEnd; + private Callback finishedCallback = null; + private Float rotationStart; + private Float rotationEnd; + private Float alphaStart; + private Float alphaEnd; + + private boolean firstUpdate = true; + + public ActorTween(Actor actor) { + super(0); + this.actor = actor; + interpolator = Interpolator.LINEAR; + } + + public ActorTween from(float x, float y) { + fromX(x); + fromY(y); + return this; + } + + public ActorTween fromX(float x) { + xStart = x; + return this; + } + + public ActorTween fromY(float y) { + yStart = y; + return this; + } + + public ActorTween to(float x, float y) { + toX(x); + toY(y); + return this; + } + + public ActorTween toX(float x) { + xEnd = x; + return this; + } + + public ActorTween toY(float y) { + yEnd = y; + return this; + } + + public ActorTween scale(float fromScale, float toScale) { + this.scaleStart = fromScale; + this.scaleEnd = toScale; + return this; + } + + public ActorTween scale(float toScale) { + this.scaleEnd = toScale; + return this; + } + + public ActorTween withRotation(float fromRadians, float toRadians) { + this.rotationStart = fromRadians; + this.rotationEnd = toRadians; + return this; + } + + public ActorTween withRotation(float toRadians) { + this.rotationEnd = toRadians; + return this; + } + + public ActorTween withAlpha(float fromAlpha, float toAlpha) { + this.alphaStart = fromAlpha; + this.alphaEnd = toAlpha; + return this; + } + + public ActorTween withAlpha(float toAlpha) { + this.alphaEnd = toAlpha; + return this; + } + + public ActorTween withDuration(float seconds) { + this.durationSeconds = seconds; + return this; + } + + public ActorTween withInterpolator(Interpolator interpolator) { + this.interpolator = interpolator; + return this; + } + + public ActorTween whenFinished(Callback c) { + finishedCallback = c; + return this; + } + + protected void setInitialValues() { + xStart = (xStart != null) ? xStart : actor.position.x; + yStart = (yStart != null) ? yStart : actor.position.y; + scaleStart = (scaleStart != null) ? scaleStart : actor.scale; + rotationStart = (rotationStart != null) ? rotationStart : actor.rotation; + alphaStart = (alphaStart != null) ? alphaStart : actor.alpha; + } + + @Override + protected void updateValues(float percentDone) { + if (firstUpdate) { + firstUpdate = false; + setInitialValues(); + } + // Perform null checks here so that we don't interpolate over unspecified fields. + if (xEnd != null) { + actor.position.x = interpolator.getValue(percentDone, xStart, xEnd); + } + if (yEnd != null) { + actor.position.y = interpolator.getValue(percentDone, yStart, yEnd); + } + if (scaleEnd != null) { + actor.scale = interpolator.getValue(percentDone, scaleStart, scaleEnd); + } + if (rotationEnd != null) { + actor.rotation = interpolator.getValue(percentDone, rotationStart, rotationEnd); + } + if (alphaEnd != null) { + actor.alpha = interpolator.getValue(percentDone, alphaStart, alphaEnd); + } + } + + @Override + protected void onFinish() { + if (finishedCallback != null) { + finishedCallback.call(); + } + } + + /** + * Callback to be called at the end of a tween (can be used to chain tweens together, to hide + * an actor when a tween finishes, etc.) + */ + public interface Callback { + void call(); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/AndroidUtils.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/AndroidUtils.java new file mode 100644 index 000000000..1a8faf7b0 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/AndroidUtils.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.app.Activity; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.res.Resources; +import android.graphics.Point; +import android.os.Environment; +import android.text.Html; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; +import android.view.WindowManager; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Utility functions to make it easier to interact with Android APIs. + */ +public final class AndroidUtils { + private static final String TAG = AndroidUtils.class.getSimpleName(); + + private AndroidUtils() { + // Don't instantiate this class. + } + + public static Activity getActivityFromContext(Context context) { + while (context instanceof ContextWrapper) { + if (context instanceof Activity) { + return (Activity) context; + } + context = ((ContextWrapper) context).getBaseContext(); + } + return null; + } + + public static void allowScreenToTurnOff(Context context) { + getActivityFromContext(context).getWindow().clearFlags( + WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + + public static void forceScreenToStayOn(Context context) { + getActivityFromContext(context).getWindow().addFlags( + WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + + public static Point getScreenSize() { + DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics(); + return new Point(displayMetrics.widthPixels, displayMetrics.heightPixels); + } + + public static float dipToPixels(float dipValue) { + DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics); + } + + public static float pixelsToDips(float pixelValue) { + DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); + float dip = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, metrics); + return pixelValue / dip; + } + + public static boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + return Environment.MEDIA_MOUNTED.equals(state); + } + + public static boolean isExternalStorageReadable() { + String state = Environment.getExternalStorageState(); + return Environment.MEDIA_MOUNTED.equals(state) + || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state); + } + + /** + * Handles loading text from our resources, including interpreting and tags. + */ + public static CharSequence getText(Resources res, int id, Object... formatArgs) { + try { + return Html.fromHtml(res.getString(id, formatArgs)); + } catch (java.util.MissingFormatArgumentException e) { + Log.e(TAG, "unable to format string id: " + id, e); + } + return ""; + } + + /** + * Re-orients a coordinate system based on default device rotation. + * Implementation based on: http://goo.gl/kRajPd + * + * @param displayRotation Display rotation, from Display.getRotation() + * @param eventValues Event values gathered from the raw sensor event. + * @return The adjusted event values, with display rotation taken into account. + */ + public static float[] getAdjustedAccelerometerValues(int displayRotation, float[] eventValues) { + float[] adjustedValues = new float[3]; + final int axisSwap[][] = { + { 1, -1, 0, 1}, // ROTATION_0 + {-1, -1, 1, 0}, // ROTATION_90 + {-1, 1, 0, 1}, // ROTATION_180 + { 1, 1, 1, 0} // ROTATION_270 + }; + + final int[] axisFactors = axisSwap[displayRotation]; + adjustedValues[0] = ((float) axisFactors[0]) * eventValues[axisFactors[2]]; + adjustedValues[1] = ((float) axisFactors[1]) * eventValues[axisFactors[3]]; + adjustedValues[2] = eventValues[2]; + + return adjustedValues; + } + + /** + * Reads all bytes from an input stream into a byte array. + * Does not close the stream. + * + * @param in the input stream to read from + * @return a byte array containing all the bytes from the stream + * @throws IOException if an I/O error occurs + */ + public static byte[] toByteArray(InputStream in) throws IOException { + // Presize the ByteArrayOutputStream since we know how large it will need + // to be, unless that value is less than the default ByteArrayOutputStream + // size (32). + ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(32, in.available())); + copy(in, out); + return out.toByteArray(); + } + + /** + * Copies all bytes from the input stream to the output stream. + * Does not close or flush either stream. + * + * @param from the input stream to read from + * @param to the output stream to write to + * @return the number of bytes copied + * @throws IOException if an I/O error occurs + */ + private static long copy(InputStream from, OutputStream to) + throws IOException { + byte[] buf = new byte[8192]; + long total = 0; + while (true) { + int r = from.read(buf); + if (r == -1) { + break; + } + to.write(buf, 0, r); + total += r; + } + return total; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/AnimatedSprite.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/AnimatedSprite.java new file mode 100644 index 000000000..c916fccf4 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/AnimatedSprite.java @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.util.Log; +import android.util.Pair; +import com.google.android.apps.santatracker.doodles.shared.physics.Util; +import java.util.ArrayList; +import java.util.List; + +/** + * An animated image. This also handles static, non-animated images: those are just animations with + * only 1 frame. + */ +public class AnimatedSprite { + private static final String TAG = AnimatedSprite.class.getSimpleName(); + private static final int DEFAULT_FPS = 24; + private static final int NUM_TRIES_TO_LOAD_FROM_MEMORY = 3; + + // When loading any sprite, this was the last successful sampleSize. We start loading the next + // Sprite with this sampleSize. + public static int lastUsedSampleSize = 1; + + private static BitmapCache bitmapCache; + + private Bitmap[] frames; + public int frameWidth; + public int frameHeight; + private int fps = DEFAULT_FPS; + private int numFrames; + private boolean loop = true; + private boolean paused = false; + private boolean flippedX = false; + private List listeners; + private Vector2D position = Vector2D.get(); + public Vector2D anchor = Vector2D.get(); + private boolean hidden; + private float scaleX = 1; + private float scaleY = 1; + private float rotation; + private Paint paint; + private int sampleSize = 1; + + private float frameIndex; + + // These are fields in order to avoid allocating memory in draw(). Not threadsafe, but why would + // draw get called from multiple threads? + private Rect srcRect = new Rect(); + private RectF dstRect = new RectF(); + + /** + * Use fromFrames() to construct an AnimatedSprite. + */ + private AnimatedSprite(Bitmap[] frames, int sampleSize) { + this.frames = frames; + this.sampleSize = sampleSize; + if (lastUsedSampleSize < sampleSize) { + lastUsedSampleSize = sampleSize; + } + numFrames = this.frames.length; + if (numFrames == 0) { + throw new IllegalArgumentException("Can't have AnimatedSprite with zero frames."); + } + frameWidth = frames[0].getWidth() * sampleSize; + frameHeight = frames[0].getHeight() * sampleSize; + listeners = new ArrayList<>(); + paint = new Paint(); + paint.setAntiAlias(true); + paint.setFilterBitmap(true); + } + + /** + * Return AnimatedSprite built from separate images (one image per frame). + */ + public static AnimatedSprite fromFrames(Resources resources, int[] ids) { + int sampleSize = lastUsedSampleSize; + Bitmap frames[] = new Bitmap[ids.length]; + for (int i = 0; i < ids.length; i++) { + Pair pair = getBitmapFromCache(ids[i], 0); + if (pair != null) { + frames[i] = pair.first; + sampleSize = pair.second; + } + if (frames[i] == null) { + final BitmapFactory.Options options = new BitmapFactory.Options(); + for (int tries = 0; tries < NUM_TRIES_TO_LOAD_FROM_MEMORY; tries++) { + try { + // Decode bitmap with inSampleSize set + options.inSampleSize = sampleSize; + frames[i] = BitmapFactory.decodeResource(resources, ids[i], options); + } catch (OutOfMemoryError oom) { + sampleSize *= 2; + Log.d(TAG, "loading failed, trying sampleSize: " + sampleSize, oom); + } + } + putBitmapInCache(frames[i], ids[i], 0, sampleSize); + } + } + return new AnimatedSprite(frames, sampleSize); + } + + /** + * Return AnimatedSprite built from the given Bitmap objects. (For testing). + */ + public static AnimatedSprite fromBitmapsForTest(Bitmap frames[]) { + return new AnimatedSprite(frames, 1); + } + + /** + * Return AnimatedSprite built from the same frames as another animated sprite. This isn't a + * deep clone, only the frames & FPS of the original sprite are copied. + */ + public static AnimatedSprite fromAnimatedSprite(AnimatedSprite other) { + AnimatedSprite sprite = new AnimatedSprite(other.frames, other.sampleSize); + sprite.setFPS(other.fps); + return sprite; + } + + private static Pair getBitmapFromCache(int id, int frame) { + if (bitmapCache == null) { + bitmapCache = new BitmapCache(); + } + return bitmapCache.getBitmapFromCache(id, frame); + } + + private static void putBitmapInCache(Bitmap bitmap, int id, int frame, int sampleSize) { + if (bitmapCache == null) { + bitmapCache = new BitmapCache(); + } + bitmapCache.putBitmapInCache(bitmap, id, frame, sampleSize); + } + + /** + * Set whether to loop the animation or not. + */ + public void setLoop(boolean loop) { + this.loop = loop; + } + + public void setFlippedX(boolean value) { + this.flippedX = value; + } + + public boolean isFlippedX() { + return flippedX; + } + + public void setPaused(boolean value) { + this.paused = value; + } + + /** + * Pause this sprite and return a process chain which can be updated to unpause the sprite after + * the specified length of time. + * + * @param durationMs how many milliseconds to pause the sprite for. + * @return a process chain which will unpause the sprite after the duration has completed. + */ + public ProcessChain pauseFor(long durationMs) { + setPaused(true); + CallbackProcess unpause = new CallbackProcess() { + @Override + public void updateLogic(float deltaMs) { + setPaused(false); + } + }; + return new WaitProcess(durationMs).then(unpause); + } + + /** + * Change the speed of the animation. + */ + public void setFPS(int fps) { + this.fps = fps; + } + + /** + * Sets the current frame. + */ + public void setFrameIndex(int frame) { + frameIndex = frame; + } + + public int getFrameIndex() { + return (int) frameIndex; + } + + public int getNumFrames() { + return numFrames; + } + + public float getDurationSeconds() { + return numFrames / (float) fps; + } + + /** + * Update the animation based on deltaMs having passed. + */ + public void update(float deltaMs) { + if (paused) { + return; + } + + float deltaFrames = (deltaMs / 1000.0f) * fps; + + // In order to make sure that we don't skip any frames when notifying listeners, this carefully + // accumulates deltaFrames instead of just immediately adding it into frameIndex. Be careful + // of floating point precision issues below. + while (deltaFrames > 0) { + // First, try accumulating the remaining deltaFrames and see if we make it to the next frame. + float newFrameIndex = frameIndex + deltaFrames; + if ((int) newFrameIndex == (int) frameIndex) { + // Didn't make it to the next frame. Done accumulating. + frameIndex = newFrameIndex; + deltaFrames = 0; + } else { + // Move forward to next frame, notify listeners, then keep accumlating. + float oldFrameIndex = frameIndex; + frameIndex = 1 + (int) frameIndex; // ignores numFrames, will handle it below. + deltaFrames -= frameIndex - oldFrameIndex; + + if (frameIndex < numFrames) { + sendOnFrameNotification((int) frameIndex); + } else { + if (loop) { + frameIndex = 0; + sendOnLoopNotification(); + sendOnFrameNotification((int) frameIndex); + } else { + frameIndex = numFrames - 1; + sendOnFinishNotification(); + // In this branch, there are no further onFrame notifications. + deltaFrames = 0; // No more changes to frameIndex, done accumulating. + } + } + } + } + } + + + void sendOnLoopNotification() { + for (int i = 0; i < listeners.size(); i++) { // Avoiding iterators to avoid garbage. + // Call the on-loop callbacks. + listeners.get(i).onLoop(); + } + } + + void sendOnFinishNotification() { + for (int i = 0; i < listeners.size(); i++) { // Avoiding iterators to avoid garbage + // Call the on-finished callbacks. + listeners.get(i).onFinished(); + } + } + + void sendOnFrameNotification(int frame) { + for (int i = 0; i < listeners.size(); i++) { // Avoiding iterators to avoid garbage. + listeners.get(i).onFrame(frame); + } + } + + public void draw(Canvas canvas) { + if (!hidden) { + // Integer cast should round down, but clamp it just in case the synchronization with the + // update thread isn't perfect. + int frameIndexFloor = Util.clamp((int) frameIndex, 0, numFrames - 1); + float scaleX = flippedX ? -this.scaleX : this.scaleX; + + canvas.save(); + srcRect.set(0, 0, frameWidth, frameHeight); + dstRect.set(-anchor.x, -anchor.y, -anchor.x + frameWidth, -anchor.y + frameHeight); + + canvas.translate(position.x, position.y); + canvas.scale(scaleX, scaleY, 0, 0); + canvas.rotate((float) Math.toDegrees(rotation), 0, 0); + + canvas.drawBitmap(frames[frameIndexFloor], srcRect, dstRect, paint); + canvas.restore(); + } + } + + // Unlike Actors, AnimatedSprites use setters instead of public fields for position, scale, etc. + // This matches how it works on iOS, which uses setters because the actual values must be passed + // down into SKNodes. + public void setPosition(float x, float y) { + position.x = x; + position.y = y; + } + + /** + * @param alpha: 0.0 = transparent, 1.0 = opaque. + */ + public void setAlpha(float alpha) { + paint.setAlpha((int) (alpha * 255)); + } + + // You can use this to more closely match the logic of iOS, where there is no draw method so the + // only way to hide something is to set this flag. On Android, you can also just not call draw + // if you want a sprite hidden. + public void setHidden(boolean hidden) { + this.hidden = hidden; + } + + public void setScale(float scaleX, float scaleY) { + this.scaleX = scaleX; + this.scaleY = scaleY; + } + + public float getScaledWidth() { + return scaleX * frameWidth; + } + + public float getScaledHeight() { + return scaleY * frameHeight; + } + + public void setRotation(float rotation) { + this.rotation = rotation; + } + + // Sets the anchor point which determines where the sprite is drawn relative to its position. This + // is also the point around which sprite rotates & scales. (x, y) are in pixels, relative to + // top-left corner. Initially set to the upper-left corner. + public void setAnchor(float x, float y) { + anchor.x = x; + anchor.y = y; + } + + public void addListener(AnimatedSpriteListener listener) { + listeners.add(listener); + } + + public void clearListeners() { + listeners.clear(); + } + + public int getNumListeners() { + return listeners.size(); + } + + public static void clearCache() { + if (AnimatedSprite.bitmapCache != null) { + AnimatedSprite.bitmapCache.clear(); + } + } + + // Reverse the frames of the animation. This doesn't update frameIndex, which may or may not + // be what you want. + public void reverseFrames() { + for (int i = 0; i < frames.length / 2; i++) { + Bitmap temp = frames[i]; + frames[i] = frames[frames.length - i - 1]; + frames[frames.length - i - 1] = temp; + } + } + + /** + * A class which can be implemented to provide callbacks for AnimatedSprite events. + */ + public static class AnimatedSpriteListener { + public void onFinished() { + } + + public void onLoop() { + } + + public void onFrame(int index) { + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/BallActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/BallActor.java new file mode 100644 index 000000000..041321c05 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/BallActor.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents ball in Tennis. + */ +public class BallActor extends Actor { + + private static final float MIN_SHADOW_SCALE = 0.4f; + private static final float MAX_SHADOW_SCALE = 0.7f; + // Highest the ball can be. Going higher than this may mess up scaling & shadow positioning. + public static final int BALL_MAX_HEIGHT = 75; + + private static final int MAX_STREAK_LENGTH = 10; // Max # of frames back the streak can go. + + // Slightly less than the sprite's frameWidth because there are semi-transparent pixels. + public static final int BALL_RADIUS = 14; + private static final double STREAK_ALPHA = 0.25; // 1 = opaque, 0 = transparent + private static final float BALL_MIN_SCALE = 0.5f; // Ball is scaled between BALL_MIN_SCALE and 1. + + private AnimatedSprite ball; + private AnimatedSprite fireball; // Flaming version of ball sprite (optional). + private AnimatedSprite shadow; // Might be null, if ball shouldn't have a shadow. + private float height = 0; // Height above the court. + // Whether or not the ball should be scaled larger at higher heights (to aid illusion of ball + // arcing through the air) + public boolean shouldScaleWithHeight; + private final Paint debugPaint; + // The streak is drawn by storing a history of positions & scales going back streakLength + // updates into the past. + private List streakPositions = new ArrayList<>(); + private List streakHeights = new ArrayList<>(); + private int streakIndex = 0; + // This is the actual streak length. On iOS, it must be <= MAX_STREAK_LENGTH in order to fit in + // the arrays, so we're keeping it <= here too. + private int streakLength = 10; + private boolean shouldDrawStreak = true; + private Paint streakPaint = new Paint(); + private Paint streakDebugPaint = new Paint(); + + // This is a field so that we don't have to create a new one every frame. Not threadsafe, + // but draw() shouldn't be called from multiple threads so it should be ok. + private Path path = new Path(); + + // Fireball is optional. + public BallActor(AnimatedSprite shadow, AnimatedSprite ball, AnimatedSprite fireball, + int streakLength) { + this.ball = ball; + ball.setAnchor(ball.frameWidth / 2, ball.frameHeight); + if (fireball != null) { + fireball.setAnchor(fireball.frameWidth / 2, BALL_RADIUS); + this.fireball = fireball; + } + + this.shadow = shadow; + this.streakLength = streakLength; + if (streakLength > MAX_STREAK_LENGTH) { + throw new IllegalArgumentException("Error: Streak length exceeds MAX_STREAK_LENGTH"); + } + shouldScaleWithHeight = true; + debugPaint = new Paint(); + debugPaint.setColor(0xff000000); + + streakPaint.setColor(android.graphics.Color.WHITE); + streakPaint.setStyle(Paint.Style.FILL); + streakPaint.setAlpha((int) (STREAK_ALPHA * 256)); + + streakDebugPaint.setColor(android.graphics.Color.BLACK); + streakDebugPaint.setStyle(Paint.Style.STROKE); + + clearStreak(); + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + ball.update(deltaMs); + if (fireball != null) { + fireball.update(deltaMs); + } + if (shadow != null) { + shadow.update(deltaMs); + } + + streakIndex++; + streakPositions.get(streakIndex % streakLength).set(position); + streakHeights.set(streakIndex % streakLength, height); + + // Prepare sprites for drawing. + if (shadow != null) { + float shadowScale = MIN_SHADOW_SCALE + (MAX_SHADOW_SCALE - MIN_SHADOW_SCALE) + * (1 - Math.min(BALL_MAX_HEIGHT, height) / BALL_MAX_HEIGHT); + if (!shouldScaleWithHeight) { + shadowScale = MAX_SHADOW_SCALE * scale; + } + shadow.setScale(shadowScale, shadowScale); + shadow.setPosition(position.x - shadowScale * shadow.frameWidth / 2, + position.y - shadowScale * shadow.frameHeight / 2); + } + + float ballScale = calculateScale(height); + ball.setScale(ballScale, ballScale); + ball.setRotation(rotation); + ball.setPosition(position.x, position.y - height); + if (fireball != null) { + fireball.setScale(ballScale, ballScale); + fireball.setRotation((float) (Math.atan2(velocity.y, velocity.x) + Math.PI / 2)); + fireball.setPosition(position.x, position.y - height - BALL_RADIUS); + } + + // Streak. Start by working down the left side of the streak. + path.rewind(); + for (int i = 0; i < streakLength; i++) { + int index = (streakIndex - i) % streakLength; + Vector2D pos = streakPositions.get(index); + float ballRadius = BALL_RADIUS * calculateScale(streakHeights.get(index)); + float taperedRadius = ballRadius * (1 - i / (float) streakLength); + float x = pos.x - taperedRadius; + float y = pos.y - ballRadius - streakHeights.get(index); + if (i == 0) { + path.moveTo(x, y); + } else { + path.lineTo(x, y); + } + } + + // Now finish by going back up right side of streak. + for (int i = streakLength - 1; i >= 0; i--) { + int index = (streakIndex - i) % streakLength; + Vector2D pos = streakPositions.get(index); + float ballRadius = BALL_RADIUS * calculateScale(streakHeights.get(index)); + float taperedRadius = ballRadius * (1 - i / (float) streakLength); + float x = pos.x + taperedRadius; + float y = pos.y - ballRadius - streakHeights.get(index); + path.lineTo(x, y); + } + path.close(); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + // Shadow, ball, and streak are all drawn together here, so nothing can be drawn above shadow + // but below the ball. + + if (!hidden) { + if (shadow != null) { + shadow.draw(canvas); + } + ball.draw(canvas); + if (fireball != null) { + fireball.draw(canvas); + } + if (shouldDrawStreak) { + canvas.drawPath(path, streakPaint); + } + + if (Debug.DRAW_POSITIONS) { + canvas.drawPath(path, streakDebugPaint); + canvas.drawCircle(position.x, position.y, 2, debugPaint); + canvas.drawCircle(position.x, position.y - height, 2, debugPaint); + } + } + } + + public void clearStreak() { + streakPositions.clear(); + streakHeights.clear(); + for (int i = 0; i < streakLength; i++) { + streakPositions.add(Vector2D.get(position)); + streakHeights.add(height); + } + streakIndex = streakLength; // Start here so we never get negative indexes. + } + + public void setHeight(float height) { + this.height = height; + } + + public float getHeight() { + return height; + } + + public void setColorForDebug(int color) { + debugPaint.setColor(color); + } + + public void showFireball(boolean shouldShowFireball) { + if (fireball != null) { + fireball.setHidden(!shouldShowFireball); + ball.setHidden(shouldShowFireball); + shouldDrawStreak = !shouldShowFireball; + } + } + + private float calculateScale(float height) { + if (!shouldScaleWithHeight) { + return scale; + } + return BALL_MIN_SCALE + (1 - BALL_MIN_SCALE) * height / BALL_MAX_HEIGHT; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/BitmapCache.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/BitmapCache.java new file mode 100644 index 000000000..d90b8695e --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/BitmapCache.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.graphics.Bitmap; +import android.util.Pair; + +import java.util.HashMap; + +/** + * Cache of bitmaps (and sampleSizes), mapped by resource ID and frame number. + * + *

Note: This cache must be manually cleared in order to free up memory. This is under the + * assumption that any bitmaps currently used by the app should be in the cache.

+ */ +public class BitmapCache { + public static final String TAG = BitmapCache.class.getSimpleName(); + + private HashMap> bitmapCache = new HashMap<>(); + + public Pair getBitmapFromCache(int id, int frame) { + Pair pair = bitmapCache.get(bitmapCacheKey(id, frame)); + return pair; + } + + public void putBitmapInCache(Bitmap bitmap, int id, int frame, int sampleSize) { + bitmapCache.put(bitmapCacheKey(id, frame), new Pair(bitmap, sampleSize)); + } + + public void clear() { + bitmapCache.clear(); + } + + private static String bitmapCacheKey(int id, int frameNumber) { + return id + ":" + frameNumber; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/CallbackProcess.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/CallbackProcess.java new file mode 100644 index 000000000..a0eae4d19 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/CallbackProcess.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * A process which should be run once and then be finished. + */ +public abstract class CallbackProcess extends Process { + private boolean didRun = false; + + @Override + public void update(float deltaMs) { + if (!didRun) { + updateLogic(deltaMs); + didRun = true; + } + } + + @Override + public boolean isFinished() { + return didRun; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Camera.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Camera.java new file mode 100644 index 000000000..a66a96876 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Camera.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import static com.google.android.apps.santatracker.doodles.shared.Interpolator.EASE_IN_AND_OUT; + +/** + * A camera class to contain the scale, translation, and rotation of the world. Note that the camera + * is defined to be positioned at the top-left corner of the screen. + */ +public class Camera extends Actor { + + public int screenWidth; + public int screenHeight; + + public Camera(int screenWidth, int screenHeight) { + this.position = Vector2D.get(); + scale = 1.0f; + + this.screenWidth = screenWidth; + this.screenHeight = screenHeight; + } + + /** + * Get the world coordinates for the screen coordinates specified. + * + * @param x The x value in screen space. + * @param y The y value in screen space. + */ + public Vector2D getWorldCoords(float x, float y) { + return Vector2D.get(xToWorld(x), yToWorld(y)); + } + + public float xToWorld(float x) { + return position.x + x / scale; + } + + public float yToWorld(float y) { + return position.y + y / scale; + } + + /** + * Converts a length from screen scale to world space. + * + * @param dimension: the length in screen space. + * @return the length in world space. + */ + public float toWorldScale(float dimension) { + return dimension / scale; + } + + /** + * Move the center of the camera's viewport to the specified position. + * + * @param position The position to center the camera on. + */ + public void focusOn(Vector2D position) { + this.position.set(getPositionToFocusOn(position, scale)); + } + + /** + * Get the camera position needed to focus on the specified position at the specified scale. + * + * @param position The position to center on. + * @param scale The scale at which to focus. + */ + private Vector2D getPositionToFocusOn(Vector2D position, float scale) { + return Vector2D.get(position).subtract((screenWidth / 2) / scale, (screenHeight / 2) / scale); + } + + /** + * Move the camer immediately so that it can see the bounding box specified by the min and max + * position vectors. + * + * @param levelMinPosition The desired minimum visible portion of the level. + * @param levelMaxPosition The desired maximum visible portion of the level. + */ + public void moveImmediatelyTo(Vector2D levelMinPosition, Vector2D levelMaxPosition) { + Vector2D levelDimens = Vector2D.get(levelMaxPosition).subtract(levelMinPosition); + + float pannedScale = Math.min(screenWidth / levelDimens.x, screenHeight / levelDimens.y); + Vector2D screenDimensInWorldCoords = Vector2D.get(screenWidth, screenHeight) + .scale(1 / pannedScale); + + // pannedPosition = levelMinPosition - (screenDimensInWorldCoords - levelDimens) / 2 + Vector2D pannedPosition = Vector2D.get(levelMinPosition).subtract( + (screenDimensInWorldCoords.x - levelDimens.x) * 0.5f, + (screenDimensInWorldCoords.y - levelDimens.y) * 0.5f); + + position.set(pannedPosition); + scale = pannedScale; + + screenDimensInWorldCoords.release(); + levelDimens.release(); + pannedPosition.release(); + } + + /** + * Pan to the specified position over the specified duration. + * + * @param levelMinPosition The desired minimum visible portion of the level. + * @param levelMaxPosition The desired maximum visible portion of the level. + * @param duration How many seconds the pan should take. + * @return The tween to pan the camera. + */ + public Tween panTo( + final Vector2D levelMinPosition, final Vector2D levelMaxPosition, float duration) { + + final Vector2D startMin = Vector2D.get(position); + final Vector2D startMax = getMaxVisiblePosition(); + + Tween panTween = new Tween(duration) { + @Override + protected void updateValues(float percentDone) { + + float xMin = EASE_IN_AND_OUT.getValue(percentDone, startMin.x, levelMinPosition.x); + float xMax = EASE_IN_AND_OUT.getValue(percentDone, startMax.x, levelMaxPosition.x); + float yMin = EASE_IN_AND_OUT.getValue(percentDone, startMin.y, levelMinPosition.y); + float yMax = EASE_IN_AND_OUT.getValue(percentDone, startMax.y, levelMaxPosition.y); + + Vector2D min = Vector2D.get(xMin, yMin); + Vector2D max = Vector2D.get(xMax, yMax); + moveImmediatelyTo(min, max); + min.release(); + max.release(); + } + + @Override + protected void onFinish() { + startMin.release(); + startMax.release(); + } + }; + return panTween; + } + + private Vector2D getMaxVisiblePosition() { + return Vector2D.get(position.x + screenWidth / scale, position.y + screenHeight / scale); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/CameraShake.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/CameraShake.java new file mode 100644 index 000000000..6a05a95ae --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/CameraShake.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * Tracks a vibration which reduces over time, suitable for screen shake effects. + * (Use position as the camera's offset when rendering) + */ +public class CameraShake extends Actor { + + private float frequency = 0; + private float magnitude = 0; + private float falloff = 0; + private float msTillNextShake = 0; + + public void shake(float frequency, float magnitude, float falloff) { + this.frequency = frequency; + this.magnitude = magnitude; + this.falloff = falloff; + msTillNextShake = 1000 / frequency; + } + + @Override + public void update(float deltaMs) { + if (magnitude == 0) { + return; + } + + msTillNextShake -= deltaMs; + if (msTillNextShake < 0) { + msTillNextShake = 1000 / frequency; + magnitude *= falloff; + // Tiny amounts of shake take too long to fall off, and they look bad, so just quickly + // kill the shake once it falls below a low threshold. + if (this.magnitude < 2) { + this.magnitude = 0; + } + } + position.x = (float) ((Math.random() - 0.5) * magnitude); + position.y = (float) ((Math.random() - 0.5) * magnitude); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Debug.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Debug.java new file mode 100644 index 000000000..1fa598e83 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Debug.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.res.Resources; +import com.google.android.apps.santatracker.doodles.tilt.ColoredRectangleActor; + +/** + * Debug flags (collected in one place). + */ +public class Debug { + // Draw positions of things as they move around. Tennis only for now. + public static final boolean DRAW_POSITIONS = false; + + // Draw the targets that the players hit towards. Tennis only for now. + public static final boolean DRAW_TARGETS = false; + + // Draw the location of each hit. Tennis only for now. + public static final boolean MARK_HITS = false; + + // Play without user input. Tennis only for now. + public static final boolean AUTO_PLAY = false; + + // Slow down or speed up everything (scales deltaMs). + public static final float SPEED_MULTIPLIER = 1f; + + // Skip frames (slows game down without affecting deltaMs). + public static final float FRAME_SKIP = 0; + + public static final boolean SHOW_SECONDARY_MENU_ICONS = false; + + // Return a SpriteActor of an "X" marker, centered over (x, y). For marking positions for + // debugging. + public static SpriteActor makeDebugMarkerX(Resources resources, float x, float y) { + AnimatedSprite sprite = AnimatedSprite.fromFrames(resources, Sprites.debug_marker); + return new SpriteActor(sprite, + Vector2D.get(x - sprite.frameWidth / 2, y - sprite.frameHeight / 2), + Vector2D.get(0, 0)); + } + + // Return a tiny rectangle actor, centered over (x, y). For marking positions for debugging. + public static Actor makeDebugMarkerPoint(float x, float y) { + float size = 3; + return new ColoredRectangleActor(Vector2D.get(x - size / 2, y - size / 2), + Vector2D.get(size, size), "fairway"); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/DoodleConfig.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/DoodleConfig.java new file mode 100644 index 000000000..65ba7a4ca --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/DoodleConfig.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.os.Bundle; +import android.support.annotation.Nullable; + +/** + * Class that holds the config we need for the doodle. + */ +public class DoodleConfig { + + /** + * Function to call to actually go to the search results page. + */ + public interface QueryRunner { + public void runQuery(); + } + + // Public to be read, but final so we know it doesn't change. + @Nullable + public final Bundle extraData; + @Nullable + public final QueryRunner queryRunner; + + public DoodleConfig(@Nullable Bundle extraData, @Nullable QueryRunner queryRunner) { + this.extraData = extraData; + this.queryRunner = queryRunner; + } + +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ElasticOutInterpolator.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ElasticOutInterpolator.java new file mode 100644 index 000000000..05f9cd50e --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ElasticOutInterpolator.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.view.animation.Interpolator; + +/** + * An interpolator which has a rubber bound effect around its end point, bouncing back and forth + * before settling at its final value. + * + * Implementation copied from outElastic here: https://goo.gl/SJZllG + */ +public class ElasticOutInterpolator implements Interpolator { + + private final float period; + + public ElasticOutInterpolator() { + period = 0.4f; + } + + public ElasticOutInterpolator(float period) { + this.period = period; + } + + @Override + public float getInterpolation(float value) { + return (float) (Math.pow(2, -10 * value) + * Math.sin((value - period / 4) * (2 * Math.PI) / period) + 1); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/EmptyTween.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/EmptyTween.java new file mode 100644 index 000000000..c4114fac4 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/EmptyTween.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * A tween that does nothing in its updateValues method. Can be used to insert pauses in chains + * of tweens. The useful part of this is that it calls finishedCallback after durationSeconds, + * and it fits into the existing Tween framework. + */ +public class EmptyTween extends Tween { + + public EmptyTween(float durationSeconds) { + super(durationSeconds); + } + + @Override + protected void updateValues(float percentDone) { + // Nothing to do, just waiting for the tween to end. + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/EventBus.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/EventBus.java new file mode 100644 index 000000000..178a08b08 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/EventBus.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A simple event bus for passing events between objects. + */ +public class EventBus { + private static EventBus instance; + + public static final int VIBRATE = 0; + public static final int SCORE_CHANGED = 1; + public static final int SHAKE_SCREEN = 2; + public static final int BRONZE = 3; + public static final int SILVER = 4; + public static final int GOLD = 5; + public static final int SWIMMING_DIVE = 6; + public static final int GAME_STATE_CHANGED = 7; + public static final int PLAY_SOUND = 8; + public static final int PAUSE_SOUND = 9; + public static final int MUTE_SOUNDS = 10; + public static final int GAME_OVER = 11; + public static final int GAME_LOADED = 12; + + private final Object lock = new Object(); + + /** + * Interface for objects which want to listen to the event bus. + */ + public interface EventBusListener { + void onEventReceived(int type, Object data); + } + + public static EventBus getInstance() { + if (instance == null) { + instance = new EventBus(); + } + return instance; + } + + // Listeners for specific events. + private Map> specificListeners; + // Listeners for all events. + private Set globalListeners; + + private EventBus() { + globalListeners = new HashSet<>(); + specificListeners = new HashMap<>(); + } + + /** + * Register for a specific event. Listener will only be called for events of that type. + */ + public void register(EventBusListener listener, int type) { + synchronized (lock) { + if (!specificListeners.containsKey(type)) { + specificListeners.put(type, new HashSet()); + } + specificListeners.get(type).add(listener); + } + } + + /** + * Register for all events. Listener will be called for events of any type. + */ + public void register(EventBusListener listener) { + synchronized (lock) { + globalListeners.add(listener); + } + } + + /** + * Send an event without data. + */ + public void sendEvent(int type) { + sendEvent(type, null); + } + + /** + * Send an event with data. Type of the data is up to the caller. + */ + public void sendEvent(int type, Object data) { + synchronized (lock) { + try { + Set listeners = specificListeners.get(type); + if (listeners != null) { + for (EventBusListener listener : listeners) { + listener.onEventReceived(type, data); + } + } + for (EventBusListener listener : globalListeners) { + listener.onEventReceived(type, data); + } + } catch (ClassCastException e) { + // This was happening when 2 games were running at the same time (which shouldn't be + // possible, but was happening in monkey testing). Game A's listener would try casting + // the data arg to the expected type for Game A, but this would fail if Game B sent a data + // of a different type. + // + // Ignore this and continue running. + } + } + } + + /** + * Removes all the listeners from this EventBus. + */ + public void clearListeners() { + synchronized (lock) { + specificListeners.clear(); + globalListeners.clear(); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ExternalStoragePermissions.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ExternalStoragePermissions.java new file mode 100644 index 000000000..2bcba2905 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ExternalStoragePermissions.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * Contains data about whether or not external storage is readable or writable. + */ +public class ExternalStoragePermissions { + + public boolean isExternalStorageReadable() { + return AndroidUtils.isExternalStorageReadable(); + } + + public boolean isExternalStorageWritable() { + return AndroidUtils.isExternalStorageWritable(); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/FakeButtonActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/FakeButtonActor.java new file mode 100644 index 000000000..59631a399 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/FakeButtonActor.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.graphics.Canvas; + +/** + * An actor that looks like a button, but doesn't actually have any logic to detect or respond to + * clicks. We use this to provide a UI affordance to the user. Even though all our games allow you + * to click anywhere on the screen, having something that looks like a button helps the users + * to know how to play the game. + */ +public class FakeButtonActor extends Actor { + + public final AnimatedSprite sprite; // Public so you can get to frameWidth/frameHeight. + private final int lastFrameIndex; + + /** + * The sprite for the button should conform to the following: + * 1. The last frame of the animation will be the "idle" state of the button. + * 2. When the button is pressed, the animation will be played through, starting from frame 0 + * and ending back on the last frame. + * 3. The FPS of the sprite should be set to give the button press animation the desired duration. + */ + public FakeButtonActor(AnimatedSprite sprite) { + super(); + this.sprite = sprite; + sprite.setLoop(false); + lastFrameIndex = sprite.getNumFrames() - 1; + sprite.setFrameIndex(lastFrameIndex); + } + + public void press() { + sprite.setFrameIndex(0); + } + + public void pressAndHold() { + sprite.setFrameIndex(0); + sprite.setPaused(true); + } + + public void release() { + sprite.setPaused(false); + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + sprite.update(deltaMs); + sprite.setPosition(position.x, position.y); + sprite.setRotation(rotation); + sprite.setHidden(hidden); + sprite.setAlpha(alpha); + sprite.setScale(scale, scale); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + sprite.draw(canvas); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameFragment.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameFragment.java new file mode 100644 index 000000000..12c5e1535 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameFragment.java @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.app.Activity; +import android.app.ActivityManager; +import android.app.Fragment; +import android.content.Context; +import android.os.AsyncTask; +import android.os.Handler; +import android.os.Looper; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ImageView.ScaleType; +import android.widget.TextView; + +import com.google.android.apps.santatracker.doodles.PineappleActivity; +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.PauseView.GamePausedListener; +import com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.Builder; +import com.google.android.apps.santatracker.doodles.shared.ScoreView.LevelFinishedListener; +import com.google.android.apps.santatracker.doodles.shared.sound.SoundManager; +import com.google.android.apps.santatracker.invites.AppInvitesFragment; +import com.google.android.apps.santatracker.util.FontHelper; + +import static com.google.android.apps.santatracker.doodles.shared.EventBus.GAME_LOADED; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.DEFAULT_DOODLE_NAME; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.LOADING_COMPLETE; + +/** + * Base class for Pineapple game fragments. + */ +public abstract class GameFragment extends Fragment implements + GameLoop, ScoreView.OnShareClickedListener { + + // Minimum length of the title screen. + public static final long TITLE_DURATION_MS = 1000; + + // Require 128MB and if we don't have it, downsample the resources. + private static final int AVAILABLE_MEMORY_REQUIRED = (2 << 27); + + // Note this is a context, not an activity. Use getActivity() for an activity. + public final Context context; + public final DoodleConfig doodleConfig; + public final PineappleLogger logger; + + protected FrameLayout wrapper; + protected View titleView; + private ImageView titleImageView; + protected ScoreView scoreView; + protected PauseView pauseView; + protected GamePausedListener gamePausedListener = new GamePausedListener() { + @Override + public void onPause() { + onGamePause(); + } + + @Override + public void onResume() { + onGameResume(); + } + + @Override + public void onReplay() { + onGameReplay(); + } + + @Override + public String gameType() { + return getGameType(); + } + + @Override + public float score() { + return getScore(); + } + }; + + protected LevelFinishedListener levelFinishedListener = new LevelFinishedListener() { + @Override + public void onReplay() { + onGameReplay(); + } + + @Override + public String gameType() { + return getGameType(); + } + + @Override + public float score() { + return getScore(); + } + + @Override + public int shareImageId() { + return getShareImageId(); + } + }; + + protected LogicRefreshThread logicRefreshThread; + protected UIRefreshHandler uiRefreshHandler; + protected SoundManager soundManager; + protected HistoryManager historyManager; + private AsyncTask asyncLoadGameTask; + + protected boolean isFinishedLoading = false; + protected boolean isPaused = false; + protected boolean resumeAfterLoading; + public boolean isDestroyed = false; + + public GameFragment() { + this.context = getActivity(); + this.doodleConfig = null; + this.logger = new PineappleNullLogger(); + } + + public GameFragment(Context context, DoodleConfig doodleConfig, PineappleLogger logger) { + this.context = context; + this.doodleConfig = doodleConfig; + this.logger = logger; + } + + @Override + public void onResume() { + super.onResume(); + if (context == null) { + return; + } + resume(); + if ((pauseView == null || pauseView.isPauseButtonEnabled) + && (scoreView == null || scoreView.getVisibility() != View.VISIBLE)) { + // If we aren't paused or finished, keep the screen on. + AndroidUtils.forceScreenToStayOn(getActivity()); + } + if (soundManager != null) { + soundManager.loadMutePreference(context); + } + } + + @Override + public void onPause() { + super.onPause(); + if (pauseView != null) { + pauseView.pause(); + } + resumeAfterLoading = false; + if (uiRefreshHandler != null) { + logicRefreshThread.stopHandler(); + uiRefreshHandler.stop(); + historyManager.save(); + } + if (soundManager != null) { + soundManager.pauseAll(); + soundManager.storeMutePreference(context); + } + AndroidUtils.allowScreenToTurnOff(getActivity()); + } + + // To be overrided by games if they want to do more cleanup on destroy. + protected void onDestroyHelper() { + } + + @Override + public void onDestroyView() { + isDestroyed = true; + if (asyncLoadGameTask != null) { + asyncLoadGameTask.cancel(true); + } + EventBus.getInstance().clearListeners(); + AnimatedSprite.clearCache(); + if (soundManager != null) { + soundManager.releaseAll(); + } + onDestroyHelper(); + super.onDestroyView(); + } + + protected void resume() { + if (uiRefreshHandler == null) { + resumeAfterLoading = true; + } else { + logicRefreshThread.startHandler(this); + if (titleView.getVisibility() != View.VISIBLE) { + playMusic(); + } + } + } + + /** + * Loads the game. Do not override this function. Instead use the three helper functions: + * firstPassLoadOnUiThread, secondPassLoadOnBackgroundThread, finalPassLoadOnUiThread. + */ + public final void loadGame() { + ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); + ActivityManager activityManager = (ActivityManager) getActivity() + .getSystemService(android.content.Context.ACTIVITY_SERVICE); + activityManager.getMemoryInfo(mi); + if (mi.availMem < AVAILABLE_MEMORY_REQUIRED || AnimatedSprite.lastUsedSampleSize > 2) { + // Low available memory, go ahead and load things with a larger sample size. + AnimatedSprite.lastUsedSampleSize = 2; + } + final Handler handler = new Handler(Looper.getMainLooper()); + handler.postDelayed(new Runnable() { + @Override + public void run() { + if (context != null && getActivity() != null) { + firstPassLoadOnUiThread(); + asyncLoadGameTask = new AsyncTask () { + @Override + protected Void doInBackground(Void... params) { + if (context != null && getActivity() != null) { + secondPassLoadOnBackgroundThread(); + } + return null; + } + @Override + protected void onPostExecute(Void result) { + if (context != null && getActivity() != null) { + finalPassLoadOnUiThread(); + } + } + }; + asyncLoadGameTask.execute(); + } + } + }, 100); + } + + protected void firstPassLoadOnUiThread() { + } + protected void secondPassLoadOnBackgroundThread() { + EventBus.getInstance().clearListeners(); + } + protected void finalPassLoadOnUiThread() { + } + + protected void onFinishedLoading() { + PineappleLogTimer logTimer = PineappleLogTimer.getInstance(); + long latencyMs = logTimer.timeElapsedMs(); + logger.logEvent(new Builder(DEFAULT_DOODLE_NAME, LOADING_COMPLETE) + .withEventSubType(getGameType()) + .withLatencyMs(latencyMs).build()); + EventBus.getInstance().sendEvent(GAME_LOADED, latencyMs); + logTimer.reset(); + if (pauseView != null) { + pauseView.onFinishedLoading(); + } + if (scoreView != null) { + scoreView.setVisibility(View.VISIBLE); + } + + isFinishedLoading = true; + } + + public boolean isFinishedLoading() { + return isFinishedLoading; + } + + protected void startHandlers() { + logicRefreshThread = new LogicRefreshThread(); + logicRefreshThread.start(); + uiRefreshHandler = new UIRefreshHandler(); + + // It's annoying when the GC kicks in during gameplay and makes the game stutter. Hint + // that now would be a good time to free up some space before the game starts. + System.gc(); + if (resumeAfterLoading) { + resume(); + } + } + + protected void playMusic() { + soundManager.play(R.raw.fruit_doodle_music); + } + + protected void hideTitle() { + UIUtil.fadeOutAndHide(titleView, 1, 500, new Runnable() { + @Override + public void run() { + if (titleImageView != null) { + titleImageView.setImageDrawable(null); + titleImageView = null; + } + } + }); + playMusic(); + } + + public boolean isGamePaused() { + return isPaused; + } + + public void onGamePause() { + isPaused = true; + } + + protected void onGameResume() { + isPaused = false; + } + + protected void onGameReplay() { + replay(); + isPaused = false; + PineappleLogTimer.getInstance().reset(); + } + + protected abstract float getScore(); + protected abstract int getShareImageId(); + + protected boolean onTitleTapped() { + return false; + } + + protected void replay() { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + scoreView.resetToStartState(); + } + }); + } + + protected void loadSounds() { + soundManager.loadLongSound(context, R.raw.fruit_doodle_music, true); + soundManager.loadShortSound(context, R.raw.menu_item_click); + soundManager.loadShortSound(context, R.raw.ui_positive_sound); + } + + protected ScoreView getScoreView() { + ScoreView scoreView = new ScoreView(context, this); + scoreView.setDoodleConfig(doodleConfig); + scoreView.setLogger(logger); + scoreView.setListener(levelFinishedListener); + return scoreView; + } + + protected PauseView getPauseView() { + PauseView pauseView = new PauseView(context); + pauseView.setDoodleConfig(doodleConfig); + pauseView.setLogger(logger); + pauseView.setListener(gamePausedListener); + return pauseView; + } + + protected View getTitleView(int resId, int textId) { + FrameLayout titleLayout = new FrameLayout(context); + titleImageView = new ImageView(context) { + @Override + public boolean onTouchEvent(MotionEvent event) { + return onTitleTapped(); + } + }; + titleImageView.setImageResource(resId); + titleImageView.setScaleType(ScaleType.CENTER_CROP); + + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + titleLayout.addView(titleImageView, lp); + + // Add fun fact. + boolean defaultEnabledValue = doodleConfig == null || doodleConfig.extraData == null; + + // Check if we are english, or we are allowed to run in all languages. + if (textId != 0) { + LayoutInflater inflater = LayoutInflater.from(context); + TextView textView = (TextView) inflater.inflate(R.layout.fact_view, titleLayout, false); + + // Set text and font + textView.setText(AndroidUtils.getText(context.getResources(), textId)); + FontHelper.makeLobster(textView); + + lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM); + titleLayout.addView(textView, lp); + } + + return titleLayout; + } + + @Override + public void onShareClicked() { + Activity activity = getActivity(); + if (activity instanceof PineappleActivity) { + AppInvitesFragment invites = ((PineappleActivity) activity).getAppInvitesFragment(); + if (invites != null) { + invites.sendGenericInvite(); + } + } + } + + protected abstract String getGameType(); + + public void onBackPressed() { + pauseView.pause(); + } + + public abstract boolean isGameOver(); +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameLoop.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameLoop.java new file mode 100644 index 000000000..7fe832381 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameLoop.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * Interface to handle the updating of game logic. + */ +public interface GameLoop { + + /** + * @param deltaMs Milliseconds since the last time update was called. Will be capped to avoid + * big jumps. + */ + void update(float deltaMs); +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameOverlayButton.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameOverlayButton.java new file mode 100644 index 000000000..78cf42117 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameOverlayButton.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import com.google.android.apps.santatracker.doodles.R; + +/** + * A button in the game overlay screens (pause and end screens). + */ +public class GameOverlayButton extends RelativeLayout { + + public GameOverlayButton(Context context) { + this(context, null); + } + + public GameOverlayButton(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public GameOverlayButton(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + inflate(context, R.layout.game_overlay_button, this); + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.GameOverlayButton, 0, 0); + + int imageRes = + ta.getResourceId(R.styleable.GameOverlayButton_imageSrc, R.drawable.common_btn_pause); + ImageView icon = (ImageView) findViewById(R.id.game_overlay_button_image); + icon.setImageResource(imageRes); + + String text = ta.getString(R.styleable.GameOverlayButton_text); + TextView description = (TextView) findViewById(R.id.game_overlay_button_description); + if (text == null || text.isEmpty()) { + description.setVisibility(GONE); + } else { + description.setText(text); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameType.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameType.java new file mode 100644 index 000000000..660684b89 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameType.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * Enum for all the different game types we have. + * Used by each type to get their proper history content. + */ +public enum GameType { + GOLF, + TENNIS, + SWIMMING, + JUMPING, + BMX, + WATER_POLO, + PURSUIT, +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/HistoryManager.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/HistoryManager.java new file mode 100644 index 000000000..068f2b7d6 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/HistoryManager.java @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.Context; +import android.os.AsyncTask; +import android.util.Log; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Maintains the history and stats of what the user has accomplished. + * + *

Note that this class handles the serializing into JSON instead of each game. This was done + * to make it easier to make a game picker that showed your status on each game. Since there are + * canonical types it would then know how to read them. We add a setArbitraryData and + * getArbitaryData for any game that wants to put other kind of information in. + */ +public class HistoryManager { + private static final String TAG = HistoryManager.class.getSimpleName(); + + public static final String BEST_PLACE_KEY = "place"; + public static final String BEST_STAR_COUNT_KEY = "stars"; + public static final String BEST_TIME_MILLISECONDS_KEY = "time"; + public static final String BEST_SCORE_KEY = "score"; + public static final String BEST_DISTANCE_METERS_KEY = "distance"; + public static final String ARBITRARY_DATA_KEY = "arb"; + + private static final String FILENAME = "history.json"; + + private final Context context; + private volatile JSONObject history; + + /** + * Listener for when the history is loaded. + */ + public static interface HistoryListener { + public void onFinishedLoading(); + public void onFinishedSaving(); + } + private HistoryListener listener; + + /** + * Creates a history manager. + * HistoryListener can be null. + */ + public HistoryManager(Context context, HistoryListener listener) { + this.context = context; + this.listener = listener; + // While history is loading from disk, we ignore any changes clients might ask for. + history = null; + load(); + } + + public void setListener(HistoryListener listener) { + this.listener = listener; + } + + /** + * Gets the json object for a particular game type. + */ + private JSONObject getGameObject(GameType gameType) throws JSONException { + if (history == null) { + throw new JSONException("null history"); + } + JSONObject gameObject = history.optJSONObject(gameType.toString()); + if (gameObject == null) { + gameObject = new JSONObject(); + } + return gameObject; + } + + /************************ Setters *****************************/ + /** + * Set the best place (1st, 2nd, 3rd) for a game type. + * NOTE: It's expected for the client to figure out if it is the best place. + */ + public void setBestPlace(GameType gameType, int place) { + try { + JSONObject gameObject = getGameObject(gameType); + gameObject.put(BEST_PLACE_KEY, place); + history.put(gameType.toString(), gameObject); + } catch (JSONException e) { + Log.e(TAG, "error setting place", e); + } + } + + /** + * Set the best star count for a game type. + * NOTE: It's expected for the client to figure out if it is the best star count. + */ + public void setBestStarCount(GameType gameType, int count) { + try { + JSONObject gameObject = getGameObject(gameType); + gameObject.put(BEST_STAR_COUNT_KEY, count); + history.put(gameType.toString(), gameObject); + } catch (JSONException e) { + Log.e(TAG, "error setting place", e); + } + } + + /** + * Set the best time for a game type. + * NOTE: it's expected for the client to figure out if it is the best time since some will want + * bigger and some will want smaller numbers. + */ + public void setBestTime(GameType gameType, long timeInMilliseconds) { + try { + JSONObject gameObject = getGameObject(gameType); + gameObject.put(BEST_TIME_MILLISECONDS_KEY, timeInMilliseconds); + history.put(gameType.toString(), gameObject); + } catch (JSONException e) { + Log.e(TAG, "error setting time", e); + } + } + + /** + * Set the best score for a game type. + * NOTE: it's expected for the client to figure out if it is the best score since some will want + * bigger and some will want smaller numbers. + */ + public void setBestScore(GameType gameType, double score) { + try { + JSONObject gameObject = getGameObject(gameType); + gameObject.put(BEST_SCORE_KEY, score); + history.put(gameType.toString(), gameObject); + } catch (JSONException e) { + Log.e(TAG, "error setting score", e); + } + } + + /** + * Set the best distance for a game type. + * NOTE: it's expected for the client to figure out if it is the best distance since some will + * want bigger and some will want smaller numbers. + */ + public void setBestDistance(GameType gameType, double distanceInMeters) { + try { + JSONObject gameObject = getGameObject(gameType); + gameObject.put(BEST_DISTANCE_METERS_KEY, distanceInMeters); + history.put(gameType.toString(), gameObject); + } catch (JSONException e) { + Log.e(TAG, "error setting distance", e); + } + } + + /** + * Sets an arbitrary jsonObject a game might want. + */ + public void setArbitraryData(GameType gameType, JSONObject data) { + try { + JSONObject gameObject = getGameObject(gameType); + gameObject.put(ARBITRARY_DATA_KEY, data); + history.put(gameType.toString(), gameObject); + } catch (JSONException e) { + Log.e(TAG, "error setting distance", e); + } + } + + /************************ Getters *****************************/ + + /** + * Returns the best place so far. Null if no value has been given yet. + */ + public Integer getBestPlace(GameType gameType) { + try { + JSONObject gameObject = getGameObject(gameType); + return gameObject.getInt(BEST_PLACE_KEY); + } catch (JSONException e) { + return null; + } + } + + /** + * Returns the best star count so far. Null if no value has been given yet. + */ + public Integer getBestStarCount(GameType gameType) { + try { + JSONObject gameObject = getGameObject(gameType); + return gameObject.getInt(BEST_STAR_COUNT_KEY); + } catch (JSONException e) { + return null; + } + } + + /** + * Returns the best time so far. Null if no value has been given yet. + */ + public Long getBestTime(GameType gameType) { + try { + JSONObject gameObject = getGameObject(gameType); + return gameObject.getLong(BEST_TIME_MILLISECONDS_KEY); + } catch (JSONException e) { + return null; + } + } + + /** + * Returns the best score so far. Null if no value has been given yet. + */ + public Double getBestScore(GameType gameType) { + try { + JSONObject gameObject = getGameObject(gameType); + return gameObject.getDouble(BEST_SCORE_KEY); + } catch (JSONException e) { + return null; + } + } + + /** + * Returns the best distance so far. Null if no value has been given yet. + */ + public Double getBestDistance(GameType gameType) { + try { + JSONObject gameObject = getGameObject(gameType); + return gameObject.getDouble(BEST_DISTANCE_METERS_KEY); + } catch (JSONException e) { + return null; + } + } + + /** + * Returns arbitrary JSONObject a game might want. Null if no value has been given yet. + */ + public JSONObject getArbitraryData(GameType gameType) { + try { + JSONObject gameObject = getGameObject(gameType); + return gameObject.getJSONObject(ARBITRARY_DATA_KEY); + } catch (JSONException e) { + return null; + } + } + + /********************** File Management **************************/ + /** + * Saves the file in the background. + */ + public void save() { + new AsyncTask () { + @Override + protected Void doInBackground(Void... params) { + try { + FileOutputStream outputStream = context.openFileOutput(FILENAME, Context.MODE_PRIVATE); + byte[] bytes = history.toString().getBytes(); + outputStream.write(bytes); + outputStream.close(); + Log.i(TAG, "Saved: " + history); + } catch (IOException e) { + Log.w(TAG, "Couldn't save JSON at: " + FILENAME); + } catch (Exception e) { + Log.w(TAG, "Crazy exception happened", e); + } + return null; + } + @Override + protected void onPostExecute(Void result) { + if (listener != null) { + listener.onFinishedSaving(); + } + } + }.execute(); + } + + /** + * Loads the history object from file. Then merges with any changes that might have occured while + * we waited for it to load. + */ + private void load() { + new AsyncTask () { + @Override + protected Void doInBackground(Void... params) { + try { + File file = new File(context.getFilesDir(), FILENAME); + int length = (int) file.length(); + if (length <= 0) { + history = new JSONObject(); + return null; + } + + byte[] bytes = new byte[length]; + FileInputStream inputStream = new FileInputStream(file); + inputStream.read(bytes); + inputStream.close(); + + history = new JSONObject(new String(bytes, "UTF-8")); + Log.i(TAG, "Loaded: " + history); + } catch (JSONException e) { + Log.w(TAG, "Couldn't create JSON for: " + FILENAME); + } catch (UnsupportedEncodingException e) { + Log.d(TAG, "Couldn't decode: " + FILENAME); + } catch (IOException e) { + Log.w(TAG, "Couldn't read history: " + FILENAME); + } + return null; + } + @Override + protected void onPostExecute(Void result) { + if (listener != null) { + listener.onFinishedLoading(); + } + } + }.execute(); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Interpolator.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Interpolator.java new file mode 100644 index 000000000..7fa07aec1 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Interpolator.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * Interpolates values for Tweens. Used to implement easing and repeated movement. + */ +public interface Interpolator { + + Interpolator LINEAR = new Interpolator() { + @Override + public float getValue(float percent, float initialValue, float finalValue) { + return initialValue + (finalValue - initialValue) * percent; + } + }; + Interpolator EASE_IN = new Interpolator() { + @Override + public float getValue(float percent, float initialValue, float finalValue) { + return initialValue + (finalValue - initialValue) * percent * percent; + } + }; + Interpolator EASE_OUT = new Interpolator() { + @Override + public float getValue(float percent, float initialValue, float finalValue) { + return initialValue - ((finalValue - initialValue) * percent * (percent - 2)); + } + }; + Interpolator EASE_IN_AND_OUT = new Interpolator() { + @Override + public float getValue(float percent, float initialValue, float finalValue) { + // Simple sigmoid function: y = 3 * x^2 - 2 * x^3 + return LINEAR.getValue(3 * percent * percent - 2 * percent * percent * percent, + initialValue, finalValue); + } + }; + Interpolator FAST_IN = new Interpolator() { + @Override + public float getValue(float percent, float initialValue, float finalValue) { + return initialValue + (finalValue - initialValue) * (-percent * (percent - 2)); + } + }; + Interpolator FAST_IN_AND_HOLD = new Interpolator() { + @Override + public float getValue(float percent, float initialValue, float finalValue) { + percent *= 2; + if (percent > 1) { + percent = 1; + } + return initialValue + (finalValue - initialValue) * (-percent * (percent - 2)); + } + }; + + Interpolator OVERSHOOT = new Interpolator() { + @Override + public float getValue(float percent, float initialValue, float finalValue) { + percent -= 1; + percent = percent * percent * (3 * percent + 2) + 1; + return initialValue + (finalValue - initialValue) * percent; + } + }; + + float getValue(float percent, float initialValue, float finalValue); +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/LaunchDecisionMaker.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/LaunchDecisionMaker.java new file mode 100644 index 000000000..2b8f38a1f --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/LaunchDecisionMaker.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.app.Activity; +import android.app.Fragment; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; + +import com.google.android.apps.santatracker.doodles.pursuit.PursuitFragment; +import com.google.android.apps.santatracker.doodles.tilt.SwimmingFragment; +import com.google.android.apps.santatracker.doodles.waterpolo.WaterPoloFragment; + +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.DOODLE_LAUNCHED; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.RUNNING_GAME_TYPE; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.SWIMMING_GAME_TYPE; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.WATERPOLO_GAME_TYPE; + +/** + * Determines which Fragment we should start with based on the DoodleConfig data. For example, + * starting with the Swimming game versus going to the Main Menu. + */ +public class LaunchDecisionMaker { + + // Key for value of final Present Drop score. + public static final String EXTRA_PRESENT_DROP_SCORE = "presentDropScore"; + public static final String EXTRA_PRESENT_DROP_STARS = "presentDropStars"; + + // These are the keys and values we expect from the DoodleConfig setup in doodle canon. + public static final String START_GAME_KEY = "startUp"; + public static final String RUNNING_GAME_VALUE = "running"; + public static final String WATERPOLO_GAME_VALUE = "waterpolo"; + public static final String SWIMMING_GAME_VALUE = "swimming"; + + public static void finishActivity(Context context) { + AndroidUtils.getActivityFromContext(context).finish(); + } + + public static void finishActivityWithResult(Context context, int resultCode, Bundle extras) { + Activity activity = AndroidUtils.getActivityFromContext(context); + Intent intent = activity.getIntent(); + intent.putExtras(extras); + activity.setResult(resultCode, intent); + activity.finish(); + } + public static Fragment makeFragment(@Nullable Context context, + @Nullable DoodleConfig doodleConfig, PineappleLogger logger) { + String gameType = null; + Fragment gameFragment = null; + if (doodleConfig != null && doodleConfig.extraData != null) { + // Check if we have a startup value. + CharSequence startUp = doodleConfig.extraData.getCharSequence(START_GAME_KEY); + if (startUp != null) { + // Launch the right game if so. + if (RUNNING_GAME_VALUE.equals(startUp)) { + gameType = RUNNING_GAME_TYPE; + gameFragment = new PursuitFragment(context, doodleConfig, logger); + } else if (WATERPOLO_GAME_VALUE.equals(startUp)) { + gameType = WATERPOLO_GAME_TYPE; + gameFragment = new WaterPoloFragment(context, doodleConfig, logger); + } else if (SWIMMING_GAME_VALUE.equals(startUp)) { + gameType = SWIMMING_GAME_TYPE; + gameFragment = new SwimmingFragment(context, doodleConfig, logger, false); + } + } + } + + if (gameFragment != null) { + logger.logGameLaunchEvent(context, gameType, DOODLE_LAUNCHED); + PineappleLogTimer.getInstance().reset(); + return gameFragment; + } else { + throw new IllegalArgumentException("Invalid DoodleConfig: " + doodleConfig); + } + } + +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/LogicRefreshThread.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/LogicRefreshThread.java new file mode 100644 index 000000000..6bfb0d073 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/LogicRefreshThread.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.os.ConditionVariable; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +/** + * Thread subclass which handles refreshing the game logic. + */ +public class LogicRefreshThread extends Thread { + private static final int REFRESH_MODEL = 0; + + // Wait at least this long between updates. + // Update at 120 FPS so that stutters due to draw-loop synchronization are less noticeable. + private static final int MODEL_INTERVAL_MS = 1000 / 60; + + private Handler handler; + private final ConditionVariable handlerCreatedCV = new ConditionVariable(); + + // Toggled in start/stop, and used in handleMessage to conditionally schedule the next refresh. + private volatile boolean running; + + private GameLoop gameLoop; + private long lastTick; + private int framesSkippedSinceLastUpdate = 0; + + public LogicRefreshThread() { + setPriority(Thread.MAX_PRIORITY); + } + + @Override + public void run() { + Looper.prepare(); + + handler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (running && gameLoop != null) { + if (msg.what == REFRESH_MODEL) { + float deltaMs = System.currentTimeMillis() - lastTick; + // Cap deltaMs. Better for game to appear to slow down than have skips/jumps. + deltaMs = Math.min(100, deltaMs); + deltaMs *= Debug.SPEED_MULTIPLIER; + lastTick = System.currentTimeMillis(); + + framesSkippedSinceLastUpdate++; + if (framesSkippedSinceLastUpdate >= Debug.FRAME_SKIP) { + framesSkippedSinceLastUpdate = 0; + if (gameLoop != null) { + gameLoop.update(deltaMs); + } + } + + // Wait different amounts of time depending on how much time the game loop took. + // Wait at least 1ms to avoid a mysterious memory leak. + long timeToUpdate = System.currentTimeMillis() - lastTick; + sendEmptyMessageDelayed(REFRESH_MODEL, Math.max(1, MODEL_INTERVAL_MS - timeToUpdate)); + } + } + } + }; + handlerCreatedCV.open(); + + Looper.loop(); + } + + public void startHandler(GameLoop gameLoop) { + this.gameLoop = gameLoop; + running = true; + lastTick = System.currentTimeMillis(); + + handlerCreatedCV.block(); + handler.sendEmptyMessage(REFRESH_MODEL); + } + + public void stopHandler() { + running = false; + gameLoop = null; + + handlerCreatedCV.block(); + handler.removeMessages(REFRESH_MODEL); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/MultiSpriteActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/MultiSpriteActor.java new file mode 100644 index 000000000..9a1a6f1c1 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/MultiSpriteActor.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.res.Resources; +import android.util.Log; + +import java.util.HashMap; +import java.util.Map; + +/** + * An actor which has multiple sprites which it can switch between. + */ +public class MultiSpriteActor extends SpriteActor { + private static final String TAG = MultiSpriteActor.class.getSimpleName(); + public Map sprites; + + public MultiSpriteActor(Map sprites, String selectedSpriteKey, + Vector2D position, Vector2D velocity) { + super(sprites.get(selectedSpriteKey), position, velocity); + this.sprites = sprites; + } + + public void setSprite(String key) { + if (sprites.containsKey(key)) { + sprite = sprites.get(key); + } else { + Log.w(TAG, "Couldn't set sprite, unrecognized key: " + key); + } + } + + /** + * A class which makes it easier to re-construct MultiSpriteActors. + */ + public static class Data { + public String key; + public int[] idList; + public int numFrames; + public Data(String key, int[] idList) { + this.key = key; + this.idList = idList; + this.numFrames = idList.length; + } + public AnimatedSprite getSprite(Resources resources) { + if (idList != null) { + return AnimatedSprite.fromFrames(resources, idList); + } + return null; + } + } + + public static MultiSpriteActor create( + Data[] data, String selectedSprite, Vector2D position, Resources resources) { + Map sprites = new HashMap<>(); + for (int i = 0; i < data.length; i++) { + sprites.put(data[i].key, data[i].getSprite(resources)); + } + return new MultiSpriteActor(sprites, selectedSprite, position, Vector2D.get()); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PauseView.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PauseView.java new file mode 100644 index 000000000..674225a0b --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PauseView.java @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageButton; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.Builder; +import com.google.android.apps.santatracker.doodles.shared.sound.SoundManager; + +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.DEFAULT_DOODLE_NAME; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.HOME_CLICKED; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.MUTE_CLICKED; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.PAUSE_CLICKED; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.REPLAY_CLICKED; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.UNMUTE_CLICKED; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.UNPAUSE_CLICKED; + +/** + * The overlay which is shown when a game is paused. + */ +public class PauseView extends FrameLayout { + + private static final int BIG_PAUSE_FADE_IN_MS = 200; // Fading in paused screen elements. + private static final int FADE_IN_MS = 500; // Fading in paused screen elements. + private static final int FADE_OUT_MS = 200; // Fading out paused screen elements. + private static final int BUMP_MS = 200; // The paused text over-zooms a bit on pause. + private static final int RELAX_MS = 200; // The paused text shrinks a bit after zooming up. + private static final float ZOOM_UP_SCALE_OVERSHOOT = 1.2f; + + public static final int FADE_DURATION_MS = 400; // The pause button fading in and out. + + /** + * A listener for interacting with the PauseView. + */ + public interface GamePausedListener { + void onPause(); + void onResume(); + void onReplay(); + + String gameType(); + float score(); + } + private GamePausedListener listener; + private DoodleConfig doodleConfig; + private PineappleLogger logger; + + private ImageButton muteButton; + private GameOverlayButton pauseButton; + private View resumeButton; + private View buttonContainer; + private View background; + + public boolean isPauseButtonEnabled = true; + private float backgroundAlpha; + private float pauseButtonAlpha; + + public PauseView(Context context) { + this(context, null); + } + + public PauseView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public PauseView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + loadLayout(context); + hidePauseScreen(); + } + + public void setDoodleConfig(DoodleConfig doodleConfig) { + this.doodleConfig = doodleConfig; + } + + public void setLogger(PineappleLogger logger) { + this.logger = logger; + } + + public GamePausedListener getListener() { + return this.listener; + } + + public void setListener(GamePausedListener listener) { + this.listener = listener; + } + + public void hidePauseButton() { + isPauseButtonEnabled = false; + UIUtil.fadeOutAndHide(pauseButton, FADE_DURATION_MS, pauseButtonAlpha); + } + + public void showPauseButton() { + isPauseButtonEnabled = true; + UIUtil.showAndFadeIn(pauseButton, FADE_DURATION_MS, pauseButtonAlpha); + } + + public void onFinishedLoading() { + setVisibility(View.VISIBLE); + } + + protected void loadLayout(final Context context) { + setVisibility(View.INVISIBLE); + LayoutInflater inflater = LayoutInflater.from(context); + + View view = inflater.inflate(R.layout.pause_view, this); + + buttonContainer = view.findViewById(R.id.button_container); + + muteButton = (ImageButton) view.findViewById(R.id.mute_button); + if (SoundManager.soundsAreMuted) { + muteButton.setImageResource(R.drawable.common_btn_speaker_off); + } + muteButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + boolean shouldMute = !SoundManager.soundsAreMuted; + + String logEventName = shouldMute ? MUTE_CLICKED : UNMUTE_CLICKED; + logger.logEvent(new Builder(DEFAULT_DOODLE_NAME, logEventName) + .withEventSubType(listener.gameType()).build()); + + muteButton.setImageResource( + shouldMute ? R.drawable.common_btn_speaker_off : R.drawable.common_btn_speaker_on); + muteButton.setContentDescription(context.getResources().getString( + shouldMute ? R.string.unmute : R.string.mute)); + EventBus.getInstance().sendEvent(EventBus.MUTE_SOUNDS, shouldMute); + } + }); + + pauseButton = (GameOverlayButton) view.findViewById(R.id.pause_button); + pauseButtonAlpha = pauseButton.getAlpha(); + pauseButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + pause(); + } + }); + + resumeButton = view.findViewById(R.id.resume_button); + resumeButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + logger.logEvent(new Builder(DEFAULT_DOODLE_NAME, UNPAUSE_CLICKED) + .withEventSubType(listener.gameType()).build()); + unpause(); + } + }); + + View replayButton = view.findViewById(R.id.replay_button); + replayButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + logger.logEvent(new Builder(DEFAULT_DOODLE_NAME, REPLAY_CLICKED) + .withEventSubType(listener.gameType()) + .withLatencyMs(PineappleLogTimer.getInstance().timeElapsedMs()) + .withEventValue1(listener.score()) + .build()); + replay(); + } + }); + + View menuButton = view.findViewById(R.id.menu_button); + menuButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.menu_item_click); + + logger.logEvent(new Builder(DEFAULT_DOODLE_NAME, HOME_CLICKED) + .withEventSubType(listener.gameType()) + .withLatencyMs(PineappleLogTimer.getInstance().timeElapsedMs()) + .withEventValue1(listener.score()) + .build()); + + LaunchDecisionMaker.finishActivity(context); + } + }); + + background = view.findViewById(R.id.pause_view_background); + backgroundAlpha = background.getAlpha(); + } + + private void replay() { + PineappleLogTimer.getInstance().unpause(); + hidePauseScreen(); + if (listener != null) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.menu_item_click); + listener.onReplay(); + } + } + + /** + * Pauses the current game. + */ + public void pause() { + if (!isPauseButtonEnabled) { + return; + } + logger.logEvent(new Builder(DEFAULT_DOODLE_NAME, PAUSE_CLICKED) + .withEventSubType(listener.gameType()) + .withLatencyMs(PineappleLogTimer.getInstance().timeElapsedMs()) + .build()); + PineappleLogTimer.getInstance().pause(); + if (listener != null) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.menu_item_click); + listener.onPause(); + } + showPauseScreen(); + AndroidUtils.allowScreenToTurnOff(getContext()); + } + + private void unpause() { + PineappleLogTimer.getInstance().unpause(); + hidePauseScreen(); + if (listener != null) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.menu_item_click); + listener.onResume(); + } + AndroidUtils.forceScreenToStayOn(getContext()); + } + + private void showPauseScreen() { + isPauseButtonEnabled = false; + SoundManager soundManager = SoundManager.getInstance(); + soundManager.mute(R.raw.fruit_doodle_music); + soundManager.pauseShortSounds(); + + if (SoundManager.soundsAreMuted) { + muteButton.setImageResource(R.drawable.common_btn_speaker_off); + } else { + muteButton.setImageResource(R.drawable.common_btn_speaker_on); + } + + muteButton.setAlpha(0.0f); + resumeButton.setAlpha(0.0f); + buttonContainer.setAlpha(0); + background.setAlpha(0); + + muteButton.setVisibility(VISIBLE); + resumeButton.setVisibility(VISIBLE); + buttonContainer.setVisibility(VISIBLE); + background.setVisibility(VISIBLE); + + ValueAnimator fadeBigPauseIn = UIUtil.animator(BIG_PAUSE_FADE_IN_MS, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + resumeButton.setAlpha((float) valueAnimator.getAnimatedValue("textAlpha")); + background.setAlpha((float) valueAnimator.getAnimatedValue("bgAlpha")); + } + }, + UIUtil.floatValue("textAlpha", 0, 1), + UIUtil.floatValue("bgAlpha", 0, backgroundAlpha) + ); + + ValueAnimator fadePauseButtonOut = UIUtil.animator(BIG_PAUSE_FADE_IN_MS, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + pauseButton.setAlpha((float) valueAnimator.getAnimatedValue("pauseButtonAlpha")); + } + }, + UIUtil.floatValue("pauseButtonAlpha", pauseButtonAlpha, 0) + ); + fadePauseButtonOut.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + pauseButton.setVisibility(INVISIBLE); + } + }); + + ValueAnimator zoomUp = UIUtil.animator(BUMP_MS, new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float scale = (float) valueAnimator.getAnimatedValue("scale"); + resumeButton.setScaleX(scale); + resumeButton.setScaleY(scale); + } + }, + UIUtil.floatValue("scale", 0, ZOOM_UP_SCALE_OVERSHOOT) + ); + + ValueAnimator relax = UIUtil.animator(RELAX_MS, new OvershootInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float scale = (float) valueAnimator.getAnimatedValue("scale"); + resumeButton.setScaleX(scale); + resumeButton.setScaleY(scale); + } + }, + UIUtil.floatValue("scale", ZOOM_UP_SCALE_OVERSHOOT, 1)); + + ValueAnimator fadeIn = UIUtil.animator(FADE_IN_MS, new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + muteButton.setAlpha((float) valueAnimator.getAnimatedValue("alpha")); + buttonContainer.setAlpha((float) valueAnimator.getAnimatedValue("alpha")); + } + }, + UIUtil.floatValue("alpha", 0, 1) + ); + AnimatorSet animations = new AnimatorSet(); + animations.play(fadeBigPauseIn).with(zoomUp); + animations.play(fadePauseButtonOut).with(zoomUp); + animations.play(relax).after(zoomUp); + animations.play(fadeIn).after(zoomUp); + animations.start(); + } + + private void hidePauseScreen() { + SoundManager soundManager = SoundManager.getInstance(); + soundManager.unmute(R.raw.fruit_doodle_music); + soundManager.resumeShortSounds(); + + ValueAnimator fadeOut = UIUtil.animator(FADE_OUT_MS, new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + muteButton.setAlpha((float) valueAnimator.getAnimatedValue("overlayAlpha")); + background.setAlpha((float) valueAnimator.getAnimatedValue("bgAlpha")); + buttonContainer.setAlpha((float) valueAnimator.getAnimatedValue("overlayAlpha")); + + resumeButton.setAlpha((float) valueAnimator.getAnimatedValue("overlayAlpha")); + resumeButton.setScaleX((float) valueAnimator.getAnimatedValue("iconScale")); + resumeButton.setScaleY((float) valueAnimator.getAnimatedValue("iconScale")); + + } + }, + UIUtil.floatValue("overlayAlpha", 1, 0), + UIUtil.floatValue("bgAlpha", backgroundAlpha, 0), + UIUtil.floatValue("iconScale", 1, 2) + ); + fadeOut.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + muteButton.setVisibility(INVISIBLE); + resumeButton.setVisibility(INVISIBLE); + buttonContainer.setVisibility(INVISIBLE); + background.setVisibility(INVISIBLE); + + isPauseButtonEnabled = true; + } + }); + + pauseButton.setAlpha(0.0f); + pauseButton.setVisibility(VISIBLE); + ValueAnimator fadePauseButtonIn = UIUtil.animator(FADE_OUT_MS, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + pauseButton.setAlpha((float) valueAnimator.getAnimatedValue("alpha")); + } + }, + UIUtil.floatValue("alpha", 0, pauseButtonAlpha) + ); + + AnimatorSet animations = new AnimatorSet(); + animations.play(fadeOut).with(fadePauseButtonIn); + animations.start(); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleDebugLogger.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleDebugLogger.java new file mode 100644 index 000000000..0fe2652a9 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleDebugLogger.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.util.Log; + +/** + * A stub logger for the purposes of testing output of log statements in the Pineapple 2016 games. + */ +public class PineappleDebugLogger extends PineappleLogger { + private static final String TAG = PineappleDebugLogger.class.getSimpleName(); + + @Override + public void logEvent(PineappleLogEvent event) { + Log.d(TAG, event.toString()); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleLogEvent.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleLogEvent.java new file mode 100644 index 000000000..14bc60a30 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleLogEvent.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.support.annotation.Nullable; + +/** + * A class used for constructing log events for the Pineapple 2016 games. + */ +public class PineappleLogEvent { + public static final String DEFAULT_DOODLE_NAME = "olympics"; + + public static final String MUTE_CLICKED = "clicked mute"; + public static final String UNMUTE_CLICKED = "clicked unmute"; + public static final String PAUSE_CLICKED = "clicked pause"; + public static final String UNPAUSE_CLICKED = "clicked unpause"; + public static final String REPLAY_CLICKED = "clicked replay"; + public static final String SHARE_CLICKED = "clicked share"; + public static final String HOME_CLICKED = "clicked home"; + public static final String LOADING_COMPLETE = "loading complete"; + public static final String DOODLE_LAUNCHED = "doodle launched"; + public static final String GAME_OVER = "game over"; + + public static final String DISTINCT_GAMES_PLAYED = "distinct games"; + public static final String RUNNING_GAME_TYPE = "running"; + public static final String WATERPOLO_GAME_TYPE = "waterpolo"; + public static final String SWIMMING_GAME_TYPE = "swimming"; + + + public final String doodleName; + public final String eventName; + @Nullable public final String eventSubType; + @Nullable public final Float eventValue1; + @Nullable public final Float eventValue2; + @Nullable public final Long latencyMs; + + private PineappleLogEvent(String doodleName, String eventName, + @Nullable String eventSubType, @Nullable Float eventValue1, + @Nullable Float eventValue2, @Nullable Long latencyMs) { + this.doodleName = doodleName; + this.eventName = eventName; + this.eventSubType = eventSubType; + this.eventValue1 = eventValue1; + this.eventValue2 = eventValue2; + this.latencyMs = latencyMs; + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("PineappleLogEvent(" + doodleName); + stringBuilder.append(", " + eventName); + stringBuilder.append(", " + eventSubType); + stringBuilder.append(", " + eventValue1); + stringBuilder.append(", " + eventValue2); + stringBuilder.append(", " + latencyMs + ")"); + return stringBuilder.toString(); + } + + /** + * A helper class to build PineappleLogEvents. + */ + public static class Builder { + private String doodleName; + private String eventName; + @Nullable private String eventSubType; + @Nullable private Float eventValue1; + @Nullable private Float eventValue2; + @Nullable private Long latencyMs; + + public Builder(String doodleName, String eventName) { + this.doodleName = doodleName; + this.eventName = eventName; + this.eventSubType = null; + this.eventValue1 = null; + this.eventValue2 = null; + this.latencyMs = null; + } + + public Builder withEventSubType(String eventSubType) { + this.eventSubType = eventSubType; + return this; + } + + public Builder withEventValue1(float eventValue1) { + this.eventValue1 = eventValue1; + return this; + } + + public Builder withEventValue2(float eventValue2) { + this.eventValue2 = eventValue2; + return this; + } + + public Builder withLatencyMs(long latencyMs) { + this.latencyMs = latencyMs; + return this; + } + + public PineappleLogEvent build() { + return new PineappleLogEvent( + doodleName, eventName, eventSubType, eventValue1, eventValue2, latencyMs); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleLogTimer.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleLogTimer.java new file mode 100644 index 000000000..8778e6bd6 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleLogTimer.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.support.annotation.VisibleForTesting; + +/** + * A helper for timing log events in the Pineapple 2016 games. + */ +public class PineappleLogTimer { + private static PineappleLogTimer instance; + + public static PineappleLogTimer getInstance() { + if (instance == null) { + instance = new PineappleLogTimer(); + } + return instance; + } + + private long startTimeMs; + private long pauseTimeMs; + private boolean isPaused; + private LogClock clock; + + private PineappleLogTimer() { + this(new LogClock()); + } + + @VisibleForTesting + PineappleLogTimer(LogClock clock) { + this.clock = clock; + startTimeMs = clock.currentTimeMillis(); + } + + public void reset() { + startTimeMs = clock.currentTimeMillis(); + pauseTimeMs = clock.currentTimeMillis(); + unpause(); + } + + public long timeElapsedMs() { + if (isPaused) { + return pauseTimeMs - startTimeMs; + } + return clock.currentTimeMillis() - startTimeMs; + } + + public void pause() { + if (!isPaused) { + pauseTimeMs = clock.currentTimeMillis(); + isPaused = true; + } + } + + public void unpause() { + if (isPaused) { + long pauseDurationMs = clock.currentTimeMillis() - pauseTimeMs; + startTimeMs += pauseDurationMs; + isPaused = false; + } + } + + /** + * Wrapper around System.currentTimeMillis so that we can test PineappleLogTimer. + */ + @VisibleForTesting + static class LogClock { + public long currentTimeMillis() { + return System.currentTimeMillis(); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleLogger.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleLogger.java new file mode 100644 index 000000000..2017e0b9f --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleLogger.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.AsyncTask; + +import com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.Builder; + +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.DEFAULT_DOODLE_NAME; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.DISTINCT_GAMES_PLAYED; + +/** + * Interface for logging DoodleEvents within the pineapple games. + */ +public abstract class PineappleLogger { + private static final String PREFS_NAME = "PineappleLoggerPrefs"; + + public abstract void logEvent(PineappleLogEvent event); + + public void logGameLaunchEvent( + final Context context, final String gameType, final String eventName) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_NAME, 0); + SharedPreferences.Editor editor = sharedPreferences.edit(); + + int gamePlays = sharedPreferences.getInt(gameType, 0); + int distinctGamesPlayed = sharedPreferences.getInt(DISTINCT_GAMES_PLAYED, 0); + if (gamePlays == 0) { + // If this is our first time playing this game, increment distinct games played. + editor.putInt(DISTINCT_GAMES_PLAYED, ++distinctGamesPlayed); + } + editor.putInt(gameType, ++gamePlays); + editor.commit(); + + logEvent( + new Builder(DEFAULT_DOODLE_NAME, eventName) + .withEventSubType(gameType) + .withEventValue1(gamePlays) + .withEventValue2(distinctGamesPlayed) + .build()); + + return null; + } + }.execute(); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleNullLogger.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleNullLogger.java new file mode 100644 index 000000000..6cb019566 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/PineappleNullLogger.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * A stub of a logger which does nothing. + */ +public class PineappleNullLogger extends PineappleLogger { + + @Override + public void logEvent(PineappleLogEvent event) { + // Do nothing. + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Process.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Process.java new file mode 100644 index 000000000..e5f3b9ca4 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Process.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * A generic class for running some piece of code. This class is most useful when used inside of + * a process chain, which allows you explicitly define portions of code which should be run in + * serial (generally inside of the update loop). + */ +public abstract class Process { + + public Process() { + } + + /** + * The outer update function for this process. Note that, when implementing the logic for the + * process, updateLogic() should generally be overridden instead of update(). + * @param deltaMs + */ + public void update(float deltaMs) { + if (!isFinished()) { + updateLogic(deltaMs); + } + } + + public ProcessChain then(Process other) { + return new ProcessChain(this).then(other); + } + + public ProcessChain then(ProcessChain pc) { + return new ProcessChain(this).then(pc); + } + + public abstract void updateLogic(float deltaMs); + + public abstract boolean isFinished(); +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ProcessChain.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ProcessChain.java new file mode 100644 index 000000000..8da81311f --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ProcessChain.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * A chain of processes, which are executed in the order in which they are added. When a process + * is finished, it is removed from the chain and the next process in line is executed. + */ +public class ProcessChain { + private Queue processes; + + public ProcessChain(Process p) { + processes = new LinkedList<>(); + processes.add(p); + } + + public ProcessChain then(Process p) { + processes.add(p); + return this; + } + + public ProcessChain then(ProcessChain pc) { + processes.addAll(pc.processes); + return this; + } + + public void update(float deltaMs) { + if (processes.isEmpty()) { + return; + } + Process activeProcess = processes.peek(); + activeProcess.update(deltaMs); + if (activeProcess.isFinished()) { + processes.remove(); + } + } + + public boolean isFinished() { + return processes.isEmpty(); + } + + public static void updateChains(List processChains, float deltaMs) { + // Remove finished chains. + for (int i = processChains.size() - 1; i >= 0; i--) { + ProcessChain chain = processChains.get(i); + if (chain.isFinished()) { + processChains.remove(i); + } + } + // Update still-running chains. + for (int i = 0; i < processChains.size(); i++) { + processChains.get(i).update(deltaMs); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/RadialGradientTextView.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/RadialGradientTextView.java new file mode 100644 index 000000000..3c678ab87 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/RadialGradientTextView.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.RadialGradient; +import android.graphics.Shader.TileMode; +import android.util.AttributeSet; +import android.widget.TextView; + +/** + * A text view with a radial gradient, used for the score display in game. + */ +public class RadialGradientTextView extends TextView { + private static final int CENTER_COLOR = 0xfffeec51; + private static final int EDGE_COLOR = 0xfffdbe38; + + private RadialGradient textGradient; + + public RadialGradientTextView(Context context) { + this(context, null); + } + + public RadialGradientTextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public RadialGradientTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onDraw(Canvas canvas) { + // Draw the shadow. + getPaint().setShadowLayer(getShadowRadius(), getShadowDx(), getShadowDy(), getShadowColor()); + getPaint().setShader(null); + super.onDraw(canvas); + + // Draw the gradient filled text. + getPaint().clearShadowLayer(); + getPaint().setShader(textGradient); + super.onDraw(canvas); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (w > 0 && h > 0) { + textGradient = new RadialGradient( + w / 2, h / 2, Math.min(w, h) / 2, CENTER_COLOR, EDGE_COLOR, TileMode.CLAMP); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/RectangularInstructionActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/RectangularInstructionActor.java new file mode 100644 index 000000000..a67bbc6da --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/RectangularInstructionActor.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.res.Resources; +import android.graphics.Canvas; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite.AnimatedSpriteListener; + +/** + * An actor that shows instructions for a game. + */ +public class RectangularInstructionActor extends Actor { + + private static final int RECTANGLE_CENTER_X = 257; + private static final int RECTANGLE_CENTER_Y = 343; + + private static final int FRAME_BUBBLE_APPEARS = 2; + + public AnimatedSprite rectangle; + public AnimatedSprite diagram; + private float diagramScale = 1; + private float diagramAlpha = 1; + private boolean animationIsReversed = false; + + /** + * @param diagram Animated sprite showing instructions in a loop. + */ + public RectangularInstructionActor(Resources resources, AnimatedSprite diagram) { + this.rectangle = AnimatedSprite.fromFrames(resources, Sprites.tutoappear_new); + this.diagram = diagram; + + // Off-center anchor point lets us match the rectangle's animation with a simple scale. + diagram.setAnchor(diagram.frameWidth / 2, diagram.frameHeight / 2); + + rectangle.setLoop(false); + rectangle.addListener(new AnimatedSpriteListener() { + @Override + public void onFrame(int index) { + // Scale (and fade) the diagram to match the rectangle. + int maxFrame = rectangle.getNumFrames() - 1; + index = animationIsReversed ? maxFrame - index : index; + float percent = maxFrame == 0 ? 1 : (float) index / maxFrame; + if (index < FRAME_BUBBLE_APPEARS) { + percent = 0; + } + diagramScale = percent; + diagramAlpha = percent; + } + + @Override + public void onFinished() { + if (animationIsReversed) { + hidden = true; + } + } + }); + } + + public void show() { + if (animationIsReversed) { + reverseAnimation(); + } + hidden = false; + rectangle.setFrameIndex(0); + diagramAlpha = 0; + diagramScale = 0; + update(0); + } + + public void hide() { + if (!animationIsReversed) { + reverseAnimation(); + } + rectangle.setFrameIndex(0); + update(0); + } + + private void reverseAnimation() { + rectangle.reverseFrames(); + animationIsReversed = !animationIsReversed; + } + + public void setDiagram(AnimatedSprite diagram) { + diagram.setAnchor(diagram.frameWidth / 2, diagram.frameHeight / 2); + this.diagram = diagram; + } + + public float getScaledWidth() { + return rectangle.frameWidth * scale; + } + + public float getScaledHeight() { + return rectangle.frameHeight * scale; + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + + rectangle.update(deltaMs); + rectangle.setPosition(position.x, position.y); + rectangle.setRotation(rotation); + rectangle.setHidden(hidden); + rectangle.setAlpha(alpha); + rectangle.setScale(scale, scale); + + diagram.update(deltaMs); + // Center diagram in rectangle. + diagram.setPosition(position.x + RECTANGLE_CENTER_X * scale, + position.y + RECTANGLE_CENTER_Y * scale); + diagram.setRotation(rotation); + diagram.setHidden(hidden); + // Diagram has to take both this.alpha and diagramAlpha into account. + diagram.setAlpha(alpha * diagramAlpha); + // Same with scale. + diagram.setScale(scale * diagramScale * 1.3f, scale * diagramScale * 1.3f); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + if (!hidden) { + rectangle.draw(canvas); + diagram.draw(canvas); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ScoreView.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ScoreView.java new file mode 100644 index 000000000..5eb449915 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/ScoreView.java @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Build.VERSION; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.BounceInterpolator; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.Builder; +import com.google.android.apps.santatracker.util.FontHelper; + +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.DEFAULT_DOODLE_NAME; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.GAME_OVER; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.HOME_CLICKED; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.REPLAY_CLICKED; +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.SHARE_CLICKED; + +/** + * Displays the score during the game and shows the end screen when the game is over. + */ +public class ScoreView extends FrameLayout { + private static final String TAG = ScoreView.class.getSimpleName(); + + public interface OnShareClickedListener { + void onShareClicked(); + } + + // Durations of various animations. + private static final int BUMP_MS = 300; // Bump when a point is scored. + private static final int ZOOM_UP_MS = 900; // Zooming score to middle of screen. + private static final int ZOOM_DOWN_MS = 400; // Zooming score to its end position. + private static final int SHARE_FADE_IN_MS = 500; // Fading in the share image. + private static final int SHARE_DROP_MS = 400; // Dropping the share image into place. + private static final int SHARE_Y_OFFSET_PX = -200; // Offset of the share image before it drops. + private static final int BG_FADE_IN_MS = 400; // Fading in the end screen background. + private static final int RESET_FADE_IN_MS = 300; // Fading in the score view when game is reset. + private static final int STAR_BOUNCE_IN_MS = 600; // Bouncing the stars into the end screen. + private static final int STAR_FADE_IN_MS = 500; // Fading the stars into the end screen. + private static final float STAR_BIG_SCALE = 2.0f; + + // The score in the upper-left corner during the game. This also gets zoomed up to the + // middle of the screen at the end of the game. + private TextView currentScore; + + // An invisible placeholder. Lets us use the android layout engine for figuring out where + // the score is positioned on the final screen. At the end of the game, currentScore animates + // from its original position/size to the position/size of finalScorePlaceholder. + private TextView finalScorePlaceholder; + + // An invisible placeholder which is positioned at the center of the screen and is used as the + // intermediate position/size before the score drops into its final position. + private TextView centeredScorePlaceholder; + + // Text that says "Game Over" + private TextView gameOverText; + + // Widgets on the end screen. + private TextView bestScore; + private ImageView shareImage; + private LinearLayout menuItems; + private GameOverlayButton shareButton; + + // A semi-opaque background which darkens the game during the end screen. + private View background; + + // Initial state for the views involved in the end-screen animation, stored so it can be + // restored if "replay" is tapped. + private float currentScoreX = Float.NaN; + private float currentScoreY = Float.NaN; + private int currentScoreMarginStart; + private int currentScoreMarginTop; + private float currentScoreTextSizePx; + private float currentScoreAlpha; + private float finalScoreMaxWidth; + private float finalScoreMaxHeight; + private float centeredScoreMaxWidth; + private float centeredScoreMaxHeight; + private float backgroundAlpha; + + private int mCurrentScoreValue; + + private LinearLayout currentStars; + private RelativeLayout finalStars; + private int filledStarCount; + + private DoodleConfig doodleConfig; + protected PineappleLogger logger; + private boolean canReplay; + + private OnShareClickedListener shareClickedListener; + + /** + * A listener for events which occur from the level finished screen. + */ + public interface LevelFinishedListener { + void onReplay(); + + String gameType(); + float score(); + int shareImageId(); + } + protected LevelFinishedListener listener; + + public ScoreView(Context context, OnShareClickedListener shareClickedListener) { + this(context, (AttributeSet) null); + this.shareClickedListener = shareClickedListener; + } + + public ScoreView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ScoreView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + loadLayout(context); + resetToStartState(); + } + + public void setDoodleConfig(DoodleConfig doodleConfig) { + this.doodleConfig = doodleConfig; + } + + public void setLogger(PineappleLogger logger) { + this.logger = logger; + } + + protected void loadLayout(final Context context) { + setVisibility(View.INVISIBLE); + LayoutInflater inflater = LayoutInflater.from(context); + View view = inflater.inflate(R.layout.score_view, this); + + gameOverText = (TextView) view.findViewById(R.id.text_game_over); + gameOverText.setVisibility(INVISIBLE); + FontHelper.makeLobster(gameOverText, false /* italic */); + + currentScore = (TextView) view.findViewById(R.id.current_score); + // Store these for later so we can put currentScore back where it started after animating it. + currentScoreTextSizePx = currentScore.getTextSize(); + currentScoreAlpha = currentScore.getAlpha(); + currentScore.post(new Runnable() { + @Override + public void run() { + currentScoreX = currentScore.getX(); + currentScoreY = currentScore.getY(); + } + }); + RelativeLayout.LayoutParams params = + (RelativeLayout.LayoutParams) currentScore.getLayoutParams(); + if (VERSION.SDK_INT >= 17) { + currentScoreMarginStart = params.getMarginStart(); + } else { + currentScoreMarginStart = params.leftMargin; + } + currentScoreMarginTop = params.topMargin; + + finalScorePlaceholder = (TextView) view.findViewById(R.id.final_score_placeholder); + finalScorePlaceholder.setVisibility(INVISIBLE); + finalScoreMaxWidth = getResources().getDimension(R.dimen.final_score_max_width); + finalScoreMaxHeight = getResources().getDimension(R.dimen.final_score_max_height); + finalScorePlaceholder.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + } + + @Override + public void afterTextChanged(Editable editable) { + UIUtil.fitToBounds(finalScorePlaceholder, finalScoreMaxWidth, finalScoreMaxHeight); + } + }); + + centeredScorePlaceholder = (TextView) view.findViewById(R.id.centered_score_placeholder); + centeredScorePlaceholder.setVisibility(INVISIBLE); + centeredScoreMaxWidth = getResources().getDimension(R.dimen.centered_score_max_width); + centeredScoreMaxHeight = getResources().getDimension(R.dimen.centered_score_max_height); + centeredScorePlaceholder.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + } + + @Override + public void afterTextChanged(Editable editable) { + UIUtil.fitToBounds(centeredScorePlaceholder, centeredScoreMaxWidth, centeredScoreMaxHeight); + } + }); + + currentStars = (LinearLayout) + view.findViewById(R.id.current_stars); + currentStars.removeAllViews(); // Remove the stickers that are in the XML for testing layout. + finalStars = (RelativeLayout) + view.findViewById(R.id.final_stars); + + bestScore = (TextView) view.findViewById(R.id.best_score); + shareImage = (ImageView) view.findViewById(R.id.share_image); + shareImage.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + replay(); + } + }); + + menuItems = (LinearLayout) view.findViewById(R.id.menu_items); + View replayButton = view.findViewById(R.id.replay_button); + replayButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + replay(); + } + }); + + shareButton = (GameOverlayButton) view.findViewById(R.id.share_button); + shareButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.menu_item_click); + logger.logEvent(new Builder(DEFAULT_DOODLE_NAME, SHARE_CLICKED) + .withEventSubType(listener.gameType()) + .withEventValue1(listener.shareImageId()) + .build()); + + if (shareClickedListener != null) { + shareClickedListener.onShareClicked(); + } + } + }); + + View moreGamesButton = view.findViewById(R.id.menu_button); + moreGamesButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + goToMoreGames(context); + } + }); + background = view.findViewById(R.id.score_view_background); + backgroundAlpha = background.getAlpha(); // Store for later use. + } + + protected void goToMoreGames(Context context) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.menu_item_click); + logger.logEvent(new Builder(DEFAULT_DOODLE_NAME, HOME_CLICKED) + .withEventSubType(listener.gameType()) + .build()); + LaunchDecisionMaker.finishActivity(context); + } + + private void replay() { + if (canReplay && listener != null) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.menu_item_click); + logger.logEvent(new Builder(DEFAULT_DOODLE_NAME, REPLAY_CLICKED) + .withEventSubType(listener.gameType()) + .build()); + + listener.onReplay(); + AndroidUtils.forceScreenToStayOn(getContext()); + } + } + + public void setListener(LevelFinishedListener listener) { + this.listener = listener; + } + + /** + * Updates the best score field on the end screen to display the given best score. + * + * @param newScore The score to be displayed as the best score. + */ + public void updateBestScore(CharSequence newScore) { + bestScore.setText( + AndroidUtils.getText(getResources(), R.string.end_screen_best_score, newScore)); + } + + /** + * Sets the end screen header to the given text. + * + *

This header will be shown in place of the best score.

+ * + * @param text The text to be put into the header. + */ + public void setHeaderText(CharSequence text) { + bestScore.setText(text); + } + + public void updateCurrentScore(CharSequence newScore, boolean shouldBump) { + currentScore.setText(newScore); + finalScorePlaceholder.setText(newScore); + centeredScorePlaceholder.setText(newScore); + if (shouldBump) { + animateBump(currentScore); + } + } + + public void setShareDrawable(Drawable drawable) { + shareImage.setImageDrawable(drawable); + } + + public void clearAllStars() { + currentStars.removeAllViews(); + filledStarCount = 0; + for (int i = 0; i < finalStars.getChildCount(); i++) { + FrameLayout star = (FrameLayout) finalStars.getChildAt(i); + star.findViewById(R.id.fill).setVisibility(INVISIBLE); + } + } + + public void addStar() { + if (filledStarCount < 3) { + filledStarCount++; + int currentStarDimens = (int) AndroidUtils.dipToPixels(40); + addStarToLayout(currentStars, currentStarDimens, LinearLayout.LayoutParams.MATCH_PARENT); + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.ui_positive_sound); + } + } + + public int getStarCount() { + return filledStarCount; + } + + // Width & height are in pixels. + private void addStarToLayout(LinearLayout layout, int width, int height) { + ImageView image = new ImageView(getContext()); + image.setImageResource(R.drawable.pineapple_star_filled); + animateBump(image); + layout.addView(image, new LinearLayout.LayoutParams(width, height)); + } + + public void resetToStartState() { + Log.i(TAG, "Reset to start state"); + currentStars.setVisibility(VISIBLE); + + bestScore.setVisibility(INVISIBLE); + shareImage.setVisibility(INVISIBLE); + menuItems.setVisibility(INVISIBLE); + shareButton.setVisibility(INVISIBLE); + background.setVisibility(INVISIBLE); + finalStars.setVisibility(INVISIBLE); + gameOverText.setVisibility(INVISIBLE); + + if (!Float.isNaN(currentScoreX)) { + currentScore.setX(currentScoreX); + } + if (!Float.isNaN(currentScoreY)) { + currentScore.setY(currentScoreY); + } + currentScore.setTextSize(TypedValue.COMPLEX_UNIT_PX, currentScoreTextSizePx); + RelativeLayout.LayoutParams params = + (RelativeLayout.LayoutParams) currentScore.getLayoutParams(); + + if (VERSION.SDK_INT >= 17) { + params.setMarginStart(currentScoreMarginStart); + } else { + params.leftMargin = currentScoreMarginStart; + } + params.topMargin = currentScoreMarginTop; + + updateCurrentScore(Integer.toString(0), false); + clearAllStars(); + + currentScore.setAlpha(0); + ValueAnimator fadeInCurrentScore = UIUtil.animator(RESET_FADE_IN_MS, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + currentScore.setAlpha((float) valueAnimator.getAnimatedValue("alpha")); + } + }, + UIUtil.floatValue("alpha", 0, currentScoreAlpha) + ); + fadeInCurrentScore.start(); + } + + public void animateToEndState() { + AndroidUtils.allowScreenToTurnOff(getContext()); + Log.i(TAG, "Animate to end state"); + canReplay = false; + setVisibility(View.VISIBLE); + logger.logEvent(new Builder(DEFAULT_DOODLE_NAME, GAME_OVER) + .withEventSubType(listener.gameType()) + .withLatencyMs(PineappleLogTimer.getInstance().timeElapsedMs()) + .withEventValue1(listener.score()) + .withEventValue2(getStarCount()) + .build()); + + // TODO: Fade this out instead of making it invisible (will have to remove + // the layout:alignComponents that attach it current score, else it will move along with the + // score.) + currentStars.setVisibility(INVISIBLE); + + // Initial state: controls & background are visible but alpha = 0 + bestScore.setAlpha(0); + shareImage.setAlpha(0.0f); + background.setAlpha(0); + finalStars.setAlpha(0); + + bestScore.setVisibility(VISIBLE); + shareImage.setVisibility(VISIBLE); + background.setVisibility(VISIBLE); + finalStars.setVisibility(VISIBLE); + gameOverText.setVisibility(VISIBLE); + + // Offset the share image and stars so that they can bounce in. + final float shareImageY = shareImage.getY(); + final float finalStarsY = finalStars.getY(); + shareImage.setY(shareImageY + SHARE_Y_OFFSET_PX); + + + // Zoom the score to center of screen. + // I tried several other ways of doing this animation, none of which worked: + // 1. Using TranslateAnimation & ScaleAnimation instead of .animate(): Positions didn't work + // right when scaling, maybe because these animate how a view is displayed but not the actual + // view properties. + // 2. Using TranslateAnimation & ObjectAnimator: couldn't add ObjectAnimator to the same + // Animation set as TranslateAnimation. + // 3. Using .animate() to get a PropertyAnimator. Couldn't tween textSize without using + // .setUpdateListener, which requires API 19. + // 4. Small textSize, scaling up from 1: Text is blurry at scales > 1. + // 5. Large textSize, scaling up to 1: Final position was wrong, I couldn't figure out why. + // 6. Medium textSize, scaling up to 2.5: Error: font size too large to fit in cache. Tried + // turning off HW accel which fixed the cache errors but positioning was still wrong. + ValueAnimator zoomUp = UIUtil.animator(ZOOM_UP_MS, new ElasticOutInterpolator(0.35f), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + currentScore.setX((float) valueAnimator.getAnimatedValue("x")); + currentScore.setY((float) valueAnimator.getAnimatedValue("y")); + currentScore.setTextSize(TypedValue.COMPLEX_UNIT_PX, + (float) valueAnimator.getAnimatedValue("textSize")); + RelativeLayout.LayoutParams params = + (RelativeLayout.LayoutParams) currentScore.getLayoutParams(); + if (VERSION.SDK_INT >= 17) { + params.setMarginStart((int) (float) valueAnimator.getAnimatedValue("marginStart")); + } else { + params.leftMargin = (int) (float) valueAnimator.getAnimatedValue("marginStart"); + } + params.topMargin = (int) (float) valueAnimator.getAnimatedValue("topMargin"); + currentScore.setAlpha((float) valueAnimator.getAnimatedValue("currentScoreAlpha")); + } + }, + UIUtil.floatValue("x", currentScore.getX(), centeredScorePlaceholder.getX()), + UIUtil.floatValue("y", currentScore.getY(), centeredScorePlaceholder.getY()), + UIUtil.floatValue("textSize", + currentScoreTextSizePx, centeredScorePlaceholder.getTextSize()), + UIUtil.floatValue("marginStart", currentScoreMarginStart, 0), + UIUtil.floatValue("topMargin", currentScoreMarginTop, 0), + UIUtil.floatValue("currentScoreAlpha", currentScoreAlpha, 1) + ); + + // Zoom the score up to its final position. + ValueAnimator zoomBackDown = UIUtil.animator(ZOOM_DOWN_MS, new BounceInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + currentScore.setX((float) valueAnimator.getAnimatedValue("x")); + currentScore.setY((float) valueAnimator.getAnimatedValue("y")); + currentScore.setTextSize(TypedValue.COMPLEX_UNIT_PX, + (float) valueAnimator.getAnimatedValue("textSize")); + } + }, + UIUtil.floatValue("x", centeredScorePlaceholder.getX(), finalScorePlaceholder.getX()), + UIUtil.floatValue("y", centeredScorePlaceholder.getY(), finalScorePlaceholder.getY()), + UIUtil.floatValue("textSize", + centeredScorePlaceholder.getTextSize(), finalScorePlaceholder.getTextSize()) + ); + + ValueAnimator fadeInBackground = UIUtil.animator(BG_FADE_IN_MS, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + background.setAlpha((float) valueAnimator.getAnimatedValue("bgAlpha")); + } + }, + UIUtil.floatValue("bgAlpha", 0, backgroundAlpha) + ); + + ValueAnimator fadeInBestScore = UIUtil.animator(BG_FADE_IN_MS, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + bestScore.setAlpha((float) valueAnimator.getAnimatedValue("bgAlpha")); + } + }, + UIUtil.floatValue("bgAlpha", 0, backgroundAlpha) + ); + + ValueAnimator fadeInMenuItems = UIUtil.animator(BG_FADE_IN_MS, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float alpha = (float) valueAnimator.getAnimatedValue("alpha"); + menuItems.setAlpha(alpha); + shareButton.setAlpha(alpha); + + } + }, + UIUtil.floatValue("alpha", 0, 1) + ); + fadeInMenuItems.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + // Don't set menu items to be visible until the animation starts so that they aren't + // clickable until they start to appear. + menuItems.setVisibility(VISIBLE); + menuItems.setAlpha(0); + + shareButton.setVisibility(VISIBLE); + shareButton.setAlpha(0); + + canReplay = true; + } + }); + + ValueAnimator fadeInShareImageAndFinalStars = UIUtil.animator(SHARE_FADE_IN_MS, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float alpha = (float) valueAnimator.getAnimatedValue("alpha"); + shareImage.setAlpha(alpha); + finalStars.setAlpha(alpha); + } + }, + UIUtil.floatValue("alpha", 0, 1) + ); + + ValueAnimator dropShareImageAndFinalStars = UIUtil.animator(SHARE_DROP_MS, + new BounceInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float yOffset = (float) valueAnimator.getAnimatedValue("yOffset"); + shareImage.setY(shareImageY + yOffset); + } + }, + UIUtil.floatValue("yOffset", SHARE_Y_OFFSET_PX, 0) + ); + + AnimatorSet animations = new AnimatorSet(); + + int numStars = finalStars.getChildCount(); + ValueAnimator bounce = null; + long starStartDelay = ZOOM_UP_MS + SHARE_FADE_IN_MS + SHARE_DROP_MS / 2; + for (int i = 0; i < filledStarCount; i++) { + FrameLayout star = (FrameLayout) finalStars.getChildAt(numStars - i - 1); + ValueAnimator fade = getStarFadeIn((ImageView) star.findViewById(R.id.fill)); + bounce = getStarBounceIn((ImageView) star.findViewById(R.id.fill)); + animations.play(fade).after(starStartDelay + STAR_FADE_IN_MS * i); + animations.play(bounce).after(starStartDelay + STAR_FADE_IN_MS * i); + } + if (bounce != null) { + animations.play(fadeInMenuItems).after(bounce); + } else { + animations.play(fadeInMenuItems).after(starStartDelay + STAR_FADE_IN_MS); + } + animations.play(fadeInBackground).with(zoomUp); + animations.play(fadeInBestScore).after(fadeInBackground); + animations.play(zoomBackDown).after(zoomUp); + animations.play(fadeInShareImageAndFinalStars).after(zoomUp); + animations.play(dropShareImageAndFinalStars).after(fadeInShareImageAndFinalStars); + animations.start(); + } + + private ValueAnimator getStarFadeIn(final ImageView star) { + star.setAlpha(0.0f); + star.setVisibility(VISIBLE); + ValueAnimator fadeIn = UIUtil.animator(STAR_FADE_IN_MS, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float alpha = (float) valueAnimator.getAnimatedValue("alpha"); + star.setAlpha(alpha); + } + }, + UIUtil.floatValue("alpha", 0, 1) + ); + fadeIn.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.ui_positive_sound); + } + }); + return fadeIn; + } + + private ValueAnimator getStarBounceIn(final ImageView star) { + return UIUtil.animator(STAR_BOUNCE_IN_MS, + new BounceInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float scale = (float) valueAnimator.getAnimatedValue("scale"); + star.setScaleX(scale); + star.setScaleY(scale); + } + }, + UIUtil.floatValue("scale", STAR_BIG_SCALE, 1) + ); + } + + private void animateBump(final View view) { + ValueAnimator tween = UIUtil.animator(BUMP_MS, new OvershootInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float scale = (float) valueAnimator.getAnimatedValue("scale"); + view.setScaleX(scale); + view.setScaleY(scale); + } + }, + UIUtil.floatValue("scale", 1.5f, 1)); + tween.start(); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/SpriteActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/SpriteActor.java new file mode 100644 index 000000000..960f7f031 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/SpriteActor.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.graphics.Canvas; + +/** + * A generic actor class for game objects. + */ +public class SpriteActor extends Actor { + public static final String TYPE = "Sprite actor"; + + public AnimatedSprite sprite; + private final String type; + // If true, then this.scale will be ignored. This would allow you to call sprite.setScale(x, y) + // without the effect getting overwritten. + public boolean ignoreScale = false; + + public SpriteActor(AnimatedSprite sprite, Vector2D position, Vector2D velocity) { + this(sprite, position, velocity, TYPE); + } + + public SpriteActor(AnimatedSprite sprite, Vector2D position, Vector2D velocity, String type) { + super(position, velocity); + this.sprite = sprite; + this.type = type; + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + sprite.update(deltaMs); + } + + @Override + public void draw(Canvas canvas) { + draw(canvas, 0, 0, sprite.frameWidth * scale, sprite.frameHeight * scale); + } + + public void draw( + Canvas canvas, float xOffset, float yOffset, float width, float height) { + if (!hidden) { + sprite.setRotation(rotation); + sprite.setPosition(position.x + xOffset, position.y + yOffset); + if (!ignoreScale) { + sprite.setScale(width / sprite.frameWidth, height / sprite.frameHeight); + } + sprite.setAlpha(alpha); + sprite.draw(canvas); + } + } + + @Override + public String getType() { + return type; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Sprites.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Sprites.java new file mode 100644 index 000000000..14b291324 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Sprites.java @@ -0,0 +1,729 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import com.google.android.apps.santatracker.doodles.R; + +/** + * Frame data for all the sprites. + */ +public final class Sprites { + + public static int[] debug_marker = { + R.drawable.debug_marker, + }; + public static int[] empty_frame = { + R.drawable.empty_frame, + }; + public static int[] google = { + R.drawable.google, + }; + public static int[] ic_launcher = { + R.drawable.ic_launcher, + }; + public static int[] intro = { + R.drawable.intro, + }; + + public static int[] pineapple_star_filled = { + R.drawable.pineapple_star_filled, + }; + + public static int[] snowball = { + R.drawable.snowball01, + R.drawable.snowball02, + R.drawable.snowball03, + R.drawable.snowball04, + R.drawable.snowball05, + R.drawable.snowball06, + R.drawable.snowball07, + R.drawable.snowball08, + }; + + public static int[] melon_shadow = { + R.drawable.melon_shadow, + }; + + public static int[] snowballrun_running_snowman_opponent = { + R.drawable.snowballrun_running_snowman_opponent_01, + R.drawable.snowballrun_running_snowman_opponent_02, + R.drawable.snowballrun_running_snowman_opponent_03, + R.drawable.snowballrun_running_snowman_opponent_04, + R.drawable.snowballrun_running_snowman_opponent_05, + R.drawable.snowballrun_running_snowman_opponent_06, + R.drawable.snowballrun_running_snowman_opponent_07, + R.drawable.snowballrun_running_snowman_opponent_08, + R.drawable.snowballrun_running_snowman_opponent_09, + R.drawable.snowballrun_running_snowman_opponent_10, + R.drawable.snowballrun_running_snowman_opponent_11, + R.drawable.snowballrun_running_snowman_opponent_12, + R.drawable.snowballrun_running_snowman_opponent_13, + R.drawable.snowballrun_running_snowman_opponent_14, + R.drawable.snowballrun_running_snowman_opponent_15, + R.drawable.snowballrun_running_snowman_opponent_16, + }; + + public static int[] running_apricot_squish = { + R.drawable.snowballrun_snowman_squished_05, + R.drawable.snowballrun_snowman_squished_06, + R.drawable.snowballrun_snowman_squished_07, + R.drawable.snowballrun_snowman_squished_08, + }; + + public static int[] snowballrunner_background = { + R.drawable.snowballrunner_background, + }; + + public static int[] snowball_runner_trees1 = { + R.drawable.snowball_runner_trees1, + }; + + public static int[] snowball_runner_trees2 = { + R.drawable.snowball_runner_trees2, + }; + + public static int[] running_button = { + R.drawable.running_button_00, + R.drawable.running_button_01, + R.drawable.running_button_02, + }; + + public static int[] snowballrun_elf_squish = { + R.drawable.snowballrun_elf_squished_01, + R.drawable.snowballrun_elf_squished_02, + R.drawable.snowballrun_elf_squished_03, + R.drawable.snowballrun_elf_squished_04, + }; + + public static int[] running_finish_line = { + R.drawable.running_finish_line, + }; + + public static int[] snowballrun_running_elf_opponent = { + R.drawable.snowballrun_running_elf_opponent_01, + R.drawable.snowballrun_running_elf_opponent_02, + R.drawable.snowballrun_running_elf_opponent_03, + R.drawable.snowballrun_running_elf_opponent_04, + R.drawable.snowballrun_running_elf_opponent_05, + R.drawable.snowballrun_running_elf_opponent_06, + R.drawable.snowballrun_running_elf_opponent_07, + R.drawable.snowballrun_running_elf_opponent_08, + R.drawable.snowballrun_running_elf_opponent_09, + R.drawable.snowballrun_running_elf_opponent_10, + R.drawable.snowballrun_running_elf_opponent_11, + R.drawable.snowballrun_running_elf_opponent_12, + R.drawable.snowballrun_running_elf_opponent_13, + R.drawable.snowballrun_running_elf_opponent_14, + R.drawable.snowballrun_running_elf_opponent_15, + R.drawable.snowballrun_running_elf_opponent_16, + }; + + public static int[] running_elfopponent_squish = { + R.drawable.snowballrun_elfopponent_squished_05, + R.drawable.snowballrun_elfopponent_squished_06, + R.drawable.snowballrun_elfopponent_squished_07, + R.drawable.snowballrun_elfopponent_squished_08, + }; + + public static int[] snowballrun_running_reindeer_opponent = { + R.drawable.snowballrun_running_reindeer_opponent_01, + R.drawable.snowballrun_running_reindeer_opponent_02, + R.drawable.snowballrun_running_reindeer_opponent_03, + R.drawable.snowballrun_running_reindeer_opponent_04, + R.drawable.snowballrun_running_reindeer_opponent_05, + R.drawable.snowballrun_running_reindeer_opponent_06, + R.drawable.snowballrun_running_reindeer_opponent_07, + R.drawable.snowballrun_running_reindeer_opponent_08, + R.drawable.snowballrun_running_reindeer_opponent_09, + R.drawable.snowballrun_running_reindeer_opponent_10, + R.drawable.snowballrun_running_reindeer_opponent_11, + R.drawable.snowballrun_running_reindeer_opponent_12, + R.drawable.snowballrun_running_reindeer_opponent_13, + R.drawable.snowballrun_running_reindeer_opponent_14, + R.drawable.snowballrun_running_reindeer_opponent_15, + R.drawable.snowballrun_running_reindeer_opponent_16, + }; + + public static int[] snowballrun_reindeer_squish = { + R.drawable.snowballrun_reindeer_squished_01, + R.drawable.snowballrun_reindeer_squished_02, + R.drawable.snowballrun_reindeer_squished_03, + R.drawable.snowballrun_reindeer_squished_04, + }; + + public static int[] running_powerup = { + R.drawable.running_powerup_00, + R.drawable.running_powerup_01, + R.drawable.running_powerup_02, + R.drawable.running_powerup_03, + R.drawable.running_powerup_04, + R.drawable.running_powerup_05, + R.drawable.running_powerup_06, + R.drawable.running_powerup_07, + }; + + public static int[] snowballrun_running_losing = { + R.drawable.snowballrun_running_losing01, + R.drawable.snowballrun_running_losing02, + R.drawable.snowballrun_running_losing03, + R.drawable.snowballrun_running_losing04, + R.drawable.snowballrun_running_losing05, + R.drawable.snowballrun_running_losing06, + R.drawable.snowballrun_running_losing07, + R.drawable.snowballrun_running_losing08, + R.drawable.snowballrun_running_losing09, + R.drawable.snowballrun_running_losing10, + R.drawable.snowballrun_running_losing11, + R.drawable.snowballrun_running_losing12, + R.drawable.snowballrun_running_losing13, + R.drawable.snowballrun_running_losing14, + R.drawable.snowballrun_running_losing15, + R.drawable.snowballrun_running_losing16, + }; + + public static int[] snowballrun_running_normal = { + R.drawable.snowballrun_running_normal01, + R.drawable.snowballrun_running_normal02, + R.drawable.snowballrun_running_normal03, + R.drawable.snowballrun_running_normal04, + R.drawable.snowballrun_running_normal05, + R.drawable.snowballrun_running_normal06, + R.drawable.snowballrun_running_normal07, + R.drawable.snowballrun_running_normal08, + R.drawable.snowballrun_running_normal09, + R.drawable.snowballrun_running_normal10, + R.drawable.snowballrun_running_normal11, + R.drawable.snowballrun_running_normal12, + R.drawable.snowballrun_running_normal13, + R.drawable.snowballrun_running_normal14, + R.drawable.snowballrun_running_normal15, + R.drawable.snowballrun_running_normal16, + }; + + public static int[] snowballrun_running_sidestep = { + R.drawable.snowballrun_sidestep, + }; + + public static int[] snowballrun_running_appearing = { + R.drawable.snowballrun_running_appearing_01, + R.drawable.snowballrun_running_appearing_02, + R.drawable.snowballrun_running_appearing_03, + R.drawable.snowballrun_running_appearing_04, + R.drawable.snowballrun_running_appearing_05, + R.drawable.snowballrun_running_appearing_06, + R.drawable.snowballrun_running_appearing_07, + R.drawable.snowballrun_running_appearing_08, + R.drawable.snowballrun_running_appearing_09, + R.drawable.snowballrun_running_appearing_10, + R.drawable.snowballrun_running_appearing_11, + R.drawable.snowballrun_running_appearing_12, + }; + + public static int[] penguin_swim_banner = { + R.drawable.penguin_swim_banner, + }; + + public static int[] penguin_swim_dazed = { + R.drawable.penguin_swim_dazed_01, + R.drawable.penguin_swim_dazed_02, + R.drawable.penguin_swim_dazed_03, + R.drawable.penguin_swim_dazed_04, + R.drawable.penguin_swim_dazed_05, + R.drawable.penguin_swim_dazed_06, + R.drawable.penguin_swim_dazed_07, + R.drawable.penguin_swim_dazed_08, + R.drawable.penguin_swim_dazed_09, + R.drawable.penguin_swim_dazed_10, + R.drawable.penguin_swim_dazed_11, + R.drawable.penguin_swim_dazed_12, + R.drawable.penguin_swim_dazed_13, + R.drawable.penguin_swim_dazed_14, + R.drawable.penguin_swim_dazed_15, + R.drawable.penguin_swim_dazed_16, + R.drawable.penguin_swim_dazed_17, + R.drawable.penguin_swim_dazed_18, + R.drawable.penguin_swim_dazed_19, + R.drawable.penguin_swim_dazed_20, + R.drawable.penguin_swim_dazed_21, + }; + + public static int[] penguin_swim_descending = { + R.drawable.penguin_swim_descending_01, + R.drawable.penguin_swim_descending_02, + R.drawable.penguin_swim_descending_03, + R.drawable.penguin_swim_descending_04, + R.drawable.penguin_swim_descending_05, + R.drawable.penguin_swim_descending_06, + R.drawable.penguin_swim_descending_07, + R.drawable.penguin_swim_descending_08, + R.drawable.penguin_swim_descending_09, + }; + + public static int[] penguin_swim_elf = { + R.drawable.penguin_swim_elf_01, + R.drawable.penguin_swim_elf_02, + R.drawable.penguin_swim_elf_03, + R.drawable.penguin_swim_elf_04, + R.drawable.penguin_swim_elf_05, + R.drawable.penguin_swim_elf_06, + R.drawable.penguin_swim_elf_07, + R.drawable.penguin_swim_elf_08, + R.drawable.penguin_swim_elf_09, + R.drawable.penguin_swim_elf_10, + R.drawable.penguin_swim_elf_11, + R.drawable.penguin_swim_elf_12, + R.drawable.penguin_swim_elf_13, + R.drawable.penguin_swim_elf_14, + R.drawable.penguin_swim_elf_15, + }; + + public static int[] penguin_swim_frozen = { + R.drawable.penguin_swim_frozen_01, + R.drawable.penguin_swim_frozen_02, + R.drawable.penguin_swim_frozen_03, + R.drawable.penguin_swim_frozen_04, + R.drawable.penguin_swim_frozen_05, + R.drawable.penguin_swim_frozen_06, + R.drawable.penguin_swim_frozen_07, + R.drawable.penguin_swim_frozen_08, + R.drawable.penguin_swim_frozen_09, + R.drawable.penguin_swim_frozen_10, + R.drawable.penguin_swim_frozen_11, + R.drawable.penguin_swim_frozen_12, + R.drawable.penguin_swim_frozen_13, + R.drawable.penguin_swim_frozen_14, + R.drawable.penguin_swim_frozen_15, + R.drawable.penguin_swim_frozen_16, + R.drawable.penguin_swim_frozen_17, + R.drawable.penguin_swim_frozen_18, + R.drawable.penguin_swim_frozen_19, + R.drawable.penguin_swim_frozen_20, + R.drawable.penguin_swim_frozen_21, + R.drawable.penguin_swim_frozen_22, + R.drawable.penguin_swim_frozen_23, + R.drawable.penguin_swim_frozen_24, + R.drawable.penguin_swim_frozen_25, + R.drawable.penguin_swim_frozen_26, + R.drawable.penguin_swim_frozen_27, + R.drawable.penguin_swim_frozen_28, + R.drawable.penguin_swim_frozen_29, + }; + + public static int[] penguin_swim_ice = { + R.drawable.penguin_swim_ice_01, + R.drawable.penguin_swim_ice_02, + R.drawable.penguin_swim_ice_03, + R.drawable.penguin_swim_ice_04, + R.drawable.penguin_swim_ice_05, + R.drawable.penguin_swim_ice_06, + R.drawable.penguin_swim_ice_07, + R.drawable.penguin_swim_ice_08, + R.drawable.penguin_swim_ice_09, + R.drawable.penguin_swim_ice_10, + R.drawable.penguin_swim_ice_11, + R.drawable.penguin_swim_ice_12, + R.drawable.penguin_swim_ice_13, + R.drawable.penguin_swim_ice_14, + R.drawable.penguin_swim_ice_15, + }; + + public static int[] penguin_swim_idle = { + R.drawable.penguin_swim_start_01, + R.drawable.penguin_swim_start_02, + R.drawable.penguin_swim_start_03, + R.drawable.penguin_swim_start_04, + R.drawable.penguin_swim_start_05, + R.drawable.penguin_swim_start_06, + R.drawable.penguin_swim_start_07, + R.drawable.penguin_swim_start_08, + }; + + public static int[] penguin_swim_start = { + R.drawable.penguin_swim_start_09, + R.drawable.penguin_swim_start_10, + R.drawable.penguin_swim_start_11, + R.drawable.penguin_swim_start_12, + R.drawable.penguin_swim_start_13, + R.drawable.penguin_swim_start_14, + R.drawable.penguin_swim_start_15, + R.drawable.penguin_swim_start_16, + }; + + public static int[] penguin_swim_canegrab = { + R.drawable.penguin_swim_canegrab_01, + R.drawable.penguin_swim_canegrab_02, + R.drawable.penguin_swim_canegrab_03, + R.drawable.penguin_swim_canegrab_04, + R.drawable.penguin_swim_canegrab_05, + R.drawable.penguin_swim_canegrab_06, + R.drawable.penguin_swim_canegrab_07, + R.drawable.penguin_swim_canegrab_08, + R.drawable.penguin_swim_canegrab_09, + R.drawable.penguin_swim_canegrab_10, + R.drawable.penguin_swim_canegrab_11, + R.drawable.penguin_swim_canegrab_12, + R.drawable.penguin_swim_canegrab_13, + R.drawable.penguin_swim_canegrab_14, + R.drawable.penguin_swim_canegrab_15, + R.drawable.penguin_swim_canegrab_16, + R.drawable.penguin_swim_canegrab_17, + R.drawable.penguin_swim_canegrab_18, + R.drawable.penguin_swim_canegrab_19, + R.drawable.penguin_swim_canegrab_20, + R.drawable.penguin_swim_canegrab_21, + R.drawable.penguin_swim_canegrab_22, + R.drawable.penguin_swim_canegrab_23, + R.drawable.penguin_swim_canegrab_24, + R.drawable.penguin_swim_canegrab_25, + R.drawable.penguin_swim_canegrab_26, + R.drawable.penguin_swim_canegrab_27, + R.drawable.penguin_swim_canegrab_28, + R.drawable.penguin_swim_canegrab_29, + R.drawable.penguin_swim_canegrab_30, + }; + + public static int[] swimming_rings = { + R.drawable.swimming_rings_00, + R.drawable.swimming_rings_01, + R.drawable.swimming_rings_02, + R.drawable.swimming_rings_03, + R.drawable.swimming_rings_04, + R.drawable.swimming_rings_05, + R.drawable.swimming_rings_06, + R.drawable.swimming_rings_07, + R.drawable.swimming_rings_08, + R.drawable.swimming_rings_09, + }; + + public static int[] penguin_swim_ascending = { + R.drawable.penguin_swim_ascending_01, + R.drawable.penguin_swim_ascending_02, + R.drawable.penguin_swim_ascending_03, + R.drawable.penguin_swim_ascending_04, + R.drawable.penguin_swim_ascending_05, + R.drawable.penguin_swim_ascending_06, + R.drawable.penguin_swim_ascending_07, + R.drawable.penguin_swim_ascending_08, + R.drawable.penguin_swim_ascending_09, + }; + + public static int[] penguin_swim_candy = { + R.drawable.penguin_swim_candy_04, + }; + + public static int[] penguin_swim_swimming = { + R.drawable.penguin_swim_swimming_01, + R.drawable.penguin_swim_swimming_02, + R.drawable.penguin_swim_swimming_03, + R.drawable.penguin_swim_swimming_04, + R.drawable.penguin_swim_swimming_05, + R.drawable.penguin_swim_swimming_06, + R.drawable.penguin_swim_swimming_07, + R.drawable.penguin_swim_swimming_08, + R.drawable.penguin_swim_swimming_09, + R.drawable.penguin_swim_swimming_10, + R.drawable.penguin_swim_swimming_11, + R.drawable.penguin_swim_swimming_12, + R.drawable.penguin_swim_swimming_13, + R.drawable.penguin_swim_swimming_14, + R.drawable.penguin_swim_swimming_15, + R.drawable.penguin_swim_swimming_16, + }; + + public static int[] penguin_swim_swimmingunderwater = { + R.drawable.penguin_swim_swimmingunderwater_01, + R.drawable.penguin_swim_swimmingunderwater_02, + R.drawable.penguin_swim_swimmingunderwater_03, + R.drawable.penguin_swim_swimmingunderwater_04, + R.drawable.penguin_swim_swimmingunderwater_05, + R.drawable.penguin_swim_swimmingunderwater_06, + R.drawable.penguin_swim_swimmingunderwater_07, + R.drawable.penguin_swim_swimmingunderwater_08, + R.drawable.penguin_swim_swimmingunderwater_09, + R.drawable.penguin_swim_swimmingunderwater_10, + R.drawable.penguin_swim_swimmingunderwater_11, + R.drawable.penguin_swim_swimmingunderwater_12, + R.drawable.penguin_swim_swimmingunderwater_13, + R.drawable.penguin_swim_swimmingunderwater_14, + R.drawable.penguin_swim_swimmingunderwater_15, + R.drawable.penguin_swim_swimmingunderwater_16, + }; + + public static int[] tutoappear_new = { + R.drawable.tutoappear_new_00, + R.drawable.tutoappear_new_01, + R.drawable.tutoappear_new_02, + R.drawable.tutoappear_new_03, + R.drawable.tutoappear_new_04, + R.drawable.tutoappear_new_05, + }; + + public static int[] tutorial_running = { + R.drawable.snowballrun_tutorials_01, + R.drawable.snowballrun_tutorials_02, + R.drawable.snowballrun_tutorials_03, + R.drawable.snowballrun_tutorials_04, + R.drawable.snowballrun_tutorials_05, + R.drawable.snowballrun_tutorials_06, + R.drawable.snowballrun_tutorials_07, + R.drawable.snowballrun_tutorials_08, + R.drawable.snowballrun_tutorials_09, + R.drawable.snowballrun_tutorials_10, + R.drawable.snowballrun_tutorials_11, + R.drawable.snowballrun_tutorials_12, + R.drawable.snowballrun_tutorials_13, + R.drawable.snowballrun_tutorials_14, + R.drawable.snowballrun_tutorials_15, + R.drawable.snowballrun_tutorials_16, + R.drawable.snowballrun_tutorials_17, + R.drawable.snowballrun_tutorials_18, + }; + public static int[] tutorial_swimming = { + R.drawable.penguin_swim_tutorials_01, + R.drawable.penguin_swim_tutorials_02, + R.drawable.penguin_swim_tutorials_03, + R.drawable.penguin_swim_tutorials_04, + R.drawable.penguin_swim_tutorials_05, + R.drawable.penguin_swim_tutorials_06, + R.drawable.penguin_swim_tutorials_07, + R.drawable.penguin_swim_tutorials_08, + }; + + public static int[] present_throw_tutorials = { + R.drawable.present_throw_tutorials_01, + R.drawable.present_throw_tutorials_02, + R.drawable.present_throw_tutorials_03, + R.drawable.present_throw_tutorials_04, + R.drawable.present_throw_tutorials_05, + R.drawable.present_throw_tutorials_06, + R.drawable.present_throw_tutorials_07, + R.drawable.present_throw_tutorials_08, + R.drawable.present_throw_tutorials_09, + R.drawable.present_throw_tutorials_10, + R.drawable.present_throw_tutorials_11, + R.drawable.present_throw_tutorials_12, + R.drawable.present_throw_tutorials_13, + R.drawable.present_throw_tutorials_14, + }; + + public static int[] present_throw_def_green_left = { + R.drawable.present_throw_blocker_green_01, + R.drawable.present_throw_blocker_green_02, + R.drawable.present_throw_blocker_green_03, + R.drawable.present_throw_blocker_green_04, + R.drawable.present_throw_blocker_green_05, + R.drawable.present_throw_blocker_green_06, + R.drawable.present_throw_blocker_green_07, + R.drawable.present_throw_blocker_green_08, + }; + + public static int[] present_throw_def_green_right = { + R.drawable.present_throw_blocker_green_09, + R.drawable.present_throw_blocker_green_10, + R.drawable.present_throw_blocker_green_11, + R.drawable.present_throw_blocker_green_12, + R.drawable.present_throw_blocker_green_13, + R.drawable.present_throw_blocker_green_14, + R.drawable.present_throw_blocker_green_15, + R.drawable.present_throw_blocker_green_16, + }; + + public static int[] present_throw_def_green_emerge = { + R.drawable.present_throw_newblocker_green_01, + R.drawable.present_throw_newblocker_green_02, + R.drawable.present_throw_newblocker_green_03, + R.drawable.present_throw_newblocker_green_04, + R.drawable.present_throw_newblocker_green_05, + R.drawable.present_throw_newblocker_green_06, + R.drawable.present_throw_newblocker_green_07, + R.drawable.present_throw_newblocker_green_08, + R.drawable.present_throw_newblocker_green_09, + R.drawable.present_throw_newblocker_green_10, + R.drawable.present_throw_newblocker_green_11, + R.drawable.present_throw_newblocker_green_12, + }; + + public static int[] present_throw_def_green_blocking = { + R.drawable.present_throw_blocking_green_01, + R.drawable.present_throw_blocking_green_02, + R.drawable.present_throw_blocking_green_03, + R.drawable.present_throw_blocking_green_04, + R.drawable.present_throw_blocking_green_05, + R.drawable.present_throw_blocking_green_06, + R.drawable.present_throw_blocking_green_07, + R.drawable.present_throw_blocking_green_08, + R.drawable.present_throw_blocking_green_09, + R.drawable.present_throw_blocking_green_10, + R.drawable.present_throw_blocking_green_11, + R.drawable.present_throw_blocking_green_12, + }; + + public static int[] present_throw_def_red_left = { + R.drawable.present_throw_blocker_red_01, + R.drawable.present_throw_blocker_red_02, + R.drawable.present_throw_blocker_red_03, + R.drawable.present_throw_blocker_red_04, + R.drawable.present_throw_blocker_red_05, + R.drawable.present_throw_blocker_red_06, + R.drawable.present_throw_blocker_red_07, + R.drawable.present_throw_blocker_red_08, + }; + + public static int[] present_throw_def_red_right = { + R.drawable.present_throw_blocker_red_09, + R.drawable.present_throw_blocker_red_10, + R.drawable.present_throw_blocker_red_11, + R.drawable.present_throw_blocker_red_12, + R.drawable.present_throw_blocker_red_13, + R.drawable.present_throw_blocker_red_14, + R.drawable.present_throw_blocker_red_15, + R.drawable.present_throw_blocker_red_16, + }; + + public static int[] present_throw_def_red_emerge = { + R.drawable.present_throw_newblocker_red_01, + R.drawable.present_throw_newblocker_red_02, + R.drawable.present_throw_newblocker_red_03, + R.drawable.present_throw_newblocker_red_04, + R.drawable.present_throw_newblocker_red_05, + R.drawable.present_throw_newblocker_red_06, + R.drawable.present_throw_newblocker_red_07, + R.drawable.present_throw_newblocker_red_08, + R.drawable.present_throw_newblocker_red_09, + R.drawable.present_throw_newblocker_red_10, + R.drawable.present_throw_newblocker_red_11, + R.drawable.present_throw_newblocker_red_12, + }; + + public static int[] present_throw_def_red_blocking = { + R.drawable.present_throw_blocking_red_01, + R.drawable.present_throw_blocking_red_02, + R.drawable.present_throw_blocking_red_03, + R.drawable.present_throw_blocking_red_04, + R.drawable.present_throw_blocking_red_05, + R.drawable.present_throw_blocking_red_06, + R.drawable.present_throw_blocking_red_07, + R.drawable.present_throw_blocking_red_08, + R.drawable.present_throw_blocking_red_09, + R.drawable.present_throw_blocking_red_10, + R.drawable.present_throw_blocking_red_11, + R.drawable.present_throw_blocking_red_12, + }; + + public static int[] present_throw_def_orange_left = { + R.drawable.present_throw_blocker_orange_01, + R.drawable.present_throw_blocker_orange_02, + R.drawable.present_throw_blocker_orange_03, + R.drawable.present_throw_blocker_orange_04, + R.drawable.present_throw_blocker_orange_05, + R.drawable.present_throw_blocker_orange_06, + R.drawable.present_throw_blocker_orange_07, + R.drawable.present_throw_blocker_orange_08, + }; + + public static int[] present_throw_def_orange_right = { + R.drawable.present_throw_blocker_orange_09, + R.drawable.present_throw_blocker_orange_10, + R.drawable.present_throw_blocker_orange_11, + R.drawable.present_throw_blocker_orange_12, + R.drawable.present_throw_blocker_orange_13, + R.drawable.present_throw_blocker_orange_14, + R.drawable.present_throw_blocker_orange_15, + R.drawable.present_throw_blocker_orange_16, + }; + + public static int[] present_throw_def_orange_emerge = { + R.drawable.present_throw_newblocker_orange_01, + R.drawable.present_throw_newblocker_orange_02, + R.drawable.present_throw_newblocker_orange_03, + R.drawable.present_throw_newblocker_orange_04, + R.drawable.present_throw_newblocker_orange_05, + R.drawable.present_throw_newblocker_orange_06, + R.drawable.present_throw_newblocker_orange_07, + R.drawable.present_throw_newblocker_orange_08, + R.drawable.present_throw_newblocker_orange_09, + R.drawable.present_throw_newblocker_orange_10, + R.drawable.present_throw_newblocker_orange_11, + R.drawable.present_throw_newblocker_orange_12, + }; + + public static int[] present_throw_def_orange_blocking = { + R.drawable.present_throw_blocking_orange_01, + R.drawable.present_throw_blocking_orange_02, + R.drawable.present_throw_blocking_orange_03, + R.drawable.present_throw_blocking_orange_04, + R.drawable.present_throw_blocking_orange_05, + R.drawable.present_throw_blocking_orange_06, + R.drawable.present_throw_blocking_orange_07, + R.drawable.present_throw_blocking_orange_08, + R.drawable.present_throw_blocking_orange_09, + R.drawable.present_throw_blocking_orange_10, + R.drawable.present_throw_blocking_orange_11, + R.drawable.present_throw_blocking_orange_12, + }; + + public static int[] present_throw_reloading = { + R.drawable.present_throw_reloading_01, + R.drawable.present_throw_reloading_02, + R.drawable.present_throw_reloading_03, + }; + + public static int[] present_throw_celebrate = { + R.drawable.present_throw_celebrating_01, + R.drawable.present_throw_celebrating_02, + }; + + public static int[] present_throw_idle = { + R.drawable.present_throw_throwing_01, + }; + + public static int[] present_throw_santabag = { + R.drawable.present_throw_santabag, + }; + + public static int[] present_throw_thrownpresent = { + R.drawable.present_throw_thrownpresent_orange, + }; + + public static int[] present_throw_floor = { + R.drawable.present_throw_floor, + }; + + public static int[] present_throw_elfbag = { + R.drawable.present_throw_elfbag, + }; + + public static int[] orange_present_falling = { + R.drawable.orange_present1, + R.drawable.orange_present2, + R.drawable.orange_present3, + R.drawable.orange_present4, + }; + + public static int[] waterpolo_target = { + R.drawable.waterpolo_target, + }; + + public static int[] present_throw_throwing = { + R.drawable.present_throw_throwing_01, + R.drawable.present_throw_throwing_02, + R.drawable.present_throw_throwing_03, + R.drawable.present_throw_throwing_04, + R.drawable.present_throw_throwing_05, + R.drawable.present_throw_throwing_06, + }; + +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/StarView.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/StarView.java new file mode 100644 index 000000000..5a728a5e2 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/StarView.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.FrameLayout; +import com.google.android.apps.santatracker.doodles.R; + +/** + * A view for the stars on the end screen. This is just a wrapper class so that we can contain + * star layout behavior in a single layout file instead of having to specify each one individually. + */ +public class StarView extends FrameLayout { + + public StarView(Context context) { + this(context, null); + } + + public StarView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public StarView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + inflate(context, R.layout.star_view, this); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/TextActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/TextActor.java new file mode 100644 index 000000000..107763969 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/TextActor.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.res.AssetManager; +import android.graphics.BlurMaskFilter; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.text.TextPaint; + +/** + * Draws text on the screen. + */ +public class TextActor extends Actor { + private static final String TAG = TextActor.class.getSimpleName(); + + private String text; + private Paint paint; + private Rect bounds = new Rect(); + private float previousAlpha; + + public boolean hidden; + private boolean centeredVertically; + + public TextActor(String text) { + this.paint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); + // Set text size using px instead of dip so that the scale of text needed to match a bitmap + // sprite stays the same across devices. + paint.setTextSize(12); + setColor(Color.BLACK); + setText(text); + } + + public void setText(String text) { + this.text = text; + paint.getTextBounds(text, 0, text.length(), bounds); + } + + public String getText() { + return text; + } + + /** + * @return The scaled width of the text. + */ + public float getWidth() { + return bounds.width() * scale; + } + + /** + * @return The scaled height of the text. + */ + public float getHeight() { + return bounds.height() * scale; + } + + public void scaleToFitScreen(int screenWidth, int screenHeight) { + scale = Math.min( + screenWidth / bounds.width(), + screenHeight / bounds.height()); + } + + public void setColor(int color) { + paint.setColor(color); + previousAlpha = paint.getAlpha() / 255f; + } + + public void setFont(AssetManager assetManager, String fontPath) { + Typeface typeface = Typeface.createFromAsset(assetManager, fontPath); + paint.setTypeface(typeface); + } + + public void enableBlur(float blurRadius) { + paint.setMaskFilter(new BlurMaskFilter(blurRadius, BlurMaskFilter.Blur.NORMAL)); + } + + public void alignCenter() { + paint.setTextAlign(Align.CENTER); + } + + public void setBold(boolean bold) { + paint.setTypeface(bold ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT); + } + + public void centerVertically(boolean center) { + this.centeredVertically = center; + } + + @Override + public void draw(Canvas canvas) { + if (previousAlpha != alpha) { + previousAlpha = alpha; + paint.setAlpha(Math.round(alpha * 255)); + } + if (hidden) { + return; + } + float yOffset = centeredVertically ? -getHeight() / 2 : 0; + canvas.save(); + canvas.scale(scale, scale); + // 1. drawText has y=0 at the baseline of the text. To make this work like other actors, y=0 + // should be the top of the bounding box, so add bounds.top to y. + // 2. drawText also has rounding error on the (x, y) coordinates, which makes text jitter + // around if you are tweening scale, so use canvas.translate() to position instead. + canvas.translate(position.x / scale, (position.y + yOffset) / scale - bounds.top); + canvas.drawText(text, 0, 0, paint); + canvas.restore(); + + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Tween.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Tween.java new file mode 100644 index 000000000..7a5230f8b --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Tween.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * Base class for tweens. Handles the basic bookkeeping, then delegates to subclasses via + * updateValues() for updating specific values. + */ +public abstract class Tween { + protected float durationSeconds = 0; + private float elapsedSeconds = 0; + private float percentDone = 0; + + public Tween(float durationSeconds) { + this.durationSeconds = durationSeconds; + } + + /** + * @return true if update should continue to be called, false if tween is finished and should + * be removed. + */ + public boolean update(double deltaMs) { + boolean wasFinished = isFinished(); + if (wasFinished) { + return false; + } + elapsedSeconds += deltaMs / 1000f; + percentDone = elapsedSeconds / durationSeconds; + if (percentDone > 1) { + percentDone = 1; + } + updateValues(percentDone); + if (!wasFinished && isFinished()) { + onFinish(); + } + return !isFinished(); + } + + /** + * Subclasses should define this method to update their value(s) every frame. Suggested + * implementation: + * currentValue = interpolator.getValue(percentDone, startValue, endValue); + */ + protected abstract void updateValues(float percentDone); + + /** + * Subclasses can override this to execute code when the Tween finishes. + */ + protected void onFinish() { + + } + + // Cancels the tween. Doesn't reset values back to their starting value or the final value. Just + // leaves state where it is and stops updating. onFinish will be called. + public void cancel() { + if (!isFinished()) { + // Advance elapsedSeconds and percentDone to the end so future update calls won't do anything. + elapsedSeconds = durationSeconds; + percentDone = 1; + onFinish(); + } + } + + public boolean isFinished() { + return percentDone >= 1; + } + + public float durationSeconds() { + return durationSeconds; + } + + public Process asProcess() { + return new Process() { + @Override + public void updateLogic(float deltaMs) { + Tween.this.update(deltaMs); + } + + @Override + public boolean isFinished() { + return Tween.this.isFinished(); + } + }; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/TweenManager.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/TweenManager.java new file mode 100644 index 000000000..8facd6be6 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/TweenManager.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import java.util.ArrayList; +import java.util.List; + +/** + * Manages a list of tweens, taking care of removing them when they are done, and adding them (even + * in the middle of iterating over the list of tweens). + */ +public class TweenManager { + private final List tweens = new ArrayList<>(); + private final List incomingTweens = new ArrayList<>(); + private boolean shouldRemoveAll = false; + + public void update(float deltaMs) { + // First, check whether removeAll was called since the last update. + if (shouldRemoveAll) { + finishRemovingAll(); + return; + } + try { + // Move everything from incomingTweens to tweens (before iterating over tweens) + for (int i = 0; i < incomingTweens.size(); i++) { // Avoiding iterator to avoid garbage. + tweens.add(incomingTweens.get(i)); + } + incomingTweens.clear(); + + // Now iterate through tweens. + for (int i = tweens.size() - 1; i >= 0; i--) { // Avoiding iterator to avoid garbage. + Tween tween = tweens.get(i); + boolean finished = tween == null || !tween.update(deltaMs); + if (shouldRemoveAll) { + finishRemovingAll(); + return; + } + if (finished) { + tweens.remove(i); + } + } + } catch (Exception e) { // do nothing + } + } + + public void add(Tween tween) { + if (tween.durationSeconds() < 0) { + throw new IllegalArgumentException("Tween duration should not be negative"); + } + // Don't add to main list of tweens directly, to avoid ConcurrentModificationException. + incomingTweens.add(tween); + } + + /** + * Removes all the tweens at the next possible opportunity. This isn't synchronous, but will + * happen before any more tween.update calls occur. + */ + public void removeAll() { + // Remove incoming tweens immediately. No risk of removing while iterating for these, and we + // shouldn't clear this later in finishRemovingAll in case more have been added since then, + // so clear immediately. + incomingTweens.clear(); + + // There is a risk of removing while iterating for tweens though, so set a flag instead of + // immediately clearing it. + shouldRemoveAll = true; + } + + private void finishRemovingAll() { + // Don't clear incomingTweens here, on the assumption that A) removeAll already cleared it + // and B) there's a possibility more have been added since then, and they *shouldn't* get + // cleared. + tweens.clear(); + shouldRemoveAll = false; + } + +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIRefreshHandler.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIRefreshHandler.java new file mode 100644 index 000000000..41b702005 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIRefreshHandler.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.os.Handler; +import android.os.Message; +import android.view.View; + +/** + * Handler subclass which handles refreshing the UI. + */ +public class UIRefreshHandler extends Handler { + private static final int REFRESH_UI_MESSAGE = 0; + // Refresh the UI at a higher rate so that we can keep the drawing pipeline filled. + private static final int UI_INTERVAL_MS = 1000 / 120; + + // Toggled in start/stop, and used in handleMessage to conditionally schedule the next refresh. + private volatile boolean running; + + private View view; + + public UIRefreshHandler() { + } + + public void start(View view) { + running = true; + this.view = view; + sendEmptyMessage(REFRESH_UI_MESSAGE); + } + + public void stop() { + running = false; + view = null; + removeMessages(REFRESH_UI_MESSAGE); + } + + @Override + public void handleMessage(Message msg) { + if (running) { + if (msg.what == REFRESH_UI_MESSAGE) { + long timeBeforeDraw = System.currentTimeMillis(); + if (view != null) { + // invalidate + view.invalidate(); + } + // Wait different amounts of time depending on how much time the draw took. + // Wait at least 1ms to avoid a mysterious memory leak. + long timeToDraw = System.currentTimeMillis() - timeBeforeDraw; + sendEmptyMessageDelayed(REFRESH_UI_MESSAGE, Math.max(1, UI_INTERVAL_MS - timeToDraw)); + } + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIUtil.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIUtil.java new file mode 100644 index 000000000..8470fd712 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIUtil.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.PropertyValuesHolder; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.widget.TextView; + +/** + * Utility class for working with Android views. + */ +public final class UIUtil { + + private UIUtil() { + // Don't instantiate this class. + } + + /** + * Shortcut to create a ValuesAnimator with the given configuration. + */ + public static ValueAnimator animator(long durationMillis, TimeInterpolator interpolator, + AnimatorUpdateListener listener, PropertyValuesHolder... propertyValuesHolders) { + ValueAnimator tween = ValueAnimator.ofPropertyValuesHolder(propertyValuesHolders); + tween.setDuration(durationMillis); + tween.setInterpolator(interpolator); + tween.addUpdateListener(listener); + return tween; + } + + /** + * Shortcut for making a PropertyValuesHolder for floats. + */ + public static PropertyValuesHolder floatValue(String name, float start, float end) { + return PropertyValuesHolder.ofFloat(name, start, end); + } + + public static void fadeOutAndHide(final View v, long durationMs, float startAlpha, + final Runnable onFinishRunnable) { + + if (v.getVisibility() != View.VISIBLE) { + return; // Already hidden. + } + ValueAnimator fadeOut = animator(durationMs, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + v.setAlpha((float) valueAnimator.getAnimatedValue("alpha")); + } + }, + floatValue("alpha", startAlpha, 0) + ); + fadeOut.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + v.setVisibility(View.INVISIBLE); + if (onFinishRunnable != null) { + onFinishRunnable.run(); + } + } + }); + fadeOut.start(); + } + public static void fadeOutAndHide(final View v, long durationMs, float startAlpha) { + fadeOutAndHide(v, durationMs, startAlpha, null); + } + + public static void fadeOutAndHide(final View v, long durationMs) { + fadeOutAndHide(v, durationMs, 1); + } + + public static void showAndFadeIn(final View v, long durationMs, float endAlpha) { + if (v.getVisibility() == View.VISIBLE) { + return; // Already visible. + } + v.setAlpha(0); + v.setVisibility(View.VISIBLE); + + ValueAnimator fadeIn = animator(durationMs, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + v.setAlpha((float) valueAnimator.getAnimatedValue("alpha")); + } + }, + floatValue("alpha", 0, endAlpha) + ); + fadeIn.start(); + } + + public static void showAndFadeIn(final View v, long durationMs) { + showAndFadeIn(v, durationMs, 1); + } + + public static void fitToBounds(TextView textView, float widthPx, float heightPx) { + textView.measure(0, 0); + float currentWidthPx = textView.getMeasuredWidth(); + float currentHeightPx = textView.getMeasuredHeight(); + float textSize = textView.getTextSize(); + + float scale = Math.min(widthPx / currentWidthPx, heightPx / currentHeightPx); + textView.setTextSize(textSize * scale); + } + + /** + * Translates in Y from startPercent to endPercent (expecting 0 for 0%, 1 for 100%). + * Hides at the end based on hideOnEnd. + */ + public static void panUpAndHide(final View v, float startPercent, float endPercent, + long durationMs, boolean hideOnEnd) { + if (v.getVisibility() != View.VISIBLE) { + return; // Already hidden. + } + ValueAnimator panUp = animator(durationMs, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + v.setY(((float) valueAnimator.getAnimatedValue()) * v.getHeight()); + } + }, + floatValue("translateY", startPercent, endPercent) + ); + if (hideOnEnd) { + panUp.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + v.setVisibility(View.INVISIBLE); + } + }); + } + panUp.start(); + } + +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Vector2D.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Vector2D.java new file mode 100644 index 000000000..3dfbd1692 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/Vector2D.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import java.util.Stack; + +/** + * A basic 2D vector, with convenience functions to interact with it. + */ +public class Vector2D { + private static final int MAX_POOL_SIZE = 50; + private static final Stack vectorPool = new Stack<>(); + + public float x; + public float y; + + private Vector2D(float x, float y) { + this.x = x; + this.y = y; + } + + public static Vector2D get() { + return get(0, 0); + } + + public static synchronized Vector2D get(float x, float y) { + if (!vectorPool.isEmpty()) { + Vector2D v = vectorPool.pop(); + v.set(x, y); + return v; + } else { + return new Vector2D(x, y); + } + } + + public static Vector2D get(Vector2D other) { + return get(other.x, other.y); + } + + /** + * Release this vector back into the vector pool. Note that, once this has been called, the + * vector object may be re-used, and there is no guarantee that the released object will act as + * expected. + */ + public void release() { + if (vectorPool.size() < MAX_POOL_SIZE) { + vectorPool.push(this); + } + } + + public Vector2D normalize() { + float length = getLength(); + if (length == 0) { + set(0, 0); + } else { + set (x / length, y / length); + } + return this; + } + + public Vector2D toNormal() { + return set(y, -x).normalize(); + } + + public float getLength() { + return getLength(x, y); + } + + public static float getLength(float x, float y) { + return (float) Math.sqrt(x * x + y * y); + } + + public Vector2D add(Vector2D rhs) { + set(this.x + rhs.x, this.y + rhs.y); + return this; + } + + public Vector2D add(float x, float y) { + set(this.x + x, this.y + y); + return this; + } + + public Vector2D subtract(Vector2D rhs) { + set(this.x - rhs.x, this.y - rhs.y); + return this; + } + + public Vector2D subtract(float x, float y) { + set(this.x - x, this.y - y); + return this; + } + + public Vector2D scale(float factor) { + set(this.x * factor, this.y * factor); + return this; + } + + public float dot(Vector2D rhs) { + return x * rhs.x + y * rhs.y; + } + + public Vector2D rotate(float radians) { + double cos = Math.cos(radians); + double sin = Math.sin(radians); + set((float) (x * cos - y * sin), (float) (x * sin + y * cos)); + return this; + } + + public Vector2D set(Vector2D other) { + x = other.x; + y = other.y; + return this; + } + + public Vector2D set(float x, float y) { + this.x = x; + this.y = y; + return this; + } + + @Override + public String toString() { + return "(" + x + ", " + y + ")"; + } + + public float distanceTo(Vector2D other) { + float dx = x - other.x; + float dy = y - other.y; + return (float) Math.sqrt(dx * dx + dy * dy); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/WaitProcess.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/WaitProcess.java new file mode 100644 index 000000000..204232df8 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/WaitProcess.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +/** + * A process which just waits for the specified amount of time. + */ +public class WaitProcess extends Process { + private long elapsedMs; + private long durationMs; + + public WaitProcess(long durationMs) { + this.durationMs = durationMs; + this.elapsedMs = 0; + } + + @Override + public void updateLogic(float deltaMs) { + elapsedMs += deltaMs; + } + + @Override + public boolean isFinished() { + return elapsedMs >= durationMs; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/WatermelonBaseActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/WatermelonBaseActor.java new file mode 100644 index 000000000..4e7d7ab87 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/WatermelonBaseActor.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared; + +import android.content.res.Resources; +import android.graphics.Canvas; + +/** + * The base watermelon actor used by both the golf and running game. + */ +public class WatermelonBaseActor extends Actor { + + public AnimatedSprite bodySprite; + public AnimatedSprite shadowSprite; + + public WatermelonBaseActor(Resources resources) { + bodySprite = AnimatedSprite.fromFrames(resources, Sprites.snowball); + shadowSprite = AnimatedSprite.fromFrames(resources, Sprites.melon_shadow); + + bodySprite.setAnchor(bodySprite.frameWidth / 2, bodySprite.frameHeight / 2); + shadowSprite.setAnchor(shadowSprite.frameWidth * 0.5f, shadowSprite.frameHeight * 0.35f); + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + + bodySprite.update(deltaMs); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + drawSprite(shadowSprite, canvas); + drawSprite(bodySprite, canvas); + } + + private void drawSprite(AnimatedSprite sprite, Canvas canvas) { + sprite.setPosition(position.x, position.y); + sprite.setScale(scale, scale); + sprite.draw(canvas); + } + + private void drawSpriteYInverted(AnimatedSprite sprite, Canvas canvas) { + sprite.setPosition(position.x, position.y); + sprite.setScale(scale, -scale); + sprite.draw(canvas); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Polygon.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Polygon.java new file mode 100644 index 000000000..fd250e482 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Polygon.java @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared.physics; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; + +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.tilt.Constants; +import com.google.android.apps.santatracker.doodles.tilt.SwimmingFragment; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +/** + * A general polygon class (either concave or convex) which can tell whether or not a point + * is inside of it. + * + *

NOTE: vertex winding order affects the normals of the line segments, and can affect things + * like collisions. A non-inverted (normals pointed out) polygon should have its vertices wound + * clockwise.

+ * + */ +public class Polygon { + private static final String TAG = Polygon.class.getSimpleName(); + private static final float EPSILON = 0.0001f; + private static final float VERTEX_RADIUS = 10; + + private Paint vertexPaint; + private Paint midpointPaint; + private Paint linePaint; + + public List vertices; + public List normals; + public Vector2D min; + public Vector2D max; + + private boolean isInverted; + + public Polygon(List vertices) { + this.vertices = vertices; + min = Vector2D.get(0, 0); + max = Vector2D.get(0, 0); + + vertexPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + vertexPaint.setColor(Color.RED); + + midpointPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + midpointPaint.setColor(Color.GREEN); + midpointPaint.setAlpha(100); + + linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + linePaint.setColor(Color.WHITE); + linePaint.setStrokeWidth(5); + + updateExtents(); + updateInversionStatus(); + calculateNormals(); + } + + public void updateExtents() { + min.set(this.vertices.get(0)); + max.set(this.vertices.get(0)); + for (int i = 0; i < vertices.size(); i++) { + Vector2D point = vertices.get(i); + min.x = Math.min(min.x, point.x); + min.y = Math.min(min.y, point.y); + max.x = Math.max(max.x, point.x); + max.y = Math.max(max.y, point.y); + } + } + + public void calculateNormals() { + normals = new ArrayList<>(); + for (int i = 0; i < vertices.size(); i++) { + Vector2D start = vertices.get(i); + Vector2D end = vertices.get((i + 1) % vertices.size()); + normals.add(Vector2D.get(end).subtract(start).toNormal()); + } + } + + public float getWidth() { + return max.x - min.x; + } + + public float getHeight() { + return max.y - min.y; + } + + public void moveTo(float x, float y) { + float deltaX = x - min.x; + float deltaY = y - min.y; + move(deltaX, deltaY); + } + + public void move(float x, float y) { + for (int i = 0; i < vertices.size(); i++) { + Vector2D vertex = vertices.get(i); + vertex.x += x; + vertex.y += y; + } + // Rather than update the extents by checking all of the vertices here, we can just update them + // manually (they will move by the same amount as the rest of the vertices). + min.x += x; + min.y += y; + max.x += x; + max.y += y; + } + + public void moveVertex(int index, Vector2D delta) { + Vector2D vertex = vertices.get(index); + vertex.x += delta.x; + vertex.y += delta.y; + updateExtents(); + updateInversionStatus(); + } + + public void addVertexAfter(int index) { + int nextIndex = index < vertices.size() - 1 ? index + 1 : 0; + Vector2D newVertex = Util.getMidpoint(vertices.get(index), vertices.get(nextIndex)); + vertices.add(nextIndex, newVertex); + updateExtents(); + calculateNormals(); + } + + public void removeVertexAt(int index) { + vertices.remove(index); + updateExtents(); + } + + /** + * Return the index of the vertex selected by the given point. + * + * @param point the point at which to check for a selected vertex. + * @param scale the scale of the world, for slackening the selection radius if needed. + * @return the index of the selected vertex, or -1 if no vertex was selected. + */ + public int getSelectedIndex(Vector2D point, float scale) { + for (int i = 0; i < vertices.size(); i++) { + Vector2D vertex = vertices.get(i); + if (point.distanceTo(vertex) + < Math.max(Constants.SELECTION_RADIUS, Constants.SELECTION_RADIUS / scale)) { + return i; + } + } + return -1; + } + + public int getMidpointIndex(Vector2D point, float scale) { + for (int i = 0; i < vertices.size(); i++) { + Vector2D start = vertices.get(i); + Vector2D end = vertices.get(i < vertices.size() - 1 ? i + 1 : 0); + if (point.distanceTo(Util.getMidpoint(start, end)) + < Math.max(Constants.SELECTION_RADIUS, Constants.SELECTION_RADIUS / scale)) { + return i; + } + } + return -1; + } + + /** + * Return whether or not this polygon is inverted (i.e., whether or not the polygon has a normal + * which points inwards. + * + * @return true if the polygon is inverted, false otherwise. + */ + public boolean isInverted() { + return isInverted; + } + + /** + * Calculate whether or not this polygon is inverted. This checks to see if the point which is one + * unit in the normal direction on the polygon's first segment is within the bounds of the + * polygon. If this is the case, then the normal points inwards and the polygon is inverted. + * Otherwise, the polygon is not inverted. + * + *

Note: This doesn't deal with polygons which are partially inverted. These sorts of polygons + * should be avoided, as they will break this function.

+ */ + private void updateInversionStatus() { + Vector2D start = vertices.get(0); + Vector2D end = vertices.get(1); + Vector2D midpoint = Util.getMidpoint(start, end); + Vector2D normal = Vector2D.get(end).subtract(start).toNormal().scale(0.1f); + + if (contains(midpoint.add(normal))) { + isInverted = true; + } else { + isInverted = false; + } + normal.release(); + midpoint.release(); + } + + /** + * Return whether or not this polygon's collision boundaries contain a given point. A polygon + * contains a point iff the point is contained within the polygon's collision boundaries, + * regardless of the direction of the polygon's normals. + * + * @param point the point to check + * @return true if this polygon contains the point, false otherwise. + */ + public boolean contains(Vector2D point) { + // If the bounding box doesn't contain the point, we don't need to do any more calculations. + if (!Util.pointIsWithinBounds(min, max, point)) { + return false; + } + + // Cast vertical ray from point to outside polygon and counting crossings. Point is in polygon + // iff number of edges crossed is odd. + + // Find a Y value that's definitely outside the polygon. + float maxY = max.y + 1; + Vector2D outsidePoint = Vector2D.get(point.x, maxY); + + // Check how many edges lie between (p.x, p.y) and (p.x, maxY). + boolean inside = false; + for (int i = 0; i < vertices.size(); i++) { + Vector2D p1 = vertices.get(i); + Vector2D p2; + if (i < vertices.size() - 1) { + p2 = vertices.get(i + 1); + } else { + p2 = vertices.get(0); + } + + // First check endpoints. Hitting left-most point counts, hitting right-most + // doesn't (to weed out case where ray hits 2 lines at their joining vertex) } + if (p1.y >= point.y && Math.abs(p1.x - point.x) <= EPSILON) { + if (p2.x >= point.x) { + inside = !inside; + } + continue; + } else if (p2.y >= point.y && Math.abs(p2.x - point.x) <= EPSILON) { + if (p1.x >= point.x) { + inside = !inside; + } + continue; + } + + // Now check for intersection. + if (Util.lineSegmentIntersectsLineSegment(p1, p2, point, outsidePoint)) { + inside = !inside; + } + } + outsidePoint.release(); + return inside; + } + + public LineSegment getIntersectingLineSegment(Vector2D p, Vector2D q) { + for (int i = 0; i < vertices.size(); i++) { + Vector2D p1 = vertices.get(i); + Vector2D p2; + if (i < vertices.size() - 1) { + p2 = vertices.get(i + 1); + } else { + p2 = vertices.get(0); + } + + if (Util.lineSegmentIntersectsLineSegment(p1, p2, p, q)) { + return new LineSegment(p1, p2); + } + } + return null; + } + + public void draw(Canvas canvas) { + if (!(SwimmingFragment.editorMode)) { + return; + } + for (int i = 0; i < vertices.size(); i++) { + Vector2D start = vertices.get(i); + Vector2D end; + if (i < vertices.size() - 1) { + end = vertices.get(i + 1); + } else { + end = vertices.get(0); + } + Vector2D midpoint = Util.getMidpoint(start, end); + Vector2D normal = Vector2D.get(end).subtract(start).toNormal(); + + canvas.drawCircle(start.x, start.y, VERTEX_RADIUS, vertexPaint); + canvas.drawLine(start.x, start.y, end.x, end.y, linePaint); + canvas.drawCircle(midpoint.x, midpoint.y, VERTEX_RADIUS / 2, midpointPaint); + canvas.drawLine(midpoint.x, midpoint.y, + midpoint.x + normal.x * 20, midpoint.y + normal.y * 20, linePaint); + + midpoint.release(); + normal.release(); + } + } + + public void setPaintColors(int vertexColor, int lineColor, int midpointColor) { + vertexPaint.setColor(vertexColor); + linePaint.setColor(lineColor); + midpointPaint.setColor(midpointColor); + } + + public JSONArray toJSON() throws JSONException { + JSONArray json = new JSONArray(); + for (int i = 0; i < vertices.size(); i++) { + JSONObject vertexJson = new JSONObject(); + Vector2D vertex = vertices.get(i); + vertexJson.put("x", (double) vertex.x); + vertexJson.put("y", (double) vertex.y); + json.put(vertexJson); + } + return json; + } + + public static Polygon fromJSON(JSONArray json) throws JSONException { + List vertices = new ArrayList<>(); + for (int i = 0; i < json.length(); i++) { + JSONObject vertexJson = json.getJSONObject(i); + Vector2D vertex = + Vector2D.get((float) vertexJson.getDouble("x"), (float) vertexJson.getDouble("y")); + vertices.add(vertex); + } + return new Polygon(vertices); + } + + /** + * A class to specify the starting and ending point of a line segment. Currently only used in + * determining which line segment is being collided with, so we can determine the normal vector. + */ + public static class LineSegment { + public Vector2D start; + public Vector2D end; + + public LineSegment(Vector2D start, Vector2D end) { + this.start = start; + this.end = end; + } + + public Vector2D getDirection() { + return Vector2D.get(end).subtract(start); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Util.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Util.java new file mode 100644 index 000000000..e55ae0627 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Util.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared.physics; + +import com.google.android.apps.santatracker.doodles.shared.Vector2D; + +import java.util.List; + +/** + * A utility class for physics-related functions. + */ +public final class Util { + private static final String TAG = Util.class.getSimpleName(); + private static final float EPSILON = 0.0001f; + private static final int COLLINEAR = 0; + private static final int CLOCKWISE = 1; + private static final int COUNTERCLOCKWISE = 2; + + private Util() { + // Don't allow instantiation of this class. + } + + /** + * Return whether the point is within the axis-aligned rectangle defined by p and q. + * + * @param p first bounding point. + * @param q second bounding point. + * @param point the point to check. + * @return true if point is within the bounds defined by p and q, false otherwise. + */ + public static boolean pointIsWithinBounds(Vector2D p, Vector2D q, Vector2D point) { + return point.x >= Math.min(p.x, q.x) && point.x <= Math.max(p.x, q.x) + && point.y >= Math.min(p.y, q.y) && point.y <= Math.max(p.y, q.y); + } + + /** + * Find the orientation of the ordered triplet of points. They are either clockwise, + * counterclockwise, or collinear. + * Implementation based on: http://goo.gl/a44iML + */ + private static int orientation(Vector2D p, Vector2D q, Vector2D r) { + float value = (q.y - p.y) * (r.x - q.x) - (r.y - q.y) * (q.x - p.x); + + // Use this instead of Math.abs(value) here because it is faster. + if (value < EPSILON && value > -EPSILON) { + return COLLINEAR; + } + return value > 0 ? CLOCKWISE : COUNTERCLOCKWISE; + } + + /** + * Compute whether or not lines 1 and 2 intersect. + * Implementation based on: + * http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ + * + * @param p1 The starting point of line 1 + * @param q1 The ending point of line 1 + * @param p2 The starting point of line 2 + * @param q2 The ending point of line 2 + * @return true if 1 and 2 intersect, false otherwise. + */ + public static boolean lineSegmentIntersectsLineSegment( + Vector2D p1, Vector2D q1, Vector2D p2, Vector2D q2) { + int o1 = orientation(p1, q1, p2); + int o2 = orientation(p1, q1, q2); + int o3 = orientation(p2, q2, p1); + int o4 = orientation(p2, q2, q1); + + // General case + if (o1 != o2 && o3 != o4) { + return true; + } + + // Special cases + if (o1 == 0 && pointIsWithinBounds(p1, q1, p2) + || o2 == 0 && pointIsWithinBounds(p1, q1, q2) + || o3 == 0 && pointIsWithinBounds(p2, q2, p1) + || o4 == 0 && pointIsWithinBounds(p2, q2, q1)) { + return true; + } + return false; + } + + /** + * Return whether or not two rectangles intersect. This uses a basic form of the separating axis + * theorem which should be faster than running a full polygon-to-polygon check. + * + * @return true if the rectangles intersect, false otherwise. + */ + public static boolean rectIntersectsRect(float x1, float y1, float w1, float h1, + float x2, float y2, float w2, float h2) { + float halfWidth1 = w1 / 2; + float halfWidth2 = w2 / 2; + float halfHeight1 = h1 / 2; + float halfHeight2 = h2 / 2; + + float horizontalThreshold = halfWidth1 + halfWidth2; + float verticalThreshold = halfHeight1 + halfHeight2; + + float horizontalDistance = Math.abs(x1 + halfWidth1 - (x2 + halfWidth2)); + float verticalDistance = Math.abs(y1 + halfHeight1 - (y2 + halfHeight2)); + + return horizontalDistance < horizontalThreshold && verticalDistance < verticalThreshold; + } + + /** + * Use the separating axis theorem to determine whether or not two convex polygons intersect. + * + * @return true if the polygons intersect, false otherwise. + */ + public static boolean convexPolygonIntersectsConvexPolygon(Polygon p1, Polygon p2) { + for (int i = 0; i < p1.normals.size(); i++) { + Vector2D normal = p1.normals.get(i); + float p1Min = getMinProjectionInDirection(normal, p1.vertices); + float p1Max = getMaxProjectionInDirection(normal, p1.vertices); + float p2Min = getMinProjectionInDirection(normal, p2.vertices); + float p2Max = getMaxProjectionInDirection(normal, p2.vertices); + if (p1Max < p2Min || p2Max < p1Min) { + // If there is a separating axis, these polygons do not intersect. + return false; + } + } + for (int i = 0; i < p2.normals.size(); i++) { + Vector2D normal = p2.normals.get(i); + float p1Min = getMinProjectionInDirection(normal, p1.vertices); + float p1Max = getMaxProjectionInDirection(normal, p1.vertices); + float p2Min = getMinProjectionInDirection(normal, p2.vertices); + float p2Max = getMaxProjectionInDirection(normal, p2.vertices); + if (p1Max < p2Min || p2Max < p1Min) { + // If there is a separating axis, these polygons do not intersect. + return false; + } + } + return true; + } + + private static float getMaxProjectionInDirection(Vector2D direction, List points) { + float max = points.get(0).dot(direction); + for (int i = 1; i < points.size(); i++) { + max = Math.max(max, points.get(i).dot(direction)); + } + return max; + } + + private static float getMinProjectionInDirection(Vector2D direction, List points) { + float min = points.get(0).dot(direction); + for (int i = 1; i < points.size(); i++) { + min = Math.min(min, points.get(i).dot(direction)); + } + return min; + } + + public static Vector2D getMidpoint(Vector2D p, Vector2D q) { + float deltaX = q.x - p.x; + float deltaY = q.y - p.y; + return Vector2D.get(p.x + deltaX / 2, p.y + deltaY / 2); + } + + public static float clamp(float value, float lowerBound, float upperBound) { + return Math.max(lowerBound, Math.min(value, upperBound)); + } + + public static int clamp(int value, int lowerBound, int upperBound) { + return Math.max(lowerBound, Math.min(value, upperBound)); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/LoopingMediaPlayer.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/LoopingMediaPlayer.java new file mode 100644 index 000000000..01b64afb9 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/LoopingMediaPlayer.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared.sound; + +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.media.MediaPlayer; +import android.media.MediaPlayer.OnCompletionListener; +import android.util.Log; + +/** + * A wrapper around a MediaPlayer which allows for a gapless, looping track. + */ +public class LoopingMediaPlayer implements PineappleMediaPlayer { + private static final String TAG = LoopingMediaPlayer.class.getSimpleName(); + + private MediaPlayer currentPlayer; + private MediaPlayer nextPlayer; + private AssetFileDescriptor soundFileDescriptor; + private float volume; + + public static LoopingMediaPlayer create(Context context, int resId) { + return new LoopingMediaPlayer(context, resId); + } + + private LoopingMediaPlayer(Context context, int resId) { + soundFileDescriptor = context.getResources().openRawResourceFd(resId); + + currentPlayer = MediaPlayer.create(context, resId); + nextPlayer = MediaPlayer.create(context, resId); + currentPlayer.setNextMediaPlayer(nextPlayer); + + currentPlayer.setOnCompletionListener(new OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + try { + currentPlayer.reset(); + currentPlayer.setDataSource(soundFileDescriptor.getFileDescriptor(), + soundFileDescriptor.getStartOffset(), soundFileDescriptor.getLength()); + currentPlayer.prepare(); + nextPlayer.setNextMediaPlayer(currentPlayer); + } catch (Exception e) { + Log.w(TAG, "onCompletion: unexpected exception", e); + } + } + }); + nextPlayer.setOnCompletionListener(new OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + try { + nextPlayer.reset(); + nextPlayer.setDataSource(soundFileDescriptor.getFileDescriptor(), + soundFileDescriptor.getStartOffset(), soundFileDescriptor.getLength()); + nextPlayer.prepare(); + currentPlayer.setNextMediaPlayer(nextPlayer); + } catch (Exception e) { + Log.w(TAG, "onCompletion: unexpected exception", e); + } + } + }); + } + + @Override + public void start() { + try { + currentPlayer.start(); + } catch (IllegalStateException e) { + Log.w(TAG, "start() failed: " + e.toString()); + } + } + + @Override + public boolean isPlaying() { + return currentPlayer.isPlaying() || nextPlayer.isPlaying(); + } + + @Override + public void pause() { + try { + currentPlayer.pause(); + nextPlayer.pause(); + } catch (Exception e) { + Log.w(TAG, "pause() failed: " + e.toString()); + } + } + + @Override + public MediaPlayer getMediaPlayer() { + return currentPlayer; + } + + @Override + public void setNextMediaPlayer(MediaPlayer mediaPlayer) { + try { + currentPlayer.setNextMediaPlayer(mediaPlayer); + } catch (Exception e) { + Log.w(TAG, "setNextMediaPlayer() failed: ", e); + } + } + + @Override + public void setVolume(float volume) { + this.volume = volume; + try { + currentPlayer.setVolume(volume, volume); + nextPlayer.setVolume(volume, volume); + } catch (Exception e) { + Log.w(TAG, "setVolume() failed: ", e); + } + } + + @Override + public void mute() { + try { + currentPlayer.setVolume(0, 0); + nextPlayer.setVolume(0, 0); + } catch (Exception e) { + Log.w(TAG, "mute() failed: ", e); + } + } + + @Override + public void unmute() { + try { + currentPlayer.setVolume(volume, volume); + nextPlayer.setVolume(volume, volume); + } catch (Exception e) { + Log.w(TAG, "unmute() failed: ", e); + } + } + + @Override + public void release() { + try { + currentPlayer.release(); + nextPlayer.release(); + soundFileDescriptor.close(); + } catch (Exception e) { + Log.w(TAG, "release() failed: ", e); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/PineappleMediaPlayer.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/PineappleMediaPlayer.java new file mode 100644 index 000000000..e7d88d873 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/PineappleMediaPlayer.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared.sound; + +import android.media.MediaPlayer; + +/** + * A wrapper around MediaPlayer so that we can extend its behavior. + */ +public interface PineappleMediaPlayer { + void start(); + boolean isPlaying(); + void pause(); + MediaPlayer getMediaPlayer(); + void setNextMediaPlayer(MediaPlayer mediaPlayer); + void setVolume(float volume); + void mute(); + void unmute(); + void release(); +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/PineappleMediaPlayerImpl.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/PineappleMediaPlayerImpl.java new file mode 100644 index 000000000..0623be205 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/PineappleMediaPlayerImpl.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared.sound; + +import android.content.Context; +import android.media.MediaPlayer; +import android.util.Log; + +/** + * A wrapper around a MediaPlayer so that we can define our own LoopingMediaPlayer and have it + * use a common interface. + */ +public class PineappleMediaPlayerImpl implements PineappleMediaPlayer { + private static final String TAG = PineappleMediaPlayerImpl.class.getSimpleName(); + + private MediaPlayer mediaPlayer; + private float volume; + + public static PineappleMediaPlayerImpl create(Context context, int resId) { + return new PineappleMediaPlayerImpl(context, resId); + } + + private PineappleMediaPlayerImpl(Context context, int resId) { + mediaPlayer = MediaPlayer.create(context, resId); + } + + @Override + public void start() { + try { + mediaPlayer.start(); + } catch (IllegalStateException e) { + Log.w(TAG, "start() failed: " + e.toString()); + } + } + + @Override + public boolean isPlaying() { + return mediaPlayer.isPlaying(); + } + + @Override + public void pause() { + try { + mediaPlayer.pause(); + } catch (IllegalStateException e) { + Log.w(TAG, "pause() failed: " + e.toString()); + } + } + + @Override + public MediaPlayer getMediaPlayer() { + return mediaPlayer; + } + + @Override + public void setNextMediaPlayer(MediaPlayer next) { + try { + mediaPlayer.setNextMediaPlayer(next); + } catch (IllegalStateException e) { + Log.w(TAG, "setNextMediaPlayer() failed: " + e.toString()); + } + } + + @Override + public void setVolume(float volume) { + this.volume = volume; + try { + mediaPlayer.setVolume(volume, volume); + } catch (IllegalStateException e) { + Log.w(TAG, "setVolume() failed: " + e.toString()); + } + } + + @Override + public void mute() { + try { + mediaPlayer.setVolume(0, 0); + } catch (IllegalStateException e) { + Log.w(TAG, "mute() failed: " + e.toString()); + } + } + + @Override + public void unmute() { + try { + mediaPlayer.setVolume(volume, volume); + } catch (IllegalStateException e) { + Log.w(TAG, "unmute() failed: " + e.toString()); + } + } + + @Override + public void release() { + try { + mediaPlayer.release(); + } catch (IllegalStateException e) { + Log.w(TAG, "release() failed: " + e.toString()); + } + } + +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/SoundManager.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/SoundManager.java new file mode 100644 index 000000000..b063f09f1 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/SoundManager.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.shared.sound; + +import android.content.Context; +import android.content.SharedPreferences; +import android.media.AudioManager; +import android.media.SoundPool; +import android.os.AsyncTask; +import android.util.Log; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A manager for all of the different sounds which will be played in the games. + */ +public class SoundManager { + private static final String TAG = SoundManager.class.getSimpleName(); + private static final String PREFS_NAME = "PineappleSoundManager"; + private static final String IS_MUTED_PREF = "MutePref"; + private static SoundManager instance; + public static boolean soundsAreMuted; + + private final Object mediaPlayerLock = new Object(); + private final Object soundPoolLock = new Object(); + + // A map from resource ID to a media player which can play the sound clip. + private Map mediaPlayerMap; + // A map from resource ID to a sound pool containing the sound clip. + private Map soundPoolMap; + // A set of resource IDs for sounds which have been individually muted. These shouldn't be unmuted + // when the mute option is toggled. + private Set mutedSounds; + private SoundManager() { + mediaPlayerMap = new HashMap<>(); + soundPoolMap = new HashMap<>(); + mutedSounds = new HashSet<>(); + } + + public static SoundManager getInstance() { + if (instance == null) { + instance = new SoundManager(); + } + return instance; + } + + public void loadLongSound(Context context, int resId, boolean looping, float volume) { + if (mediaPlayerMap.containsKey(resId)) { + return; + } + PineappleMediaPlayer mediaPlayer; + if (looping) { + mediaPlayer = LoopingMediaPlayer.create(context, resId); + } else { + mediaPlayer = PineappleMediaPlayerImpl.create(context, resId); + } + mediaPlayer.setVolume(volume); + if (soundsAreMuted) { + mediaPlayer.mute(); + } + synchronized (mediaPlayerLock) { + mediaPlayerMap.put(resId, mediaPlayer); + } + } + + public void loadLongSound(Context context, int resId, boolean looping) { + // Make this quiet by default so that it doesn't overpower the in-game sounds. + loadLongSound(context, resId, looping, 0.1f); + } + + public void loadShortSound(final Context context, final int resId, final boolean looping, + final float volume) { + if (soundPoolMap.containsKey(resId)) { + return; + } + new AsyncTask () { + @Override + protected Void doInBackground(Void... params) { + SoundPoolContainer container = new SoundPoolContainer(context, resId, looping, volume); + synchronized (soundPoolLock) { + soundPoolMap.put(resId, container); + } + return null; + } + }.execute(); + } + + public void loadShortSound(Context context, int resId) { + loadShortSound(context, resId, false, 1f); + } + + public void play(int resId) { + if (mediaPlayerMap.containsKey(resId)) { + mediaPlayerMap.get(resId).start(); + } else if (soundPoolMap.containsKey(resId)) { + SoundPoolContainer container = soundPoolMap.get(resId); + float vol = soundsAreMuted ? 0 : container.volume; + container.streamId = + container.soundPool.play(container.soundId, vol, vol, 1, container.looping ? -1 : 0, 1); + } + } + + public void pauseAll() { + synchronized (mediaPlayerLock) { + for (int resId : mediaPlayerMap.keySet()) { + pause(resId); + } + } + synchronized (soundPoolLock) { + for (int resId : soundPoolMap.keySet()) { + pause(resId); + } + } + } + + public void pause(int resId) { + if (mediaPlayerMap.containsKey(resId)) { + PineappleMediaPlayer mediaPlayer = mediaPlayerMap.get(resId); + if (mediaPlayer.isPlaying()) { + mediaPlayer.pause(); + } + } else if (soundPoolMap.containsKey(resId)) { + soundPoolMap.get(resId).soundPool.autoPause(); + } + } + + public void pauseShortSounds() { + synchronized (soundPoolLock) { + for (SoundPoolContainer container : soundPoolMap.values()) { + container.soundPool.autoPause(); + } + } + } + + public void resumeShortSounds() { + synchronized (soundPoolLock) { + for (SoundPoolContainer container : soundPoolMap.values()) { + container.soundPool.autoResume(); + } + } + } + + public void playLongSoundsInSequence(int[] soundIds) { + for (int i = 0; i < soundIds.length; i++) { + if (isPlayingLongSound(soundIds[i])) { + // Don't try to play long sounds which are already playing. + return; + } + } + + try { + PineappleMediaPlayer[] sounds = new PineappleMediaPlayer[soundIds.length]; + for (int i = 0; i < soundIds.length; i++) { + sounds[i] = mediaPlayerMap.get(soundIds[i]); + if (sounds[i] == null) { + return; + } + if (i > 0) { + sounds[i - 1].setNextMediaPlayer(sounds[i].getMediaPlayer()); + } + } + sounds[0].start(); + } catch (IllegalStateException e) { + Log.d(TAG, "playLongSoundsInSequence() failed: " + e.toString()); + } + } + + public boolean isPlayingLongSound(int resId) { + if (mediaPlayerMap.containsKey(resId)) { + return mediaPlayerMap.get(resId).isPlaying(); + } + return false; + } + + public void releaseAll() { + synchronized (mediaPlayerLock) { + for (PineappleMediaPlayer mediaPlayer : mediaPlayerMap.values()) { + mediaPlayer.release(); + } + mediaPlayerMap.clear(); + } + synchronized (soundPoolLock) { + for (SoundPoolContainer container : soundPoolMap.values()) { + container.soundPool.release(); + } + soundPoolMap.clear(); + } + } + + public void release(int resId) { + if (mediaPlayerMap.containsKey(resId)) { + mediaPlayerMap.get(resId).release(); + mediaPlayerMap.remove(resId); + } + if (soundPoolMap.containsKey(resId)) { + soundPoolMap.get(resId).soundPool.release(); + soundPoolMap.remove(resId); + } + } + + public void mute() { + synchronized (mediaPlayerLock) { + for (int resId : mediaPlayerMap.keySet()) { + muteInternal(resId, false); + } + } + synchronized (soundPoolLock) { + for (int resId : soundPoolMap.keySet()) { + muteInternal(resId, false); + } + } + soundsAreMuted = true; + } + + public void mute(int resId) { + muteInternal(resId, true); + } + + private void muteInternal(int resId, boolean addToMutedSounds) { + if (mediaPlayerMap.containsKey(resId)) { + mediaPlayerMap.get(resId).mute(); + } + if (soundPoolMap.containsKey(resId)) { + SoundPoolContainer container = soundPoolMap.get(resId); + container.soundPool.setVolume(container.streamId, 0, 0); + } + if (addToMutedSounds) { + mutedSounds.add(resId); + } + } + + public void unmute() { + soundsAreMuted = false; + synchronized (mediaPlayerLock) { + for (int resId : mediaPlayerMap.keySet()) { + if (!mutedSounds.contains(resId)) { + unmuteInternal(resId, false); + } + } + } + synchronized (soundPoolLock) { + for (int resId : soundPoolMap.keySet()) { + if (!mutedSounds.contains(resId)) { + unmuteInternal(resId, false); + } + } + } + } + + public void unmute(int resId) { + unmuteInternal(resId, true); + } + + private void unmuteInternal(int resId, boolean removeFromMutedSounds) { + if (soundsAreMuted) { + return; + } + if (mediaPlayerMap.containsKey(resId)) { + mediaPlayerMap.get(resId).unmute(); + } + if (soundPoolMap.containsKey(resId)) { + SoundPoolContainer container = soundPoolMap.get(resId); + container.soundPool.setVolume(container.streamId, container.volume, container.volume); + } + if (removeFromMutedSounds) { + mutedSounds.remove(resId); + } + } + + public void storeMutePreference(final Context context) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_NAME, 0); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(IS_MUTED_PREF, soundsAreMuted); + editor.commit(); + return null; + } + }.execute(); + } + + public void loadMutePreference(final Context context) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_NAME, 0); + if (sharedPreferences.getBoolean(IS_MUTED_PREF, false)) { + mute(); + } else { + unmute(); + } + return null; + } + }.execute(); + } + + private static class SoundPoolContainer { + public final SoundPool soundPool; + public final int soundId; + public final boolean looping; + public final float volume; + public int streamId; + public SoundPoolContainer(Context context, int resId, boolean looping, float volume) { + soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0); + soundId = soundPool.load(context, resId, 1); + this.looping = looping; + this.volume = volume; + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/BounceActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/BounceActor.java new file mode 100644 index 000000000..3a762a172 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/BounceActor.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.EventBus; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon.LineSegment; +import com.google.android.apps.santatracker.doodles.shared.physics.Util; + +import org.json.JSONException; +import org.json.JSONObject; + +/** + * An actor which causes a colliding object to bounce off of it. + */ +public class BounceActor extends CollisionActor { + public static final String TYPE = "Bouncy"; + + private static final float VIBRATE_VELOCITY_THRESHOLD = 150; + + public BounceActor(Polygon collisionBody) { + super(collisionBody); + } + + /** + * Cause the other actor to bounce off of this actor. + * Implementation based on: http://goo.gl/2gcLVd + */ + @Override + public boolean resolveCollision(Actor other, float deltaMs) { + // Short-circuit this call if a bounding box check is not passed. + if (!collisionBody.isInverted() && + !Util.pointIsWithinBounds(collisionBody.min, collisionBody.max, other.position)) { + // For a non-inverted polygon, we will collide with the body by moving inside of it. If the + // other actor is not inside of the bounds of the collision body, it cannot cause a collision. + return false; + } + + float deltaSeconds = deltaMs / 1000.0f; + Vector2D relativeVelocity = Vector2D.get(other.velocity.x - velocity.x, + other.velocity.y - velocity.y); + + // Find which line segment was crossed in order to intersect with the collision actor. + LineSegment intersectingSegment = collisionBody.getIntersectingLineSegment( + other.position, other.positionBeforeFrame); + if (intersectingSegment == null) { + relativeVelocity.release(); + return false; + } + Vector2D normal = intersectingSegment.getDirection().toNormal(); + + // Calculate relative velocity in terms of the normal direction. + float velocityAlongNormal = relativeVelocity.dot(normal); + + // Don't collide if velocities are separating. + if (velocityAlongNormal > 0) { + relativeVelocity.release(); + normal.release(); + return false; + } else if (velocityAlongNormal < -VIBRATE_VELOCITY_THRESHOLD) { + EventBus.getInstance().sendEvent(EventBus.VIBRATE); + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.golf_hit_wall); + } + + // Correct the position by moving the other actor along the normal of the colliding line + // segment until it passes back over the colliding segment. This works for the general case. + // Add the normal vector so that collisions with tiny velocities aren't affected by floating + // point precision. + Vector2D correctedPosition = Vector2D.get(other.position).add(normal).subtract( + normal.x * velocityAlongNormal * deltaSeconds, + normal.y * velocityAlongNormal * deltaSeconds); + + // This code checks to see if the corrected position causes the actor's path to intersect + // another line segment of the polygon. This could happen if the actor is colliding with a + // corner of this collision object. If this is the case, then we should just do the safe thing + // and undo the other actor's position update before applying the impulse. + intersectingSegment = collisionBody.getIntersectingLineSegment( + other.positionBeforeFrame, correctedPosition); + boolean movedBall = false; + if (intersectingSegment != null) { + // It is possible, if moving through the corner of an obstacle, that this correction causes + // the colliding actor to fall through this actor anyway. Correct for that case by moving + // the colliding actor back to its original position. + other.position.set(other.positionBeforeFrame); + } else { + other.position.set(correctedPosition); + movedBall = true; + } + + // Calculate restitution. + float e = Math.min(other.restitution, restitution); + + // Calculate impulse. + float j = -(1 + e) * velocityAlongNormal; + j /= other.inverseMass + inverseMass; + + // Apply impulse. + Vector2D impulse = normal.scale(j); + other.velocity.add(impulse.x * other.inverseMass, impulse.y * other.inverseMass); + velocity.subtract(impulse.x * inverseMass, impulse.y * inverseMass); + + relativeVelocity.release(); + correctedPosition.release(); + normal.release(); + return movedBall; + } + + @Override + public String getType() { + return BounceActor.TYPE; + } + + public static BounceActor fromJSON(JSONObject json) throws JSONException { + return new BounceActor(Polygon.fromJSON(json.getJSONArray(POLYGON_KEY))); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/BoundingBoxSpriteActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/BoundingBoxSpriteActor.java new file mode 100644 index 000000000..b0a8c63e8 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/BoundingBoxSpriteActor.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.util.Log; + +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.SpriteActor; +import com.google.android.apps.santatracker.doodles.shared.Sprites; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; +import com.google.android.apps.santatracker.doodles.shared.physics.Util; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +/** + * A sprite actor which contains a pre-set convex collision body. + */ +public class BoundingBoxSpriteActor extends CollisionActor implements Touchable { + private static final String TAG = BoundingBoxSpriteActor.class.getSimpleName(); + + public static final String DUCK = "duck"; + public static final String ICE_CUBE = "cube1"; + public static final String HAND_GRAB = "hand grab"; + + private static final Random RANDOM = new Random(); + protected static final float SCALE = 2; + + /** + * A utility class which contains data needed to create BoundingBoxSpriteActors. + */ + protected static class Data { + public int[] resIds; + public int numFrames; + public int zIndex; + public Vector2D spriteOffset; + public Vector2D[] vertexOffsets; + public Data(int[] resIds, int zIndex, Vector2D spriteOffset, Vector2D[] vertexOffsets) { + this.resIds = resIds; + this.numFrames = resIds == null ? 0 : resIds.length; + this.zIndex = zIndex; + this.spriteOffset = spriteOffset; + this.vertexOffsets = vertexOffsets; + } + } + public static final Map TYPE_TO_RESOURCE_MAP; + static { + TYPE_TO_RESOURCE_MAP = new HashMap<>(); + + Vector2D[] duckVertexOffsets = { + Vector2D.get(0, 0), + Vector2D.get(87, 0), + Vector2D.get(87, 186), + Vector2D.get(0, 186), + }; + TYPE_TO_RESOURCE_MAP.put(DUCK, + new Data(Sprites.penguin_swim_elf, 1, Vector2D.get(0, 0).scale(SCALE), + duckVertexOffsets)); + + Vector2D[] iceCube1VertexOffsets = { + Vector2D.get(0, 0), Vector2D.get(101.9f, 0), + Vector2D.get(101.9f, 100.2f), Vector2D.get(0, 100.2f) + }; + TYPE_TO_RESOURCE_MAP.put(ICE_CUBE, + new Data(Sprites.penguin_swim_ice, 1, Vector2D.get(0, 0).scale(SCALE), + iceCube1VertexOffsets)); + + // This is just a placeholder so that we can create hand grabs programatically. This data + // shouldn't actually be used. + TYPE_TO_RESOURCE_MAP.put(HAND_GRAB, new Data(null, 0, Vector2D.get(0, 0).scale(SCALE), + null)); + } + + public String type; + public final SpriteActor spriteActor; + public Vector2D spriteOffset; + + public BoundingBoxSpriteActor( + Polygon collisionBody, SpriteActor spriteActor, Vector2D spriteOffset, String type) { + super(collisionBody); + + this.spriteOffset = spriteOffset; + this.type = type; + this.spriteActor = spriteActor; + scale = SCALE; + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + spriteActor.update(deltaMs); + spriteActor.position.set(position.x, position.y); + } + + @Override + public void draw(Canvas canvas) { + spriteActor.draw(canvas, spriteOffset.x, spriteOffset.y, + spriteActor.sprite.frameWidth * scale, spriteActor.sprite.frameHeight * scale); + collisionBody.draw(canvas); + } + + @Override + public boolean canHandleTouchAt(Vector2D worldCoords, float cameraScale) { + Vector2D lowerRight = Vector2D.get(position).add(spriteOffset) + .add(spriteActor.sprite.frameWidth * scale, + spriteActor.sprite.frameHeight * scale); + boolean retVal = super.canHandleTouchAt(worldCoords, cameraScale) + || Util.pointIsWithinBounds(Vector2D.get(position).add(spriteOffset), + lowerRight, worldCoords); + + lowerRight.release(); + return retVal; + } + + @Override + public void startTouchAt(Vector2D worldCoords, float cameraScale) { + selectedIndex = collisionBody.getSelectedIndex(worldCoords, cameraScale); + } + + @Override + public boolean handleMoveEvent(Vector2D delta) { + collisionBody.move(-delta.x, -delta.y); + position.set(collisionBody.min); + // NOTE: Leave this commented-out section here. This is used when adding new + // BoundingBoxSpriteActors in order to fine-tune the collision boundaries and sprite offsets. + /* + boolean moved; + if (selectedIndex >= 0) { + collisionBody.moveVertex(selectedIndex, Vector2D.get(delta).scale(-1)); + Log.d(TAG, "min: " + collisionBody.min); + Log.d(TAG, "max: " + collisionBody.max); + } else { + spriteOffset.subtract(delta); + Log.d(TAG, "Sprite offset: " + spriteOffset); + } + */ + return true; + } + + @Override + public boolean handleLongPress() { + // NOTE: Leave this commented-out section here. This is used when adding new + // BoundingBoxSpriteActors in order to fine-tune the collision boundaries and sprite offsets. + /* + if (selectedIndex >= 0) { + if (canRemoveCollisionVertex()) { + // If we can, just remove the vertex. + collisionBody.removeVertexAt(selectedIndex); + return true; + } + } else if (midpointIndex >= 0) { + // Long press on a midpoint, add a vertex to the selected obstacle's polygon. + collisionBody.addVertexAfter(midpointIndex); + return true; + } + */ + return false; + } + + @Override + public boolean resolveCollision(Actor other, float deltaMs) { + if (other instanceof SwimmerActor) { + return resolveCollisionInternal((SwimmerActor) other); + } + return false; + } + + @Override + public String getType() { + return type; + } + + @Override + public JSONObject toJSON() throws JSONException { + JSONObject json = new JSONObject(); + json.put(TYPE_KEY, getType()); + json.put(X_KEY, position.x); + json.put(Y_KEY, position.y); + return json; + } + + protected boolean resolveCollisionInternal(SwimmerActor swimmer) { + if (swimmer.isInvincible || swimmer.isUnderwater) { + return false; + } + if (swimmer.collisionBody.min.y > collisionBody.max.y + || swimmer.collisionBody.max.y < collisionBody.min.y) { + // Perform a short-circuiting check which fails if the swimmer is outside of the vertical + // boundaries of this collision body. + return false; + } + + // NOTE: We've since removed the diagonal ice cube, so we don't have any + // non-axis-aligned rectangles to check collisions with. However, there may still be a few + // artifacts of complex polygon collisions in the code. + + // CAN and ICE_CUBE objects are just axis-aligned rectangles. Use the faster + // rectangle-to-rectangle collision code in these cases. + if (Util.rectIntersectsRect(swimmer.collisionBody.min.x, swimmer.collisionBody.min.y, + swimmer.collisionBody.getWidth(), swimmer.collisionBody.getHeight(), + collisionBody.min.x, collisionBody.min.y, + collisionBody.getWidth(), collisionBody.getHeight())) { + + // If the swimmer is colliding with the side of an obstacle, make the swimmer slide along it + // instead of colliding. + if (swimmer.positionBeforeFrame.y < collisionBody.max.y) { + swimmer.moveTo(swimmer.positionBeforeFrame.x, swimmer.position.y); + } else { + swimmer.collide(type); + } + } + return false; + } + + public static BoundingBoxSpriteActor create(Vector2D position, String type, Resources resources) { + if (!TYPE_TO_RESOURCE_MAP.containsKey(type)) { + Log.e(TAG, "Unknown object type: " + type); + return null; + } + Data data = TYPE_TO_RESOURCE_MAP.get(type); + + BoundingBoxSpriteActor actor; + if (type.equals(HAND_GRAB)) { + actor = HandGrabActor.create(position, resources); + } else { + actor = new BoundingBoxSpriteActor( + getBoundingBox(position, data.vertexOffsets, SCALE), + new SpriteActor(AnimatedSprite.fromFrames(resources, data.resIds), + Vector2D.get(position), Vector2D.get(0, 0)), + Vector2D.get(data.spriteOffset), + type); + } + + actor.zIndex = data.zIndex; + + // Start at a random frame index so that all of the sprites aren't synced up. + actor.spriteActor.sprite.setFrameIndex(RANDOM.nextInt(actor.spriteActor.sprite.getNumFrames())); + + return actor; + } + + public static BoundingBoxSpriteActor fromJSON(JSONObject json, Context context) + throws JSONException { + String type = json.getString(Actor.TYPE_KEY); + Vector2D position = Vector2D.get((float) json.getDouble(X_KEY), (float) json.getDouble(Y_KEY)); + return create(position, type, context.getResources()); + } + + protected static Polygon getBoundingBox( + Vector2D position, Vector2D[] vertexOffsets, float scale) { + List vertices = new ArrayList<>(); + for (int i = 0; i < vertexOffsets.length; i++) { + vertices.add(Vector2D.get(position).add(Vector2D.get(vertexOffsets[i]).scale(scale))); + } + return new Polygon(vertices); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/CollisionActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/CollisionActor.java new file mode 100644 index 000000000..b888cc802 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/CollisionActor.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.graphics.Canvas; + +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; + +import org.json.JSONException; +import org.json.JSONObject; + +/** + * An actor which represents an object in the world which causes some reaction when it is collided + * with. + */ +public class CollisionActor extends Actor implements Touchable { + public static final String TYPE = "collision"; + protected static final String POLYGON_KEY = "polygon"; + + // These measurements are in "world units", which are really just arbitrary units where one world + // unit == one pixel at the default camera zoom level. + public static final float DEFAULT_WIDTH = 200; + public static final float DEFAULT_HEIGHT = 200; + public Polygon collisionBody; + + protected int selectedIndex = -1; + protected int midpointIndex = -1; + + public CollisionActor(Polygon collisionBody) { + super(Vector2D.get(collisionBody.min.x, collisionBody.min.y), Vector2D.get()); + this.collisionBody = collisionBody; + restitution = 0.7f; + inverseMass = Actor.INFINITE_MASS; // Give collision actors infinite mass. + zIndex = 10; + } + + @Override + public void update(float deltaMs) { + positionBeforeFrame.set(position); + float deltaX = velocity.x * deltaMs / 1000.0f; + float deltaY = velocity.y * deltaMs / 1000.0f; + collisionBody.move(deltaX, deltaY); + position.set(collisionBody.min); + } + + @Override + public boolean canHandleTouchAt(Vector2D worldCoords, float cameraScale) { + return collisionBody.getSelectedIndex(worldCoords, cameraScale) >= 0 + || collisionBody.getMidpointIndex(worldCoords, cameraScale) >= 0; + } + + @Override + public void startTouchAt(Vector2D worldCoords, float cameraScale) { + selectedIndex = collisionBody.getSelectedIndex(worldCoords, cameraScale); + midpointIndex = collisionBody.getMidpointIndex(worldCoords, cameraScale); + } + + @Override + public boolean handleMoveEvent(Vector2D delta) { + if (selectedIndex >= 0) { + Vector2D positionDelta = Vector2D.get(delta).scale(-1); + collisionBody.moveVertex(selectedIndex, positionDelta); + positionDelta.release(); + return true; + } + return false; + } + + @Override + public boolean handleLongPress() { + if (selectedIndex >= 0) { + if (canRemoveCollisionVertex()) { + // If we can, just remove the vertex. + collisionBody.removeVertexAt(selectedIndex); + return true; + } + } else if (midpointIndex >= 0) { + // Long press on a midpoint, add a vertex to the selected obstacle's polygon. + collisionBody.addVertexAfter(midpointIndex); + return true; + } + return false; + } + + @Override + public String getType() { + return CollisionActor.TYPE; + } + + @Override + public JSONObject toJSON() throws JSONException { + JSONObject json = new JSONObject(); + json.put(TYPE_KEY, getType()); + json.put(POLYGON_KEY, collisionBody.toJSON()); + return json; + } + + /** + * Resolve a collision with another physics actor. + * + * @param other The actor being collided with. + * @param deltaMs The length of the collision frame. + * @return true if resolving the collision moves the other actor, false otherwise. + */ + public boolean resolveCollision(Actor other, float deltaMs) { + return false; + } + + public void draw(Canvas canvas) { + collisionBody.draw(canvas); + } + + public boolean canRemoveCollisionVertex() { + return collisionBody.vertices.size() > 3; + } + + public static CollisionActor fromJSON(JSONObject json) throws JSONException { + return new CollisionActor(Polygon.fromJSON(json.getJSONArray(POLYGON_KEY))); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ColoredRectangleActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ColoredRectangleActor.java new file mode 100644 index 000000000..36e6d633d --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ColoredRectangleActor.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Cap; +import android.graphics.Paint.Style; + +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.physics.Util; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.Map; + +/** + * An actor class which represents an arbitrarily-colored rectangle. + */ +public class ColoredRectangleActor extends Actor implements Touchable { + /* Default color is black*/ + public static final String UNSPECIFIED = "unspecified"; + + /* Golf colors */ + public static final String TEE_GREEN = "tee"; + public static final String FAIRWAY_GREEN = "fairway"; + + /* Swimming colors */ + public static final String DISTANCE_30M = "30m"; + public static final String DISTANCE_50M = "50m"; + public static final String DISTANCE_100M = "100m"; + public static final String DISTANCE_LEVEL_LENGTH = "level length"; + public static final String DISTANCE_PR = "pr"; + public static final String STARTING_BLOCK = "start"; + + public static final String DIMENS_X_KEY = "dimens x"; + public static final String DIMENS_Y_KEY = "dimens y"; + + + public static final Map TYPE_TO_COLOR_MAP; + static { + TYPE_TO_COLOR_MAP = new HashMap<>(); + /* Golf */ + TYPE_TO_COLOR_MAP.put(TEE_GREEN, Constants.LIGHT_GREEN); + TYPE_TO_COLOR_MAP.put(FAIRWAY_GREEN, Constants.DARK_GREEN); + /* Swimming */ + TYPE_TO_COLOR_MAP.put(DISTANCE_30M, 0x44cd7f32); + TYPE_TO_COLOR_MAP.put(DISTANCE_50M, 0x44c0c0c0); + TYPE_TO_COLOR_MAP.put(DISTANCE_100M, 0x44ffd700); + TYPE_TO_COLOR_MAP.put(DISTANCE_LEVEL_LENGTH, 0x44ffffff); + TYPE_TO_COLOR_MAP.put(DISTANCE_PR, 0x4400cc00); + TYPE_TO_COLOR_MAP.put(STARTING_BLOCK, 0xff4993a4); + TYPE_TO_COLOR_MAP.put(UNSPECIFIED, 0xff000000); + } + + /** + * A direction used to pull the boundaries of the colored rectangle. + */ + private enum Direction { + NONE, + UP, + DOWN, + LEFT, + RIGHT, + } + private Direction selectedDirection; + + public String type; + public Vector2D dimens; + private Paint paint; + private Paint midpointPaint; + + private Vector2D upMidpoint = Vector2D.get(); + private Vector2D downMidpoint = Vector2D.get(); + private Vector2D leftMidpoint = Vector2D.get(); + private Vector2D rightMidpoint = Vector2D.get(); + + public ColoredRectangleActor(Vector2D position, Vector2D dimens) { + this(position, dimens, UNSPECIFIED); + } + + public ColoredRectangleActor(Vector2D position, Vector2D dimens, String type) { + super(position, Vector2D.get()); + + this.dimens = dimens; + this.type = type; + this.zIndex = -1; + + if (type.equals(FAIRWAY_GREEN)) { + this.zIndex = -2; + } + + selectedDirection = Direction.NONE; + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(TYPE_TO_COLOR_MAP.get(type)); + paint.setStyle(Style.FILL); + + midpointPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + midpointPaint.setColor(Color.WHITE); + + updateExtents(); + } + + @Override + public void draw(Canvas canvas) { + canvas.drawRect(position.x, position.y, position.x + dimens.x, position.y + dimens.y, paint); + } + + public void setStyle(Style style) { + paint.setStyle(style); + } + + public void setStrokeWidth(float width) { + paint.setStrokeWidth(width); + paint.setStrokeCap(Cap.ROUND); + } + + public void setColor(int color) { + paint.setColor(color); + } + + @Override + public String getType() { + return type; + } + + @Override + public boolean canHandleTouchAt(Vector2D worldCoords, float cameraScale) { + Vector2D lowerRight = Vector2D.get(position).add(dimens); + boolean retVal = Util.pointIsWithinBounds(position, lowerRight, worldCoords) + || worldCoords.distanceTo(upMidpoint) < Constants.SELECTION_RADIUS + || worldCoords.distanceTo(downMidpoint) < Constants.SELECTION_RADIUS + || worldCoords.distanceTo(leftMidpoint) < Constants.SELECTION_RADIUS + || worldCoords.distanceTo(rightMidpoint) < Constants.SELECTION_RADIUS; + + lowerRight.release(); + return retVal; + } + + @Override + public void startTouchAt(Vector2D worldCoords, float cameraScale) { + if (worldCoords.distanceTo(upMidpoint) < Constants.SELECTION_RADIUS) { + selectedDirection = Direction.UP; + } else if (worldCoords.distanceTo(downMidpoint) < Constants.SELECTION_RADIUS) { + selectedDirection = Direction.DOWN; + } else if (worldCoords.distanceTo(leftMidpoint) < Constants.SELECTION_RADIUS) { + selectedDirection = Direction.LEFT; + } else if (worldCoords.distanceTo(rightMidpoint) < Constants.SELECTION_RADIUS) { + selectedDirection = Direction.RIGHT; + } else { + selectedDirection = Direction.NONE; + } + } + + @Override + public boolean handleMoveEvent(Vector2D delta) { + if (selectedDirection == Direction.NONE) { + position.subtract(delta); + } else if (selectedDirection == Direction.UP) { + position.y -= delta.y; + dimens.y += delta.y; + } else if (selectedDirection == Direction.DOWN) { + dimens.y -= delta.y; + } else if (selectedDirection == Direction.LEFT) { + position.x -= delta.x; + dimens.x += delta.x; + } else { + // Direction.RIGHT + dimens.x -= delta.x; + } + updateExtents(); + return true; + } + + @Override + public boolean handleLongPress() { + return false; + } + + @Override + public JSONObject toJSON() throws JSONException { + JSONObject json = new JSONObject(); + json.put(TYPE_KEY, getType()); + json.put(X_KEY, position.x); + json.put(Y_KEY, position.y); + json.put(DIMENS_X_KEY, dimens.x); + json.put(DIMENS_Y_KEY, dimens.y); + return json; + } + + private void updateExtents() { + upMidpoint.set(position).add(dimens.x / 2, 0); + downMidpoint.set(position).add(dimens.x / 2, dimens.y); + leftMidpoint.set(position).add(0, dimens.y / 2); + rightMidpoint.set(position).add(dimens.x, dimens.y / 2); + } + + public static ColoredRectangleActor fromJSON(JSONObject json) throws JSONException { + String type = json.getString(Actor.TYPE_KEY); + Vector2D position = Vector2D.get( + (float) json.optDouble(X_KEY, 0), (float) json.optDouble(Y_KEY, 0)); + Vector2D dimens = Vector2D.get( + (float) json.optDouble(DIMENS_X_KEY, 0), (float) json.optDouble(DIMENS_Y_KEY, 0)); + return new ColoredRectangleActor(position, dimens, type); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/Constants.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/Constants.java new file mode 100644 index 000000000..2da86a591 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/Constants.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +/** + * Constants from deleted games that were unsafe to delete. + */ +public class Constants { + + public static final float SELECTION_RADIUS = 70; + public static final int DARK_GREEN = 0xff9b953d; + public static final int LIGHT_GREEN = 0xffb1af4b; + public static final float GRAVITY = 4000.0f; + +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/DistanceMarkerActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/DistanceMarkerActor.java new file mode 100644 index 000000000..e0c8f0049 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/DistanceMarkerActor.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import com.google.android.apps.santatracker.doodles.shared.Vector2D; + +/** + * A colored rectangle actor which marks distance in the swimming game. + */ +public class DistanceMarkerActor extends ColoredRectangleActor { + private static final int HEIGHT = 200; + + public DistanceMarkerActor(int positionInMeters, String type) { + this(positionInMeters, type, HEIGHT); + } + + public DistanceMarkerActor(int positionInMeters, String type, float height) { + super(Vector2D.get(0, SwimmingModel.getWorldYFromMeters(positionInMeters)), + Vector2D.get(SwimmingModel.LEVEL_WIDTH, height), type); + zIndex = -2; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/DiveView.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/DiveView.java new file mode 100644 index 000000000..1733183c5 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/DiveView.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Paint; +import android.graphics.PorterDuff.Mode; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.animation.DecelerateInterpolator; +import android.widget.ImageView; +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.Interpolator; +import com.google.android.apps.santatracker.doodles.shared.PauseView; +import com.google.android.apps.santatracker.doodles.shared.Process; +import com.google.android.apps.santatracker.doodles.shared.ProcessChain; +import com.google.android.apps.santatracker.doodles.shared.Tween; +import com.google.android.apps.santatracker.doodles.shared.UIUtil; +import java.util.ArrayList; +import java.util.List; + +/** + * The dive cooldown UI for the swimming game. + */ +public class DiveView extends ImageView { + private static final int CLOCK_DURATION_MS = + SwimmerActor.DIVE_DURATION_MS + SwimmerActor.DIVE_COOLDOWN_MS; + private static final float BUMP_SCALE = 1.4f; + private static final long BUMP_DURATION_MS = 200; + + private RectF viewBounds; + private Paint paint; + private Paint imagePaint; + + private float clockAngle; + private Bitmap diveArrowBitmap; + private Rect diveArrowBounds; + private List processChains; + + public DiveView(Context context) { + this(context, null); + } + + public DiveView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DiveView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(0xffffffff); + imagePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + imagePaint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP)); + viewBounds = new RectF(0, 0, getWidth(), getHeight()); + diveArrowBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.swimming_dive_arrow); + diveArrowBounds = new Rect(0, 0, diveArrowBitmap.getWidth(), diveArrowBitmap.getHeight()); + processChains = new ArrayList<>(); + + setLayerType(LAYER_TYPE_HARDWARE, null); + } + + @Override + public void onDraw(Canvas canvas) { + float startAngle = -90; + float sweepAngle = clockAngle; + + canvas.drawArc(viewBounds, startAngle, sweepAngle, true, paint); + canvas.drawBitmap(diveArrowBitmap, diveArrowBounds, viewBounds, imagePaint); + } + + @Override + public void onSizeChanged(int w, int h, int oldw, int oldh) { + viewBounds = new RectF(0, 0, getWidth(), getHeight()); + } + + public void update(float deltaMs) { + ProcessChain.updateChains(processChains, deltaMs); + } + + public void startCooldown() { + setImageColorSaturation(0); + show(); + Process cooldown = new Tween(CLOCK_DURATION_MS / 1000.0f) { + @Override + protected void updateValues(float percentDone) { + clockAngle = Interpolator.LINEAR.getValue(percentDone, 0, 360); + postInvalidate(); + } + + @Override + protected void onFinish() { + setImageColorSaturation(1); + bump(); + } + }.asProcess(); + processChains.add(new ProcessChain(cooldown)); + } + + public void hide() { + UIUtil.fadeOutAndHide(this, PauseView.FADE_DURATION_MS); + } + + public void show() { + clockAngle = 0; + UIUtil.showAndFadeIn(this, PauseView.FADE_DURATION_MS); + } + + private void bump() { + ValueAnimator bumpAnimation = UIUtil.animator(BUMP_DURATION_MS, + new DecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + final float scale = (float) valueAnimator.getAnimatedValue("scale"); + post(new Runnable() { + @Override + public void run() { + setScaleX(scale); + setScaleY(scale); + } + }); + } + }, + UIUtil.floatValue("scale", BUMP_SCALE, 1) + ); + bumpAnimation.start(); + } + + private void setImageColorSaturation(float saturation) { + ColorMatrix cm = new ColorMatrix(); + cm.setSaturation(saturation); + imagePaint.setColorFilter(new ColorMatrixColorFilter(cm)); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/HandGrabActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/HandGrabActor.java new file mode 100644 index 000000000..3d0effe28 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/HandGrabActor.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.content.res.Resources; +import android.graphics.Canvas; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite.AnimatedSpriteListener; +import com.google.android.apps.santatracker.doodles.shared.EventBus; +import com.google.android.apps.santatracker.doodles.shared.MultiSpriteActor; +import com.google.android.apps.santatracker.doodles.shared.Sprites; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; +import java.util.HashMap; +import java.util.Map; + +/** + * The hand grab obstacle in the swimming game. + */ +public class HandGrabActor extends BoundingBoxSpriteActor { + private static final String X_SPRITE = "x"; + private static final String LEMON_GRAB_SPRITE = "lemon grab"; + private static final String LEMON_GRAB_SPRITE_FLIPPED = "lemon grab flipped"; + + private static final float COLLISION_DISTANCE_THRESHOLD = 100; + private static final Vector2D[] VERTEX_OFFSETS = { + Vector2D.get(0, 0), + Vector2D.get(110f, 0), + Vector2D.get(110f, 146.0f), + Vector2D.get(0, 146.0f) + }; + + private static final Map OFFSET_MAP; + static { + OFFSET_MAP = new HashMap<>(); + OFFSET_MAP.put(X_SPRITE, Vector2D.get()); + OFFSET_MAP.put(LEMON_GRAB_SPRITE, Vector2D.get(-100, -100)); + OFFSET_MAP.put(LEMON_GRAB_SPRITE_FLIPPED, Vector2D.get(100, -100)); + } + + public HandGrabActor(Polygon collisionBody, MultiSpriteActor spriteActor) { + super(collisionBody, spriteActor, + Vector2D.get(OFFSET_MAP.get(X_SPRITE)).scale(SwimmerActor.SWIMMER_SCALE), HAND_GRAB); + zIndex = -1; + scale = SwimmerActor.SWIMMER_SCALE; + } + + @Override + public void draw(Canvas canvas) { + if (hidden) { + return; + } + super.draw(canvas); + } + + public void setSprite(String key) { + if (key.equals(X_SPRITE)) { + zIndex = -1; + } else if (key.equals(LEMON_GRAB_SPRITE)) { + zIndex = 3; + } + ((MultiSpriteActor) spriteActor).setSprite(key); + + if (isFlippedX() && key.equals(LEMON_GRAB_SPRITE)) { + spriteOffset.set(OFFSET_MAP.get(LEMON_GRAB_SPRITE_FLIPPED)).scale(scale); + } else { + spriteOffset.set(OFFSET_MAP.get(key)).scale(scale); + } + } + + public boolean isFlippedX() { + return ((MultiSpriteActor) spriteActor).sprites.get(LEMON_GRAB_SPRITE).isFlippedX(); + } + + @Override + protected boolean resolveCollisionInternal(final SwimmerActor swimmer) { + if (swimmer.isInvincible || swimmer.isUnderwater) { + return false; + } + + // Only collide if the two actor's minimum collision coordinates are close together. This is + // so that the swimmer will only collide with the hand grab if it is right over the x. + if (swimmer.collisionBody.min.distanceTo(collisionBody.min) < COLLISION_DISTANCE_THRESHOLD) { + swimmer.collide(type); + + setSprite(LEMON_GRAB_SPRITE); + spriteActor.sprite.addListener(new AnimatedSpriteListener() { + @Override + public void onFrame(int index) { + if (index == 10) { + swimmer.hidden = true; + swimmer.spriteActor.sprite.setPaused(true); + EventBus.getInstance().sendEvent(EventBus.VIBRATE); + } + + } + + @Override + public void onFinished() { + hidden = true; + swimmer.isDead = true; + } + }); + } + return false; + } + + public static HandGrabActor create(Vector2D position, Resources res) { + Map spriteMap = new HashMap<>(); + boolean shouldFlip = position.x + VERTEX_OFFSETS[1].x / 2 < SwimmingModel.LEVEL_WIDTH / 2; + + AnimatedSprite lemonGrabSprite = AnimatedSprite.fromFrames(res, Sprites.penguin_swim_canegrab); + lemonGrabSprite.setLoop(false); + lemonGrabSprite.setFlippedX(shouldFlip); + + spriteMap.put(LEMON_GRAB_SPRITE, lemonGrabSprite); + spriteMap.put(X_SPRITE, AnimatedSprite.fromFrames(res, Sprites.penguin_swim_candy)); + + MultiSpriteActor spriteActor = + new MultiSpriteActor(spriteMap, X_SPRITE, position, Vector2D.get(0, 0)); + + Polygon boundingBox = getBoundingBox(position, VERTEX_OFFSETS, SwimmerActor.SWIMMER_SCALE); + + return new HandGrabActor(boundingBox, spriteActor); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/LevelManager.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/LevelManager.java new file mode 100644 index 000000000..0d03fd8ba --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/LevelManager.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.content.Context; +import android.support.annotation.VisibleForTesting; +import android.util.Log; + +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.ExternalStoragePermissions; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.List; + +/** + * A helper class which handles the saving and loading of levels for the doodle games. + * + * The {@code LevelManager} stores levels in a simple JSON format. The {@code Actor} classes wishing + * to be managed by a {@code LevelManager} should handle their own serialization and + * deserialization. + */ +public abstract class LevelManager { + public static final String TAG = LevelManager.class.getSimpleName(); + private static final String ACTORS_KEY = "actors"; + + protected final Context context; + private final ExternalStoragePermissions storagePermissions; + + public LevelManager(Context context) { + this(context, new ExternalStoragePermissions()); + } + + @VisibleForTesting + LevelManager(Context context, ExternalStoragePermissions storagePermissions) { + this.context = context; + this.storagePermissions = storagePermissions; + } + + /** + * Saves a level to persistent storage. + * + * @param level The level to save. + * @param filename The name of the level's file on disk. This file will be stored inside of a + * preset directory, defined by the LevelManager implementation. + */ + public void saveLevel(T level, String filename) { + File levelsDir = getLevelsDir(); + if (!levelsDir.exists() && !levelsDir.mkdirs()) { + // If we are unable to find or make the desired output directory, log a warning and fail. + Log.w(TAG, "Unable to reach dir: " + levelsDir.getAbsolutePath()); + return; + } + try { + FileOutputStream outputStream = new FileOutputStream(new File(levelsDir, filename)); + saveLevel(level, outputStream); + } catch (FileNotFoundException e) { + Log.w(TAG, "Unable to save file: " + filename); + } + } + + /** + * Writes a level to the provided OutputStream. + * + * @param level The level to save. + * @param outputStream The stream to which the level should be written. + */ + @VisibleForTesting + void saveLevel(T level, OutputStream outputStream) { + try { + saveActors(level.getActors(), outputStream); + } catch (JSONException e) { + Log.w(TAG, "Unable to create level JSON."); + } catch (IOException e) { + Log.w(TAG, "Unable to write actors to output stream."); + } + } + + /** + * Loads a level from persistent storage. + * + *

This loads first tries to load a level from assets, falling back to external storage if + * necessary. If it still cannot load the level, the default level will be loaded.

+ * + * @param filename The name of the file to load. This file should be stored in a preset directory, + * specified by the LevelManager implementation. + * @return The loaded level. + */ + public T loadLevel(String filename) { + if (filename == null) { + Log.w(TAG, "Couldn't load level with null filename, using default level instead."); + return loadDefaultLevel(); + } + + BufferedReader externalStorageReader = null; + try { + externalStorageReader = + new BufferedReader( + new InputStreamReader( + new FileInputStream(new File(getLevelsDir(), filename)), "UTF-8")); + } catch (IOException e) { + Log.d(TAG, "Unable to load file from external storage: " + filename); + } + + BufferedReader assetsReader = null; + try { + assetsReader = + new BufferedReader(new InputStreamReader(context.getAssets().open(filename), "UTF-8")); + } catch (IOException e) { + Log.d(TAG, "Unable to load file from assets: " + filename); + } + + T model = loadLevel(externalStorageReader, assetsReader); + model.setLevelName(filename); + return model; + } + + /** + * Loads a level from either assets, or from external storage. + * + *

This first tries to load a level from assets, falling back to external storage if + * necessary. If it still cannot load the level, the default level will be loaded.

+ * + *

This method should only be used for testing LevelManager. Real use cases should generally + * use {@code loadLevel(String filename)}.

+ * + * @param externalStorageReader + * @param assetsInputReader + * @return The loaded level. + */ + @VisibleForTesting + T loadLevel(BufferedReader externalStorageReader, BufferedReader assetsInputReader) { + JSONObject json = null; + if (assetsInputReader != null) { + json = readLevelJson(assetsInputReader); + Log.d(TAG, "Loaded level from assets."); + } + if (json == null + && externalStorageReader != null + && storagePermissions.isExternalStorageReadable()) { + json = readLevelJson(externalStorageReader); + Log.d(TAG, "Loaded level from external storage."); + } + if (json == null) { + Log.w(TAG, "Couldn't load level data, using default level instead."); + return loadDefaultLevel(); + } + + T model = getEmptyModel(); + try { + JSONArray actors = json.getJSONArray(ACTORS_KEY); + for (int i = 0; i < actors.length(); i++) { + Actor actor = loadActorFromJSON(actors.getJSONObject(i)); + if (actor != null) { + model.addActor(actor); + } + } + } catch (JSONException e) { + Log.w(TAG, "Couldn't load actors, using default level instead."); + return loadDefaultLevel(); + } + return model; + } + + /** + * Initializes the default level and returns it. + * + *

In general, this should be an empty or minimal level.

+ * + * @return the initialized default level. + */ + public abstract T loadDefaultLevel(); + + /** + * Returns the external storage directory within which levels of this type should be saved. + * + * @return The base directory which should be used to save levels. + */ + protected abstract File getLevelsDir(); + + /** + * Loads a single actor from JSON. + * + * @param json The JSON representation of the actor to be loaded + * @return The loaded actor, or null if the actor could not be loaded. + * @throws JSONException if the JSON is malformed, or fails to be parsed. + */ + @VisibleForTesting + abstract Actor loadActorFromJSON(JSONObject json) throws JSONException; + + /** + * Returns an empty, or minimal model of the appropriate type. Generally, this should be the same + * as asking for a {@code new T()}. + * + * @return The empty model. + */ + protected abstract T getEmptyModel(); + + /** + * Returns a JSONArray containing the JSON representation of the passed-in list of actors. + * + *

If a given actor does not provide a JSON representation, it will not appear in the returned + * JSONArray.

+ * + * @param actors The actors to convert into JSON. + * @return The JSON representation of the list of actors. + * @throws JSONException If the parsing of an actor into JSON fails. + */ + @VisibleForTesting + JSONArray getActorsJson(List actors) throws JSONException { + JSONArray actorsJson = new JSONArray(); + for (Actor actor : actors) { + JSONObject json = actor.toJSON(); + if (json != null) { + actorsJson.put(json); + } + } + return actorsJson; + } + + /** + * Writes a list of actors to an OutputStream. + * + * @param actors The actors to be written. + * @param outputStream The OuputStream which should be used to write the list of actors. + * @throws JSONException If the conversion of actors into JSON fails. + * @throws IOException If we fail to write to the OutputStream. + */ + private void saveActors(List actors, OutputStream outputStream) + throws JSONException, IOException { + JSONObject json = new JSONObject(); + json.put(ACTORS_KEY, getActorsJson(actors)); + Log.d(TAG, json.toString(2)); + + if (storagePermissions.isExternalStorageWritable()) { + writeLevelJson(json, outputStream); + } else { + Log.w(TAG, "External storage is not writable"); + } + } + + /** + * Writes a JSONObject to an OutputStream. + * + * @param json The object to be written. + * @param outputStream The stream to be written to. + * @throws IOException If we fail to write to the OutputStream. + */ + private void writeLevelJson(JSONObject json, OutputStream outputStream) throws IOException { + outputStream.write(json.toString().getBytes()); + outputStream.close(); + } + + /** + * Read a JSONObject from a BufferedReader. + * + * @param reader The BufferedReader which contains the JSON to be read. + * @return A JSONObject parsed from the contents of the BufferedReader. + */ + private JSONObject readLevelJson(BufferedReader reader) { + try { + String levelData = ""; + String line = reader.readLine(); + while (line != null) { + levelData += line; + line = reader.readLine(); + } + reader.close(); + return new JSONObject(levelData); + } catch (IOException e) { + Log.w(TAG, "readLevelJson: Couldn't read JSON."); + } catch (JSONException e) { + Log.w(TAG, "readLevelJson: Couldn't create JSON."); + } + return null; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ObstacleManager.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ObstacleManager.java new file mode 100644 index 000000000..cfa092d3d --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ObstacleManager.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.content.Context; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * A class for managing obstacles in the swimming game. + */ +public class ObstacleManager extends Actor { + private static final String TAG = ObstacleManager.class.getSimpleName(); + private static final int NUM_INITIAL_CHUNKS = 4; + private static final int RETAIN_THRESHOLD = 2000; + + private LinkedList levelChunks; + private SwimmerActor swimmer; + + public ObstacleManager(SwimmerActor swimmer, Context context) { + levelChunks = new LinkedList<>(); + SwimmingLevelChunk.generateAllLevelChunks(-1000, context); + for (int i = 1; i < NUM_INITIAL_CHUNKS; i++) { + levelChunks.add(SwimmingLevelChunk.getNextChunk()); + } + this.swimmer = swimmer; + zIndex = 1; + } + + @Override + public void update(float deltaMs) { + for (int i = 0; i < levelChunks.size(); i++) { + levelChunks.get(i).update(deltaMs); + } + + if (!levelChunks.isEmpty()) { + SwimmingLevelChunk lastChunk = levelChunks.getLast(); + // If the swimmer is within 2000 units of the end of the last chunk, add a new one. + if (swimmer.position.y - lastChunk.endY < RETAIN_THRESHOLD) { + SwimmingLevelChunk nextChunk = SwimmingLevelChunk.getNextChunk(); + if (nextChunk != null) { + levelChunks.add(nextChunk); + } + } + + if (levelChunks.getFirst().endY - swimmer.position.y > RETAIN_THRESHOLD) { + levelChunks.remove(0); + } + } + } + + public void resolveCollisions(SwimmerActor swimmer, float deltaMs) { + for (int i = 0; i < levelChunks.size(); i++) { + levelChunks.get(i).resolveCollisions(swimmer, deltaMs); + } + } + + public List getActors() { + List actors = new ArrayList<>(); + for (int i = 0; i < levelChunks.size(); i++) { + actors.addAll(levelChunks.get(i).obstacles); + } + return actors; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ScreenBoundaryActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ScreenBoundaryActor.java new file mode 100644 index 000000000..bd279bb65 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ScreenBoundaryActor.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.graphics.Color; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * An actor which defines a screen boundary. Used for camera positioning. + */ +public class ScreenBoundaryActor extends CollisionActor { + public static final String TYPE = "Screen boundary"; + + private static int currentZIndex = 0; + + public ScreenBoundaryActor(Polygon collisionBody) { + super(collisionBody); + // orange, green, semi-transparent green. + collisionBody.setPaintColors(0xffffa500, Color.BLACK, 0x6400ff00); + + // Give ScreenBoundaryActors increasing z-indices, as these determine sort order, and + // the behavior of ScreenBoundaryActors is based on sort order. + zIndex = currentZIndex++; + } + + @Override + public boolean resolveCollision(Actor other, float deltaMs) { + return false; + } + + @Override + public String getType() { + return ScreenBoundaryActor.TYPE; + } + + public static ScreenBoundaryActor fromJSON(JSONObject json) throws JSONException { + return new ScreenBoundaryActor(Polygon.fromJSON(json.getJSONArray(POLYGON_KEY))); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/StickyActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/StickyActor.java new file mode 100644 index 000000000..48a3ae220 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/StickyActor.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.graphics.Color; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * An actor which slows down the colliding actor upon entry. + */ +public class StickyActor extends CollisionActor { + public static final String TYPE = "Sticky"; + // A "stickiness" factor, which is essentially friction, but doesn't take into account the tilt + // of the device. + private float stickiness = 2.0f; + public boolean isEnabled = true; + + public StickyActor(Polygon collisionBody) { + super(collisionBody); + // cyan, yellow, semi-transparent green. + collisionBody.setPaintColors(Color.CYAN, 0xffffff00, 0x6400ff00); + } + + /** + * Cause the other actor to be slowed down by this actor. + */ + @Override + public boolean resolveCollision(Actor other, float deltaMs) { + if (!isEnabled || other.velocity.getLength() == 0 || !collisionBody.contains(other.position)) { + // Don't bother resolving the collision if the other actor is either not moving, or if the + // other actor is not colliding with this object. + return false; + } + float deltaSeconds = deltaMs / 1000.0f; + Vector2D acceleration = Vector2D.get(other.velocity).normalize(); + if (other.velocity.getLength() < 400) { + acceleration.scale(0.01f * stickiness * Constants.GRAVITY); + } else { + acceleration.scale(stickiness * Constants.GRAVITY); + } + if (Math.signum(other.velocity.x - acceleration.x * deltaSeconds) + != Math.signum(other.velocity.x)) { + // Don't allow stickiness to accelerate the ball in the other direction. + other.velocity.x = 0; + other.velocity.y = 0; + } else { + other.velocity.x -= acceleration.x * deltaSeconds; + other.velocity.y -= acceleration.y * deltaSeconds; + } + return false; + } + + @Override + public String getType() { + return StickyActor.TYPE; + } + + public static StickyActor fromJSON(JSONObject json) throws JSONException { + return new StickyActor(Polygon.fromJSON(json.getJSONArray(POLYGON_KEY))); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmerActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmerActor.java new file mode 100644 index 000000000..73b797b12 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmerActor.java @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.content.res.Resources; +import android.graphics.Canvas; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite.AnimatedSpriteListener; +import com.google.android.apps.santatracker.doodles.shared.CallbackProcess; +import com.google.android.apps.santatracker.doodles.shared.EventBus; +import com.google.android.apps.santatracker.doodles.shared.GameFragment; +import com.google.android.apps.santatracker.doodles.shared.MultiSpriteActor; +import com.google.android.apps.santatracker.doodles.shared.ProcessChain; +import com.google.android.apps.santatracker.doodles.shared.Sprites; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.WaitProcess; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; +import com.google.android.apps.santatracker.doodles.shared.physics.Util; + +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * The player-controlled swimmer in the swimming game. + */ +public class SwimmerActor extends BoundingBoxSpriteActor { + private static final String TAG = SwimmerActor.class.getSimpleName(); + + private static final float ACCELERATION_Y = -500; + private static final float MIN_SPEED = 400; + private static final float DEFAULT_MAX_SPEED = 800; + private static final long SPEED_STEP_DURATION_MS = 10000; + private static final float TILT_VELOCITY = 10000; + + public static final float SWIMMER_SCALE = 1.6f; + public static final int DIVE_DURATION_MS = 1500; + public static final int DIVE_COOLDOWN_MS = 5000; + public static final String SWIMMER_ACTOR_TYPE = "swimmer"; + public static final String KICKOFF_IDLE_SPRITE = "kickoff_idle"; + public static final String KICKOFF_START_SPRITE = "kickoff_start"; + public static final String RINGS_SPRITE = "rings"; + public static final String SWIM_LOOP_SPRITE = "swimming"; + public static final String CAN_COLLIDE_SPRITE = "can_collide"; + public static final String FREEZE_SPRITE = "freeze"; + public static final String DIVE_DOWN_SPRITE = "dive"; + public static final String UNDER_LOOP_SPRITE = "under_loop"; + public static final String RISE_UP_SPRITE = "rise_up"; + public static final float KICKOFF_IDLE_Y_OFFSET = -240; + + private static final Vector2D[] VERTEX_OFFSETS = { + Vector2D.get(0, 0), Vector2D.get(96, 0), + Vector2D.get(96, 90), Vector2D.get(0, 90) + }; + + private static final Map OFFSET_MAP; + + static { + OFFSET_MAP = new HashMap<>(); + OFFSET_MAP.put(KICKOFF_IDLE_SPRITE, Vector2D.get(0, 0)); + OFFSET_MAP.put(KICKOFF_START_SPRITE, Vector2D.get(0, 0)); + OFFSET_MAP.put(RINGS_SPRITE, Vector2D.get(-60, -20)); // TODO + OFFSET_MAP.put(SWIM_LOOP_SPRITE, Vector2D.get(0, 0)); + OFFSET_MAP.put(CAN_COLLIDE_SPRITE, Vector2D.get(0, 0)); + OFFSET_MAP.put(FREEZE_SPRITE, Vector2D.get(0, 0)); + OFFSET_MAP.put(DIVE_DOWN_SPRITE, Vector2D.get(0, 0)); + OFFSET_MAP.put(UNDER_LOOP_SPRITE, Vector2D.get(0, 0)); + OFFSET_MAP.put(RISE_UP_SPRITE, Vector2D.get(0, 0)); + } + + public boolean controlsEnabled = true; + public boolean isInvincible = false; + public boolean isUnderwater = false; + public boolean isDead = false; + + private MultiSpriteActor multiSpriteActor; + private AnimatedSprite canCollideSprite; + private AnimatedSprite freezeSprite; + private String collidedObjectType; + + private AnimatedSprite ringsSprite; + private Vector2D ringsSpriteOffset; + + private float restartSpeed = MIN_SPEED; + private float maxSpeed = DEFAULT_MAX_SPEED; + private long currentSpeedStepTime = 0; + + private boolean diveEnabled = false; + private float targetX; + + private List processChains = new ArrayList<>(); + + public SwimmerActor(Polygon collisionBody, MultiSpriteActor spriteActor) { + super(collisionBody, spriteActor, + Vector2D.get(OFFSET_MAP.get(KICKOFF_IDLE_SPRITE)).scale(SWIMMER_SCALE), SWIMMER_ACTOR_TYPE); + + multiSpriteActor = spriteActor; + canCollideSprite = multiSpriteActor.sprites.get(CAN_COLLIDE_SPRITE); + canCollideSprite.setLoop(false); + freezeSprite = multiSpriteActor.sprites.get(FREEZE_SPRITE); + freezeSprite.setLoop(false); + multiSpriteActor.sprites.get(DIVE_DOWN_SPRITE).addListener(new AnimatedSpriteListener() { + @Override + public void onLoop() { + zIndex = -3; + setSprite(UNDER_LOOP_SPRITE); + } + }); + multiSpriteActor.sprites.get(RISE_UP_SPRITE).addListener(new AnimatedSpriteListener() { + @Override + public void onLoop() { + zIndex = 0; + setSprite(SWIM_LOOP_SPRITE); + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.swimming_dive_up); + } + }); + multiSpriteActor.sprites.get(SWIM_LOOP_SPRITE).addListener(new AnimatedSpriteListener() { + @Override + public void onFrame(int index) { + if (index == 5 || index == 13) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.swimming_ice_splash_a); + } + } + }); + + ringsSprite = multiSpriteActor.sprites.get(RINGS_SPRITE); + ringsSprite.setPaused(true); + ringsSprite.setHidden(true); + ringsSprite.setScale(SWIMMER_SCALE, SWIMMER_SCALE); + ringsSprite.addListener(new AnimatedSpriteListener() { + @Override + public void onLoop() { + ringsSprite.setHidden(true); + ringsSprite.setPaused(true); + } + }); + ringsSpriteOffset = Vector2D.get(OFFSET_MAP.get(RINGS_SPRITE)).scale(SWIMMER_SCALE); + + multiSpriteActor.sprites.get(KICKOFF_START_SPRITE).addListener(new AnimatedSpriteListener() { + @Override + public void onLoop() { + diveEnabled = true; + diveDown(); + } + + @Override + public void onFrame(int index) { + if (index == 3) { + velocity.set(0, -restartSpeed); + } + } + }); + + zIndex = 0; + alpha = 1.0f; + scale = SWIMMER_SCALE; + targetX = position.x; + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + + ProcessChain.updateChains(processChains, deltaMs); + + // Update x position based on tilt. + float frameVelocityX = TILT_VELOCITY * deltaMs / 1000; + float positionDeltaX = targetX - position.x; + if (Math.abs(positionDeltaX) < frameVelocityX) { + // We will overshoot if we apply the frame velocity. Just go straight to the target position. + moveTo(targetX, position.y); + } else { + moveTo(position.x + Math.signum(positionDeltaX) * frameVelocityX, position.y); + } + + // Update acceleration and frame rate if necessary. + if (velocity.getLength() > 1) { + velocity.y = Math.max(-maxSpeed, velocity.y + ACCELERATION_Y * deltaMs / 1000); + if (velocity.y == -maxSpeed) { + multiSpriteActor.sprites.get(SWIM_LOOP_SPRITE).setFPS(24); + } else { + multiSpriteActor.sprites.get(SWIM_LOOP_SPRITE).setFPS(48); + } + currentSpeedStepTime += deltaMs; + if (currentSpeedStepTime > SPEED_STEP_DURATION_MS) { + maxSpeed += 500; + currentSpeedStepTime = 0; + } + } + + ringsSprite.update(deltaMs); + ringsSprite.setPosition(spriteActor.position.x + ringsSpriteOffset.x, + spriteActor.position.y + ringsSpriteOffset.y); + } + + @Override + public void draw(Canvas canvas) { + if (hidden) { + return; + } + spriteActor.draw(canvas, spriteOffset.x, spriteOffset.y, + spriteActor.sprite.frameWidth * scale, spriteActor.sprite.frameHeight * scale); + ringsSprite.draw(canvas); + collisionBody.draw(canvas); + } + + @Override + public JSONObject toJSON() { + return null; + } + + public void setSprite(String key) { + multiSpriteActor.setSprite(key); + spriteOffset.set(OFFSET_MAP.get(key)).scale(SWIMMER_SCALE); + } + + public void moveTo(float x, float y) { + collisionBody.moveTo(x, y); + position.set(x, y); + spriteActor.position.set(x, y); + targetX = x; + } + + public void updateTargetPositionFromTilt(Vector2D tilt, float levelWidth) { + if (controlsEnabled) { + // Decrease the amount of tilt necessary to move the swimmer. + float tiltPercentage = (float) (tilt.x / (Math.PI / 2)); + tiltPercentage *= 2.5f; + + int levelPadding = 60; + targetX = Util.clamp( + (levelWidth / 2) - (collisionBody.getWidth() / 2) + (tiltPercentage * levelWidth / 2), + 0 - collisionBody.getWidth() + levelPadding, + levelWidth - (2 * collisionBody.getWidth()) - levelPadding); + } + } + + public void startSwimming() { + setSprite(KICKOFF_START_SPRITE); + } + + public void collide(String objectType) { + restartSpeed = Math.max(MIN_SPEED, Math.abs(velocity.y / 4)); + maxSpeed = restartSpeed; + currentSpeedStepTime = 0; + moveTo(positionBeforeFrame.x, positionBeforeFrame.y); + velocity.set(0, 0); + controlsEnabled = false; + + if (objectType.equals(DUCK) || objectType.equals(ICE_CUBE)) { + EventBus.getInstance().sendEvent(EventBus.SHAKE_SCREEN); + EventBus.getInstance().sendEvent(EventBus.VIBRATE); + + if (objectType.equals(DUCK)) { + setSprite(SwimmerActor.CAN_COLLIDE_SPRITE); + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.swimming_duck_collide); + } else { // Ice cube. + setSprite(SwimmerActor.FREEZE_SPRITE); + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.swimming_ice_collide); + } + } else { // Octopus. + // Just play the sound for the octopus. It vibrates later (when it actually grabs the lemon). + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.swimming_grab); + } + collidedObjectType = objectType; + isDead = true; + } + + public void endGameWithoutCollision() { + controlsEnabled = false; + collidedObjectType = HAND_GRAB; + isDead = true; + } + + public String getCollidedObjectType() { + return collidedObjectType; + } + + public void diveDown() { + if (controlsEnabled && diveEnabled) { + EventBus.getInstance().sendEvent(EventBus.SWIMMING_DIVE); + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.swimming_dive_down); + ringsSprite.setHidden(false); + ringsSprite.setPaused(false); + isUnderwater = true; + setSprite(DIVE_DOWN_SPRITE); + diveEnabled = false; + + ProcessChain waitThenRiseUp = new WaitProcess(DIVE_DURATION_MS).then(new CallbackProcess() { + @Override + public void updateLogic(float deltaMs) { + isUnderwater = false; + setSprite(RISE_UP_SPRITE); + } + }).then(new WaitProcess(DIVE_COOLDOWN_MS)).then(new CallbackProcess() { + @Override + public void updateLogic(float deltaMs) { + diveEnabled = true; + } + }); + processChains.add(waitThenRiseUp); + } + } + + public static final SwimmerActor create(Vector2D position, Resources res, + final GameFragment gameFragment) { + if (gameFragment.isDestroyed) { + return null; + } + Map spriteMap = new HashMap<>(); + spriteMap.put(KICKOFF_IDLE_SPRITE, + AnimatedSprite.fromFrames(res, Sprites.penguin_swim_idle)); + if (gameFragment.isDestroyed) { + return null; + } + spriteMap.put(KICKOFF_START_SPRITE, + AnimatedSprite.fromFrames(res, Sprites.penguin_swim_start)); + if (gameFragment.isDestroyed) { + return null; + } + spriteMap.put(RINGS_SPRITE, + AnimatedSprite.fromFrames(res, Sprites.swimming_rings)); + if (gameFragment.isDestroyed) { + return null; + } + spriteMap.put(SWIM_LOOP_SPRITE, + AnimatedSprite.fromFrames(res, Sprites.penguin_swim_swimming)); + if (gameFragment.isDestroyed) { + return null; + } + spriteMap.put(CAN_COLLIDE_SPRITE, + AnimatedSprite.fromFrames(res, Sprites.penguin_swim_dazed)); + if (gameFragment.isDestroyed) { + return null; + } + spriteMap.put(FREEZE_SPRITE, + AnimatedSprite.fromFrames(res, Sprites.penguin_swim_frozen)); + if (gameFragment.isDestroyed) { + return null; + } + spriteMap.put(DIVE_DOWN_SPRITE, + AnimatedSprite.fromFrames(res, Sprites.penguin_swim_descending)); + if (gameFragment.isDestroyed) { + return null; + } + spriteMap.put(UNDER_LOOP_SPRITE, + AnimatedSprite.fromFrames(res, Sprites.penguin_swim_swimmingunderwater)); + if (gameFragment.isDestroyed) { + return null; + } + spriteMap.put(RISE_UP_SPRITE, + AnimatedSprite.fromFrames(res, Sprites.penguin_swim_ascending)); + if (gameFragment.isDestroyed) { + return null; + } + MultiSpriteActor spriteActor = + new MultiSpriteActor(spriteMap, KICKOFF_IDLE_SPRITE, position, Vector2D.get(0, 0)); + if (gameFragment.isDestroyed) { + return null; + } + + return new SwimmerActor(getBoundingBox(position, VERTEX_OFFSETS, SWIMMER_SCALE), spriteActor); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingFragment.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingFragment.java new file mode 100644 index 000000000..89914edc2 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingFragment.java @@ -0,0 +1,896 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Point; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.Build.VERSION; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Vibrator; +import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.FrameLayout.LayoutParams; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.ToggleButton; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.AndroidUtils; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.Camera; +import com.google.android.apps.santatracker.doodles.shared.CameraShake; +import com.google.android.apps.santatracker.doodles.shared.DoodleConfig; +import com.google.android.apps.santatracker.doodles.shared.EventBus; +import com.google.android.apps.santatracker.doodles.shared.EventBus.EventBusListener; +import com.google.android.apps.santatracker.doodles.shared.GameFragment; +import com.google.android.apps.santatracker.doodles.shared.GameType; +import com.google.android.apps.santatracker.doodles.shared.HistoryManager; +import com.google.android.apps.santatracker.doodles.shared.HistoryManager.HistoryListener; +import com.google.android.apps.santatracker.doodles.shared.PineappleLogger; +import com.google.android.apps.santatracker.doodles.shared.RectangularInstructionActor; +import com.google.android.apps.santatracker.doodles.shared.SpriteActor; +import com.google.android.apps.santatracker.doodles.shared.Sprites; +import com.google.android.apps.santatracker.doodles.shared.UIUtil; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.sound.SoundManager; +import com.google.android.apps.santatracker.doodles.tilt.SwimmingModel.SwimmingState; +import com.google.android.apps.santatracker.util.MeasurementManager; +import com.google.firebase.analytics.FirebaseAnalytics; + +import java.io.File; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.SWIMMING_GAME_TYPE; + +/** + * The main fragment for the swimming game. + */ +public class SwimmingFragment extends GameFragment + implements SensorEventListener, EventBusListener { + private static final String TAG = SwimmingFragment.class.getSimpleName(); + public static final String CURRENT_LEVEL_KEY = "CURRENT_LEVEL"; + private static final float ACCELEROMETER_SCALE = 1.5f / 9.8f; // Scale to range -1.5:1.5. + private static final int END_VIEW_ON_DEATH_DELAY_MS = 1400; + + public static boolean editorMode = false; + + private SwimmingView swimmingView; + private DiveView diveView; + private TextView countdownView; + private Button saveButton; + private Button loadButton; + private Button resetButton; + private Button deleteButton; + private ToggleButton collisionModeButton; + private SwimmingModel model; + + private SwimmingLevelManager levelManager; + private SensorManager sensorManager; + private Sensor accelerometerSensor; + private int displayRotation; + + private int playCount = 0; + private long titleDurationMs = GameFragment.TITLE_DURATION_MS; + private SwimmingModel tempLevel; + private boolean mIsGameOver = false; + + public SwimmingFragment() { + super(); + } + + public SwimmingFragment(Context context, DoodleConfig doodleConfig, PineappleLogger logger, + boolean editorMode) { + super(context, doodleConfig, logger); + SwimmingFragment.editorMode = editorMode; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + if (context == null) { + return null; + } + + levelManager = new SwimmingLevelManager(context); + + wrapper = new FrameLayout(context); + + titleView = getTitleView(R.drawable.penguin_swim_loadingscreen, R.string.swimming); + wrapper.addView(titleView); + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + loadGame(); + } + }); + return wrapper; + } + + @Override + protected void firstPassLoadOnUiThread() { + final FrameLayout.LayoutParams wrapperLP = + new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + + final SwimmingFragment that = this; + scoreView = getScoreView(); + pauseView = getPauseView(); + + int diveViewBottomMargin = (int) context.getResources().getDimension( + R.dimen.dive_margin_bottom); + int diveViewStartMargin = (int) context.getResources().getDimension( + R.dimen.dive_margin_left); + int diveViewSize = (int) context.getResources().getDimension( + R.dimen.dive_image_size); + + FrameLayout.LayoutParams diveViewLP = new LayoutParams(diveViewSize, diveViewSize); + diveViewLP.setMargins(diveViewStartMargin, 0, 0, diveViewBottomMargin); + diveViewLP.gravity = Gravity.BOTTOM | Gravity.LEFT; + + if (VERSION.SDK_INT >= 17) { + diveViewLP.setMarginStart(diveViewStartMargin); + } + diveView = new DiveView(context); + + countdownView = new TextView(context); + countdownView.setGravity(Gravity.CENTER); + countdownView.setTextColor(context.getResources().getColor(R.color.ui_text_yellow)); + countdownView.setTypeface(Typeface.DEFAULT_BOLD); + countdownView.setText("0"); + countdownView.setVisibility(View.INVISIBLE); + Locale locale = context.getResources().getConfiguration().locale; + countdownView.setText(NumberFormat.getInstance(locale).format(3)); + Point screenDimens = AndroidUtils.getScreenSize(); + UIUtil.fitToBounds(countdownView, screenDimens.x / 10, screenDimens.y / 10); + + LinearLayout gameView = new LinearLayout(context); + gameView.setOrientation(LinearLayout.VERTICAL); + + // Add game view. + swimmingView = new SwimmingView(context); + LinearLayout.LayoutParams lp = + new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT, + 7); + gameView.addView(swimmingView, lp); + + if (editorMode) { + LinearLayout buttonWrapper = new LinearLayout(context); + buttonWrapper.setOrientation(LinearLayout.HORIZONTAL); + lp = + new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT, + 1); + gameView.addView(buttonWrapper, lp); + + resetButton = + getButton( + R.string.reset_level, + new OnClickListener() { + @Override + public void onClick(View v) { + SwimmingModel level = levelManager.loadDefaultLevel(); + initializeLevel(level, false); + + getActivity().getSharedPreferences( + context.getString(R.string.swimming), Context.MODE_PRIVATE) + .edit() + .putString(CURRENT_LEVEL_KEY, null) + .commit(); + } + }); + deleteButton = + getButton( + R.string.delete_levels, + new OnClickListener() { + @Override + public void onClick(View v) { + DialogFragment dialogFragment = new DeleteLevelDialogFragment(); + dialogFragment.show(getActivity().getFragmentManager(), "delete"); + } + }); + loadButton = + getButton( + R.string.load_level, + new OnClickListener() { + @Override + public void onClick(View v) { + DialogFragment dialogFragment = new LoadLevelDialogFragment(that); + dialogFragment.show(getActivity().getFragmentManager(), "load"); + } + }); + saveButton = + getButton( + R.string.save_level, + new OnClickListener() { + @Override + public void onClick(View v) { + DialogFragment dialogFragment = new SaveLevelDialogFragment(that); + dialogFragment.show(getActivity().getFragmentManager(), "save"); + } + }); + collisionModeButton = new ToggleButton(context); + collisionModeButton.setText(R.string.scenery_mode); + collisionModeButton.setTextOff(context.getString(R.string.scenery_mode)); + collisionModeButton.setTextOn(context.getString(R.string.collision_mode)); + collisionModeButton.setOnCheckedChangeListener( + new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + model.collisionMode = isChecked; + } + }); + + lp = + new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.MATCH_PARENT, + 1); + buttonWrapper.addView(deleteButton, lp); + buttonWrapper.addView(resetButton, lp); + buttonWrapper.addView(loadButton, lp); + buttonWrapper.addView(saveButton, lp); + buttonWrapper.addView(collisionModeButton, lp); + } + + sensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE); + accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + if (accelerometerSensor == null) { + // TODO: The game won't be playable without this, so what should we do? + Log.d(TAG, "Accelerometer sensor is null"); + } + displayRotation = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay().getRotation(); + + wrapper.addView(gameView, 0, wrapperLP); + wrapper.addView(countdownView, 1); + wrapper.addView(diveView, 2, diveViewLP); + wrapper.addView(scoreView, 3); + wrapper.addView(pauseView, 4); + } + + @Override + protected void secondPassLoadOnBackgroundThread() { + super.secondPassLoadOnBackgroundThread(); + + tempLevel = new SwimmingModel(); + final SwimmingModel level = tempLevel; + historyManager = new HistoryManager( + context, + new HistoryListener() { + @Override + public void onFinishedLoading() { + addBestTimeLine(level); + } + + @Override + public void onFinishedSaving() {} + }); + + initializeLevel(tempLevel, true); + } + + @Override + protected void finalPassLoadOnUiThread() { + soundManager = SoundManager.getInstance(); + loadSounds(); + + onFinishedLoading(); + startHandlers(); + tempLevel = null; + } + + @Override + protected void replay() { + super.replay(); + SwimmingModel level = new SwimmingModel(); + initializeLevel(level, false); + } + + @Override + protected void resume() { + super.resume(); + if (uiRefreshHandler != null) { + sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_GAME); + uiRefreshHandler.start(swimmingView); + } + } + + @Override + public void onPause() { + super.onPause(); + if (sensorManager != null) { + sensorManager.unregisterListener(this); + } + // Clear the path list because it's static and otherwise it hangs around forever. + if (SwimmingLevelChunk.pathList != null) { + SwimmingLevelChunk.pathList.clear(); + } + } + + @Override + protected void onDestroyHelper() { + if (swimmingView != null) { + swimmingView.setModel(null); + } + model = null; + tempLevel = null; + levelManager = null; + + if (SwimmingLevelChunk.swimmingLevelChunks != null) { + SwimmingLevelChunk.swimmingLevelChunks.clear(); + } + if (SwimmingLevelChunk.pathList != null) { + SwimmingLevelChunk.pathList.clear(); + } + } + + @Override + public void update(float deltaMs) { + if (isPaused) { + return; + } + model.update(deltaMs); + diveView.update(deltaMs); + + // If we are in editor mode, hide the intro animation right away and skip the camera pan. + // Otherwise, wait until it has finished playing before fading and then run the camera pan. + if ((editorMode || model.timeElapsed >= titleDurationMs) + && model.getState() == SwimmingState.INTRO) { + if (editorMode) { + Log.d(TAG, "Hiding intro animation right away."); + + // Run on UI thread since background threads can't touch the intro view. + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + titleView.setVisibility(View.GONE); + } + }); + model.setState(SwimmingState.WAITING); + } else { + Log.d(TAG, "Fading out and hiding intro animation."); + + // Run on UI thread since background threads can't touch the intro view. + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + hideTitle(); + } + }); + model.setState(SwimmingState.WAITING); + } + } + + } + + @Override + public void onSensorChanged(SensorEvent event) { + if (event.values == null || model == null) { + return; + } + int sensorType = event.sensor.getType(); + if (sensorType == Sensor.TYPE_ACCELEROMETER) { + float[] adjustedEventValues = + AndroidUtils.getAdjustedAccelerometerValues(displayRotation, event.values); + float x = -adjustedEventValues[0] * ACCELEROMETER_SCALE; + float y = -adjustedEventValues[1] * ACCELEROMETER_SCALE; + // Accelerometer input is very noisy, so we filter it using a (simple) low-pass filter. + float weight = 0.1f; + model.tilt.x = model.tilt.x + weight * (x - model.tilt.x); + model.tilt.y = model.tilt.y + weight * (y - model.tilt.y); + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int i) { + } + + @Override + public void onEventReceived(int type, final Object data) { + if (isDestroyed) { + return; + } + switch(type) { + case EventBus.SCORE_CHANGED: + int distance = integerValue(data); + boolean shouldAddStar = false; + + if (model.currentScoreThreshold < SwimmingModel.SCORE_THRESHOLDS.length + && distance >= SwimmingModel.SCORE_THRESHOLDS[model.currentScoreThreshold]) { + // Pop in star. + shouldAddStar = true; + model.currentScoreThreshold++; + } + updateScoreUi(distance, shouldAddStar); + break; + case EventBus.SWIMMING_DIVE: + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + diveView.startCooldown(); + } + }); + break; + + case EventBus.GAME_STATE_CHANGED: + SwimmingState state = (SwimmingState) data; + mIsGameOver = false; + if (state == SwimmingState.FINISHED) { + mIsGameOver = true; + calculateBestDistance(); + calculateStars(); + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + pauseView.hidePauseButton(); + } + }); + final Handler handler = new Handler(Looper.getMainLooper()); + handler.postDelayed(new Runnable() { + @Override + public void run() { + if (model == null) { + return; + } + int bestDistance = historyManager.getBestDistance(GameType.SWIMMING).intValue(); + String collidedObjectType = model.swimmer.getCollidedObjectType(); + scoreView.updateBestScore( + AndroidUtils.getText( + context.getResources(), R.string.swimming_score, bestDistance)); + scoreView.setShareDrawable( + getShareImageDrawable(collidedObjectType)); + + diveView.hide(); + scoreView.animateToEndState(); + } + }, END_VIEW_ON_DEATH_DELAY_MS); + } + + // [ANALYTICS] + FirebaseAnalytics analytics = FirebaseAnalytics.getInstance(getActivity()); + MeasurementManager.recordSwimmingEnd(analytics, + model.getStarCount(), + model.distanceMeters, + model.swimmer.getCollidedObjectType()); + break; + + case EventBus.PLAY_SOUND: + int resId = (int) data; + if (soundManager != null) { + soundManager.play(resId); + } + break; + + case EventBus.MUTE_SOUNDS: + boolean shouldMute = (boolean) data; + if (soundManager != null) { + if (shouldMute) { + soundManager.mute(); + } else { + soundManager.unmute(); + } + } + break; + + case EventBus.GAME_LOADED: + long loadTimeMs = (long) data; + titleDurationMs = Math.max(0, titleDurationMs - loadTimeMs); + Log.d(TAG, "Waiting " + titleDurationMs + "ms and then hiding title."); + break; + } + + } + + @Nullable + private Drawable getShareImageDrawable(String collidedObjectType) { + return ContextCompat.getDrawable(getActivity(), R.drawable.winner); + } + + private void initializeLevel(final SwimmingModel newLevel, boolean shouldPlayIntro) { + EventBus.getInstance().clearListeners(); + EventBus.getInstance().register(newLevel, EventBus.VIBRATE); + EventBus.getInstance().register(newLevel, EventBus.SHAKE_SCREEN); + EventBus.getInstance().register(newLevel, EventBus.GAME_STATE_CHANGED); + + // Initialize Activity-specific stuff. + EventBus.getInstance().register(this); + + Point size = AndroidUtils.getScreenSize(); + newLevel.screenWidth = size.x; + newLevel.screenHeight = size.y; + newLevel.addActor(new Camera(newLevel.screenWidth, newLevel.screenHeight)); + newLevel.addActor(new CameraShake()); + // Center the level horizontally on the screen and scale to fit. + newLevel.camera.moveImmediatelyTo( + Vector2D.get(0, 0), + Vector2D.get(SwimmingModel.LEVEL_WIDTH, 0)); + newLevel.playCount = playCount++; + newLevel.locale = getResources().getConfiguration().locale; + + if (isDestroyed) { + return; + } + SwimmerActor swimmer = SwimmerActor.create(Vector2D.get(0, 0), context.getResources(), + this); + if (swimmer == null) { + return; + } + swimmer.moveTo( + SwimmingModel.LEVEL_WIDTH / 2 - swimmer.collisionBody.getWidth() / 2, + SwimmerActor.KICKOFF_IDLE_Y_OFFSET); + newLevel.addActor(swimmer); + + + DistanceMarkerActor startingBlock = + new DistanceMarkerActor(0, ColoredRectangleActor.STARTING_BLOCK, 1000); + newLevel.addActor(startingBlock); + + SpriteActor banner = new SpriteActor( + AnimatedSprite.fromFrames(context.getResources(), Sprites.penguin_swim_banner), + Vector2D.get(SwimmingModel.LEVEL_WIDTH / 2, startingBlock.position.y), Vector2D.get()); + banner.scale = 2; + banner.zIndex = 2; + banner.sprite.setAnchor(banner.sprite.frameWidth / 2, banner.sprite.frameHeight - 50); + newLevel.addActor(banner); + + newLevel.addActor(new DistanceMarkerActor(30, ColoredRectangleActor.DISTANCE_30M)); + newLevel.addActor(new DistanceMarkerActor(50, ColoredRectangleActor.DISTANCE_50M)); + newLevel.addActor(new DistanceMarkerActor(100, ColoredRectangleActor.DISTANCE_100M)); + newLevel.addActor(new DistanceMarkerActor( + SwimmingLevelChunk.LEVEL_LENGTH_IN_METERS, ColoredRectangleActor.DISTANCE_LEVEL_LENGTH)); + if (historyManager != null) { + addBestTimeLine(newLevel); + } + + if (isDestroyed) { + return; + } + ObstacleManager obstacleManager = new ObstacleManager(swimmer, context); + newLevel.addActor(obstacleManager); + + newLevel.camera.position.y = -newLevel.camera.toWorldScale(newLevel.screenHeight); + newLevel.clampCameraPosition(); // Clamp camera so that it doesn't jump when we start swimming. + + AnimatedSprite swimmingTutorialSprite = + AnimatedSprite.fromFrames(context.getResources(), Sprites.tutorial_swimming); + swimmingTutorialSprite.setFPS(6); + RectangularInstructionActor instructions = new RectangularInstructionActor( + context.getResources(), swimmingTutorialSprite); + instructions.hidden = true; + instructions.scale = (newLevel.screenWidth * 0.6f) / instructions.rectangle.frameWidth; + // Put instructions at top right, slightly below pause button. + instructions.position.set(newLevel.screenWidth / 2 - instructions.getScaledWidth() / 2, 70); + newLevel.addUiActor(instructions); + + newLevel.setCountdownView(countdownView); + + if (!shouldPlayIntro) { + // Skip State.INTRO. + newLevel.setState(SwimmingState.WAITING); + } + if (isDestroyed) { + return; + } + model = newLevel; + swimmingView.setModel(model); + + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + initializeLevelUiThread(newLevel); + } + }); + + // Hint that this would be a good time to do some garbage collection since we should be able + // to get rid of any stuff from the previous level at this time. + System.gc(); + } + + // Initialize level parts that need to happen in UI thread. + private void initializeLevelUiThread(final SwimmingModel newLevel) { + if (isDestroyed) { + return; + } + scoreView.updateCurrentScore( + AndroidUtils.getText(context.getResources(), R.string.swimming_score, 0), false); + pauseView.showPauseButton(); + diveView.show(); + newLevel.vibrator = (Vibrator) getActivity().getSystemService(Activity.VIBRATOR_SERVICE); + } + + @Override + protected void loadSounds() { + super.loadSounds(); + soundManager.loadShortSound(context, R.raw.swimming_dive_down); + soundManager.loadShortSound(context, R.raw.swimming_dive_up); + soundManager.loadShortSound(context, R.raw.swimming_ice_splash_a); + soundManager.loadShortSound(context, R.raw.swimming_duck_collide); + soundManager.loadShortSound(context, R.raw.swimming_ice_collide); + soundManager.loadShortSound(context, R.raw.swimming_grab); + } + + private void addBestTimeLine(SwimmingModel level) { + Double bestDistance = historyManager.getBestDistance(GameType.SWIMMING); + if (bestDistance != null) { + level.addActor(new DistanceMarkerActor(bestDistance.intValue(), + ColoredRectangleActor.DISTANCE_PR)); + } + } + + private void calculateStars() { + Integer bestStarCount = historyManager.getBestStarCount(GameType.SWIMMING); + int modelStarCount = model.getStarCount(); + if (bestStarCount == null || bestStarCount < modelStarCount) { + historyManager.setBestStarCount(GameType.SWIMMING, modelStarCount); + } + } + + private void calculateBestDistance() { + Double bestDistance = historyManager.getBestDistance(GameType.SWIMMING); + if (bestDistance == null || bestDistance < model.distanceMeters) { + historyManager.setBestDistance(GameType.SWIMMING, model.distanceMeters); + } + } + + private Button getButton(int textId, OnClickListener onClickListener) { + Button button = new Button(context); + button.setText(textId); + button.setOnClickListener(onClickListener); + return button; + } + + private void updateScoreUi(final int score, final boolean shouldShowStars) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + scoreView.updateCurrentScore( + AndroidUtils.getText(context.getResources(), R.string.swimming_score, score), + shouldShowStars); + if (shouldShowStars) { + scoreView.addStar(); + } + } + }); + + } + + private int integerValue(Object object) { + if (object instanceof Integer) { + return (int) object; + } else { + throw new IllegalArgumentException("Unknown event data type"); + } + } + + @Override + public void onGamePause() { + if (model != null && model.swimmer != null) { + model.swimmer.controlsEnabled = false; + } + super.onGamePause(); + } + + @Override + protected void onGameResume() { + if (model != null && model.swimmer != null) { + model.swimmer.controlsEnabled = true; + } + super.onGameResume(); + } + + @Override + protected void onGameReplay() { + if (model != null && model.swimmer != null) { + model.swimmer.controlsEnabled = true; + } + super.onGameReplay(); + } + + @Override + protected boolean onTitleTapped() { + if (model != null && model.getState() == SwimmingState.INTRO) { + // If the user taps the screen while the intro animation is playing, end the intro + // immediately and transition into the game. + model.timeElapsed = GameFragment.TITLE_DURATION_MS; + return true; + } + return false; + } + + @Override + protected String getGameType() { + return SWIMMING_GAME_TYPE; + } + + @Override + protected float getScore() { + return model.distanceMeters; + } + + @Override + protected int getShareImageId() { + String collidedObjectType = model.swimmer.getCollidedObjectType(); + if (BoundingBoxSpriteActor.ICE_CUBE.equals(collidedObjectType)) { + return 0; + } else if (BoundingBoxSpriteActor.DUCK.equals(collidedObjectType)) { + return 1; + } else { // Octopus hand grab. + return 2; + } + } + + /** + * A dialog fragment for loading a swimming level. + */ + public static class LoadLevelDialogFragment extends DialogFragment { + private SwimmingFragment swimmingFragment; + public LoadLevelDialogFragment(SwimmingFragment swimmingFragment) { + this.swimmingFragment = swimmingFragment; + } + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final String[] fileList = + SwimmingLevelManager.levelsDir.exists() + ? SwimmingLevelManager.levelsDir.list() + : new String[0]; + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder + .setTitle(R.string.load_level) + .setItems( + fileList, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + SwimmingModel level = swimmingFragment.levelManager.loadLevel(fileList[which]); + swimmingFragment.initializeLevel(level, false); + + // Save the current level so we automatically come back to it later. + getActivity() + .getSharedPreferences( + swimmingFragment.context.getString(R.string.swimming), + Context.MODE_PRIVATE) + .edit() + .putString(CURRENT_LEVEL_KEY, fileList[which]) + .commit(); + } + }); + return builder.create(); + } + } + + /** + * A dialog fragment for saving a swimming level. + */ + public static class SaveLevelDialogFragment extends DialogFragment { + private SwimmingFragment swimmingFragment; + public SaveLevelDialogFragment(SwimmingFragment swimmingFragment) { + this.swimmingFragment = swimmingFragment; + } + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final EditText editText = new EditText(swimmingFragment.context); + editText.setText(swimmingFragment.model.levelName); + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder + .setTitle(R.string.save_level) + .setView(editText) + .setPositiveButton( + R.string.save, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + swimmingFragment.levelManager.saveLevel( + swimmingFragment.model, editText.getText().toString()); + } + }) + .setNegativeButton( + R.string.cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // Do nothing. + } + }); + return builder.create(); + } + } + + /** + * A dialog fragment for deleting a swimming level. + */ + public static class DeleteLevelDialogFragment extends DialogFragment { + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final List selectedItems = new ArrayList<>(); + final String[] fileList = + SwimmingLevelManager.levelsDir.exists() + ? SwimmingLevelManager.levelsDir.list() + : new String[0]; + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder + .setTitle(R.string.delete_levels) + .setMultiChoiceItems( + fileList, + null, + new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, boolean isChecked) { + if (isChecked) { + selectedItems.add(which); + } else if (selectedItems.contains(which)) { + selectedItems.remove(Integer.valueOf(which)); + } + } + }) + .setPositiveButton( + R.string.delete, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + for (Integer selection : selectedItems) { + File file = new File(SwimmingLevelManager.levelsDir, fileList[selection]); + file.delete(); + } + } + }) + .setNegativeButton( + R.string.cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // Do nothing. + } + }); + return builder.create(); + } + } + + public boolean isGameOver() { + return mIsGameOver; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingLevelChunk.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingLevelChunk.java new file mode 100644 index 000000000..21f561f94 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingLevelChunk.java @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapFactory.Options; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.Log; + +import com.google.android.apps.santatracker.doodles.Config; +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; +import com.google.android.apps.santatracker.doodles.shared.physics.Util; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Random; + +/** + * One chunk of a level in the swimming game. + */ +public class SwimmingLevelChunk extends Actor { + private static final String TAG = SwimmingLevelChunk.class.getSimpleName(); + + public static final int LEVEL_LENGTH_IN_METERS = 500; + public static Queue swimmingLevelChunks; + + public static List pathList; + public static final int CHUNK_HEIGHT = 5000; + public static final int NUM_ROWS = 100; + public static final int NUM_COLS = 50; + public static final float COL_WIDTH = SwimmingModel.LEVEL_WIDTH / (float) NUM_COLS; + public static final float ROW_HEIGHT = CHUNK_HEIGHT / (float) NUM_ROWS; + private static final int SOLUTION_PATH_NUM_COLS = 50; + private static final Random RANDOM = new Random(); + + private static final List TYPES; + static { + TYPES = new ArrayList<>(); + TYPES.add(BoundingBoxSpriteActor.ICE_CUBE); + TYPES.add(BoundingBoxSpriteActor.DUCK); + TYPES.add(BoundingBoxSpriteActor.HAND_GRAB); + } + + private final float DEFAULT_OBSTACLE_DENSITY; + + public final float startY; + public final float endY; + public List obstacles; + private SolutionPath solutionPath; + private boolean mirrored; + + public static SwimmingLevelChunk create(float startY, Context context) { + if (pathList == null || pathList.size() == 0) { + loadChunkTemplates(context.getResources()); + } + // Increase the probability that the random chunk will be a "middle open" chunk. + int pathIndex = Math.min(pathList.size() - 1, RANDOM.nextInt(pathList.size() + 1)); + SolutionPath solutionPath = pathList.get(pathIndex); + return new SwimmingLevelChunk(startY, solutionPath, RANDOM.nextBoolean(), context); + } + + public static void generateAllLevelChunks(float startY, Context context) { + long startTime = System.currentTimeMillis(); + swimmingLevelChunks = new LinkedList<>(); + SwimmingLevelChunk chunk = create(startY, context); + while (SwimmingModel.getMetersFromWorldY(chunk.endY) < LEVEL_LENGTH_IN_METERS) { + swimmingLevelChunks.add(chunk); + chunk = create(chunk.endY, context); + } + Log.d(TAG, "generateAllLevelChunks: finished in " + + ((System.currentTimeMillis() - startTime) / 1000.0f) + + " seconds."); + } + + public static SwimmingLevelChunk getNextChunk() { + if (!swimmingLevelChunks.isEmpty()) { + return swimmingLevelChunks.remove(); + } + return null; + } + + private SwimmingLevelChunk(float startY, SolutionPath solutionPath, + boolean mirrored, Context context) { + + // Get swimming obstacle density from config + Config config = new Config(); + DEFAULT_OBSTACLE_DENSITY = (float) config.SWIMMING_OBSTACLE_DENSITY; + + this.solutionPath = solutionPath; + this.mirrored = mirrored; + this.startY = startY; + generateObstacles(context); + removeObstaclesFromSolutionPath(startY); + this.endY = startY - solutionPath.getChunkHeight(); + } + + @Override + public void update(float deltaMs) { + for (int i = 0; i < obstacles.size(); i++) { + obstacles.get(i).update(deltaMs); + } + } + + @Override + public void draw(Canvas canvas) { + //solutionPath.draw(canvas, startY, mirrored); + for (int i = 0; i < obstacles.size(); i++) { + obstacles.get(i).draw(canvas); + } + } + + public void resolveCollisions(SwimmerActor swimmer, float deltaMs) { + for (int i = 0; i < obstacles.size(); i++) { + obstacles.get(i).resolveCollision(swimmer, deltaMs); + } + } + + public static void loadChunkTemplates(Resources res) { + pathList = new ArrayList<>(); + + Options decodeOptions = new Options(); + decodeOptions.inScaled = false; + + Bitmap b = BitmapFactory.decodeResource(res, R.raw.diamond, decodeOptions); + pathList.add(new GridSolutionPath(b)); + + b = BitmapFactory.decodeResource(res, R.raw.zig, decodeOptions); + pathList.add(new GridSolutionPath(b)); + + b = BitmapFactory.decodeResource(res, R.raw.ziggeroo, decodeOptions); + pathList.add(new GridSolutionPath(b)); + + b = BitmapFactory.decodeResource(res, R.raw.fork_in, decodeOptions); + pathList.add(new GridSolutionPath(b)); + + b = BitmapFactory.decodeResource(res, R.raw.fork_out, decodeOptions); + pathList.add(new GridSolutionPath(b)); + + b = BitmapFactory.decodeResource(res, R.raw.middle_open, decodeOptions); + pathList.add(new GridSolutionPath(b)); + } + + private void generateObstacles(Context context) { + obstacles = new ArrayList<>(); + for (int i = 0; i < solutionPath.getNumRows() * DEFAULT_OBSTACLE_DENSITY; i++) { + float x = RANDOM.nextInt((4 * SwimmingModel.LEVEL_WIDTH) / 5); + float y = startY - (SwimmingModel.LEVEL_WIDTH / 5) + - RANDOM.nextInt((int) solutionPath.getChunkHeight() - (SwimmingModel.LEVEL_WIDTH / 5)); + + int metersY = SwimmingModel.getMetersFromWorldY(y); + int type; + if (metersY < SwimmingModel.SCORE_THRESHOLDS[0]) { + // Only show ice cubes before the bronze threshold. + type = 0; + } else if (metersY < SwimmingModel.SCORE_THRESHOLDS[1]) { + // Show ice cubes and cans before the silver threshold. + type = RANDOM.nextInt(TYPES.size() - 1); + } else { + // After the silver threshold, use all obstacles. + boolean isInMiddleThreeLanes = SwimmingModel.LEVEL_WIDTH / 5 <= x + && x <= 3 * SwimmingModel.LEVEL_WIDTH / 5; + if (isInMiddleThreeLanes) { + // Only place octograbs in the middle three lanes. If we are generating an obstacle in the + // middle 3 lanes, give it a higher chance of being an octograb. + type = Math.min(TYPES.size() - 1, RANDOM.nextInt(TYPES.size() + 1)); + } else { + // If we are outside of the middle 3 lanes, give each other option equal weight. + type = RANDOM.nextInt(TYPES.size() - 1); + } + } + + BoundingBoxSpriteActor obstacle = BoundingBoxSpriteActor.create( + Vector2D.get(x, y), TYPES.get(type), context.getResources()); + Polygon obstacleBody = obstacle.collisionBody; + boolean shouldAdd = true; + for (int j = 0; j < obstacles.size(); j++) { + Polygon otherBody = obstacles.get(j).collisionBody; + if (Util.rectIntersectsRect( + otherBody.min.x, otherBody.min.y, + otherBody.getWidth(), otherBody.getHeight(), + obstacleBody.min.x, obstacleBody.min.y, + obstacleBody.getWidth(), obstacleBody.getHeight())) { + shouldAdd = false; + } + } + if (shouldAdd) { + obstacles.add(obstacle); + } + } + } + + private void removeObstaclesFromSolutionPath(float startY) { + for (int i = obstacles.size() - 1; i >= 0; i--) { + BoundingBoxSpriteActor obstacle = obstacles.get(i); + Vector2D min = obstacle.collisionBody.min; + Vector2D max = obstacle.collisionBody.max; + if (solutionPath.intersects(startY, min.x, min.y, max.x, max.y, mirrored)) { + obstacles.remove(i); + } + } + } + + private interface SolutionPath { + boolean intersects(float startY, float minX, float minY, float maxX, float maxY, + boolean mirrored); + void draw(Canvas canvas, float startY, boolean mirrored); + int getEndCol(boolean mirrored); + float getChunkHeight(); + int getNumRows(); + } + + private static class SolutionPathImpl implements SolutionPath { + private static final int DRIFT_SAME = 0; + private static final int DRIFT_REVERSE = 1; + private final int[] driftDistribution = new int[] { 50, 75, 100 }; + private SolutionPathRow[] rows; + private int endCol; + private int drift; + private Paint paint; + + public SolutionPathImpl(int startCol) { + rows = new SolutionPathRow[NUM_ROWS]; + paint = new Paint(); + paint.setColor(Color.DKGRAY); + + for (int i = 0; i < rows.length; i++) { + + // Decide which way to drift. + int driftToken = RANDOM.nextInt(100); + if (driftToken < driftDistribution[DRIFT_SAME]) { + if (drift == 0) { + // If the path is going straight, switch it to a random direction. + drift = RANDOM.nextBoolean() ? 1 : -1; + } + } else if (driftToken < driftDistribution[DRIFT_REVERSE]) { + drift = 0; + } else { + drift *= -1; + } + if (startCol == 0) { + drift = 1; + } else if (startCol == NUM_COLS - SOLUTION_PATH_NUM_COLS - 1) { + drift = -1; + } + startCol = Util.clamp(startCol + drift, 0, NUM_COLS - SOLUTION_PATH_NUM_COLS - 1); + + rows[i] = new SolutionPathRow(startCol, SOLUTION_PATH_NUM_COLS); + } + this.endCol = startCol; + } + + @Override + public boolean intersects(float startY, float minX, float minY, float maxX, float maxY, + boolean mirrored) { + // Subtract y from startY because the level proceeds in the negative y direction. + int minRowIndex = (int) Math.max(0, (startY - maxY) / ROW_HEIGHT); + int maxRowIndex = (int) Math.max(0, (startY - minY) / ROW_HEIGHT); + for (int i = minRowIndex; i <= maxRowIndex; i++) { + if (rows[i].intersects(Math.min(minX, SwimmingModel.LEVEL_WIDTH), mirrored) + || rows[i].intersects(Math.min(maxX, SwimmingModel.LEVEL_WIDTH), mirrored)) { + return true; + } + } + return false; + } + + @Override + public void draw(Canvas canvas, float startY, boolean mirrored) { + float y = startY; + for (int i = 0; i < rows.length; i++) { + float startX = rows[i].startX; + float endX = rows[i].endX; + if (mirrored) { + startX = SwimmingModel.LEVEL_WIDTH - rows[i].endX; + endX = SwimmingModel.LEVEL_WIDTH - rows[i].startX; + } + canvas.drawRect(startX, y, endX, y + ROW_HEIGHT, paint); + y -= ROW_HEIGHT; + } + } + + @Override + public int getEndCol(boolean mirrored) { + return mirrored ? NUM_COLS - 1 - endCol : endCol; + } + + @Override + public float getChunkHeight() { + return CHUNK_HEIGHT; + } + + @Override + public int getNumRows() { + return rows.length; + } + } + + private static class GridSolutionPath implements SolutionPath { + + public final float chunkHeight; + public final int numRows; + public final float rowHeight; + + private boolean[][] grid; + private Paint paint; + + /** + * Initialize this solution path with a bitmap. The length of the solution path will scale with + * the height of the image, where 1px in the image = 1 grid unit in the chunk. The width of the + * solution path is fixed to NUM_COLS and will just sample the bitmap at NUM_COLS points. Any + * bitmap with a higher horizontal resolution than NUM_COLS will be down-sampled, and any bitmap + * with a lower resolution will have single pixels being sampled more than once horizontally. + * + * In order to maintain visual consistency with the supplied bitmap, it is recommended that + * the input PNGs are 50px wide. + */ + public GridSolutionPath(Bitmap bitmap) { + int bitmapWidth = bitmap.getWidth(); + int bitmapHeight = bitmap.getHeight(); + chunkHeight = bitmapHeight * COL_WIDTH; + numRows = bitmapHeight; + rowHeight = chunkHeight / numRows; + + Log.d(TAG, "bitmapHeight: " + bitmapHeight); + Log.d(TAG, "chunkHeight: " + chunkHeight); + Log.d(TAG, "numRows: " + numRows); + Log.d(TAG, "rowHeight: " + rowHeight); + + paint = new Paint(); + paint.setColor(Color.DKGRAY); + grid = new boolean[numRows][NUM_COLS]; + + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + int bitmapX = (int) ((((float) j) / grid[0].length) * bitmapWidth); + int bitmapY = (int) ((((float) i) / grid.length) * bitmapHeight); + int pixel = bitmap.getPixel(bitmapX, bitmapY); + grid[i][j] = (pixel & 0x00ffffff) != 0; + } + } + } + + @Override + public boolean intersects(float startY, float minX, float minY, float maxX, float maxY, + boolean mirrored) { + if (mirrored) { + float tmpMinX = minX; + minX = SwimmingModel.LEVEL_WIDTH - maxX; + maxX = SwimmingModel.LEVEL_WIDTH - tmpMinX; + } + + // Subtract y from startY because the level proceeds in the negative y direction. + int minRowIndex = (int) Math.max(0, (startY - maxY) / rowHeight); + int maxRowIndex = (int) Math.max(0, (startY - minY) / rowHeight); + int minColIndex = (int) Math.min(NUM_COLS - 1, minX / COL_WIDTH); + int maxColIndex = (int) Math.min(NUM_COLS - 1, maxX / COL_WIDTH); + for (int i = minRowIndex; i <= maxRowIndex; i++) { + for (int j = minColIndex; j <= maxColIndex; j++) { + if (grid[i][j]) { + return true; + } + } + } + return false; + } + + @Override + public void draw(Canvas canvas, float startY, boolean mirrored) { + float y = startY - rowHeight; + for (int i = 0; i < grid.length; i++) { + float x = 0; + for (int j = 0; j < grid[0].length; j++) { + if (!mirrored && grid[i][j]) { + canvas.drawRect(x, y, x + COL_WIDTH, y + rowHeight, paint); + } else if (mirrored && grid[i][grid[0].length - 1 - j]) { + canvas.drawRect(x, y, x + COL_WIDTH, y + rowHeight, paint); + } + x += COL_WIDTH; + } + y -= rowHeight; + } + } + + @Override + public int getEndCol(boolean mirrored) { + return mirrored ? NUM_COLS - 1 : 0; + } + + @Override + public float getChunkHeight() { + return chunkHeight; + } + + @Override + public int getNumRows() { + return numRows; + } + } + + private static class SolutionPathRow { + // The first column which is in the solution path. + public final int startCol; + // The column after the last column in the solution path. + public final int endCol; + public final float startX; + public final float endX; + public SolutionPathRow(int startCol, int numCols) { + this.startCol = startCol; + this.endCol = startCol + numCols; + this.startX = startCol * COL_WIDTH; + this.endX = endCol * COL_WIDTH; + } + + public boolean intersects(float x, boolean mirrored) { + float startX = this.startX; + float endX = this.endX; + if (mirrored) { + startX = SwimmingModel.LEVEL_WIDTH - this.endX; + endX = SwimmingModel.LEVEL_WIDTH - this.startX; + } + return startX <= x && x <= endX; + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingLevelManager.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingLevelManager.java new file mode 100644 index 000000000..b4e07b7b6 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingLevelManager.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.content.Context; +import android.os.Environment; +import android.util.Log; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * A level manager for the Pineapple 2016 swimming game. + */ +public class SwimmingLevelManager extends LevelManager { + + public static File levelsDir = null; + + private static final int DEFAULT_OBSTACLE_Y = -1000; + + public SwimmingLevelManager(Context context) { + super(context); + } + + @Override + public SwimmingModel loadDefaultLevel() { + SwimmingModel model = getEmptyModel(); + + List types = new ArrayList<>(BoundingBoxSpriteActor.TYPE_TO_RESOURCE_MAP.keySet()); + for (int i = 0; i < types.size(); i++) { + int x = i * SwimmingModel.LEVEL_WIDTH / types.size(); + int y = DEFAULT_OBSTACLE_Y; + BoundingBoxSpriteActor obstacle = + BoundingBoxSpriteActor.create(Vector2D.get(x, y), types.get(i), context.getResources()); + model.addActor(obstacle); + } + return model; + } + + @Override + protected File getLevelsDir() { + if (levelsDir == null) { + levelsDir = new File(Environment.getExternalStorageDirectory(), "swimming_levels"); + } + return levelsDir; + } + + @Override + Actor loadActorFromJSON(JSONObject json) throws JSONException { + String type = json.getString(Actor.TYPE_KEY); + Actor actor = null; + if (BoundingBoxSpriteActor.TYPE_TO_RESOURCE_MAP.containsKey(type)) { + actor = BoundingBoxSpriteActor.fromJSON(json, context); + } else { + Log.w(TAG, "Unable to create object of type: " + type); + } + return actor; + } + + @Override + protected SwimmingModel getEmptyModel() { + return new SwimmingModel(); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingModel.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingModel.java new file mode 100644 index 000000000..9197f2059 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingModel.java @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.os.Build; +import android.os.Vibrator; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.widget.TextView; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.CallbackProcess; +import com.google.android.apps.santatracker.doodles.shared.Camera; +import com.google.android.apps.santatracker.doodles.shared.CameraShake; +import com.google.android.apps.santatracker.doodles.shared.EventBus; +import com.google.android.apps.santatracker.doodles.shared.EventBus.EventBusListener; +import com.google.android.apps.santatracker.doodles.shared.Process; +import com.google.android.apps.santatracker.doodles.shared.ProcessChain; +import com.google.android.apps.santatracker.doodles.shared.RectangularInstructionActor; +import com.google.android.apps.santatracker.doodles.shared.UIUtil; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.WaitProcess; +import com.google.android.apps.santatracker.doodles.shared.physics.Util; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +/** + * The model for the swimming game. + */ +public class SwimmingModel implements TiltModel, EventBusListener { + private static final String TAG = SwimmingModel.class.getSimpleName(); + + public static final int LEVEL_WIDTH = 1280; + public static final int[] SCORE_THRESHOLDS = { 30, 50, 100 }; + + private static final float SHAKE_FREQUENCY = 33; + private static final float SHAKE_MAGNITUDE = 40; + private static final float SHAKE_FALLOFF = 0.9f; + private static final long VIBRATION_DURATION_MS = 50; + private static final int WORLD_TO_METER_RATIO = 700; + private static final long WAITING_STATE_DELAY_MS = 1000; + private static final long COUNTDOWN_DELAY_MS = 4000; + private static final float COUNTDOWN_BUMP_SCALE = 1.5f; + + public final List collisionObjectTypes; + + public String levelName; + public boolean collisionMode = true; + + public List actors; + public List uiActors; // Will be drawn above actors. + public Camera camera; + public CameraShake cameraShake; + public SwimmerActor swimmer; + public RectangularInstructionActor instructions; + public TextView countdownView; + public ObstacleManager obstacleManager; + public Vibrator vibrator; + public Locale locale; + public int distanceMeters; + public int currentScoreThreshold = 0; + + public int screenWidth; + public int screenHeight; + public Vector2D tilt; + + // Measures the time elapsed in the current state. This value is reset to 0 upon entering a new + // state. + public long timeElapsed = 0; + private float countdownTimeMs = 3000; + private List processChains = new ArrayList<>(); + public int playCount; + + /** + * States for the swimming game. + */ + public enum SwimmingState { + INTRO, + WAITING, + SWIMMING, + FINISHED, + } + private SwimmingState state; + + public SwimmingModel() { + tilt = Vector2D.get(0, 0); + actors = new ArrayList<>(); + uiActors = new ArrayList<>(); + state = SwimmingState.INTRO; + + collisionObjectTypes = new ArrayList<>(); + collisionObjectTypes.addAll(BoundingBoxSpriteActor.TYPE_TO_RESOURCE_MAP.keySet()); + } + + @Override + public void onEventReceived(int type, Object data) { + switch(type) { + case EventBus.VIBRATE: + if (vibrator != null) { + vibrator.vibrate(VIBRATION_DURATION_MS); + } + break; + + case EventBus.SHAKE_SCREEN: + cameraShake.shake(SHAKE_FREQUENCY, SHAKE_MAGNITUDE, SHAKE_FALLOFF); + break; + + case EventBus.GAME_STATE_CHANGED: + SwimmingState state = (SwimmingState) data; + if (state == SwimmingState.WAITING) { + long countdownDelayMs = WAITING_STATE_DELAY_MS; + if (playCount == 0) { + // Wait for the crossfade to finish then show instructions. + processChains.add(new WaitProcess(WAITING_STATE_DELAY_MS).then(new CallbackProcess() { + @Override + public void updateLogic(float deltaMs) { + if (getState() == SwimmingState.WAITING) { + instructions.show(); + } + } + }).then(new WaitProcess(COUNTDOWN_DELAY_MS).then(new CallbackProcess() { + @Override + public void updateLogic(float deltaMs) { + instructions.hide(); + } + }))); + // If we're showing the instructions, wait until the instructions is hidden before + // starting the countdown. + countdownDelayMs += COUNTDOWN_DELAY_MS + 300; + } + // Start countdown. + processChains.add(new WaitProcess(countdownDelayMs).then(new Process() { + @Override + public void updateLogic(float deltaMs) { + final float oldCountdownTimeMs = countdownTimeMs; + float newCountdownTimeMs = countdownTimeMs - deltaMs; + if ((long) newCountdownTimeMs / 1000 != (long) oldCountdownTimeMs / 1000) { + countdownView.post(new Runnable() { + @Override + public void run() { + countdownView.setVisibility(View.VISIBLE); + // Use the old integer value so that the countdown goes 3, 2, 1 and not 2, 1, 0. + String countdownValue = + NumberFormat.getInstance(locale).format((long) oldCountdownTimeMs / 1000); + setTextAndBump(countdownView, countdownValue); + } + }); + } + countdownTimeMs = newCountdownTimeMs; + } + + @Override + public boolean isFinished() { + return countdownTimeMs <= 0; + } + }).then(new CallbackProcess() { + @Override + public void updateLogic(float deltaMs) { + countdownView.post(new Runnable() { + @Override + public void run() { + countdownView.setVisibility(View.INVISIBLE); + } + }); + setState(SwimmingState.SWIMMING); + } + })); + } else if (state == SwimmingState.SWIMMING) { + swimmer.startSwimming(); + } + } + } + + public void setState(SwimmingState state) { + if (this.state != state) { + this.state = state; + timeElapsed = 0; + EventBus.getInstance().sendEvent(EventBus.GAME_STATE_CHANGED, state); + } + } + + public SwimmingState getState() { + return state; + } + + public void update(float deltaMs) { + synchronized (this) { + timeElapsed += deltaMs; + + ProcessChain.updateChains(processChains, deltaMs); + + for (int i = 0; i < actors.size(); i++) { + actors.get(i).update(deltaMs); + } + + for (int i = 0; i < uiActors.size(); i++) { + uiActors.get(i).update(deltaMs); + } + + if (state == SwimmingState.SWIMMING || state == SwimmingState.WAITING) { + swimmer.updateTargetPositionFromTilt(tilt, LEVEL_WIDTH); + + int newDistance = getMetersFromWorldY(swimmer.position.y); + if (newDistance != distanceMeters) { + if (newDistance >= SwimmingLevelChunk.LEVEL_LENGTH_IN_METERS) { + swimmer.endGameWithoutCollision(); + } + distanceMeters = Math.min(SwimmingLevelChunk.LEVEL_LENGTH_IN_METERS, newDistance); + EventBus.getInstance().sendEvent(EventBus.SCORE_CHANGED, distanceMeters); + } + if (swimmer.isDead) { + setState(SwimmingState.FINISHED); + } + + resolveCollisions(deltaMs); + + clampCameraPosition(); + } + } + } + + public void clampCameraPosition() { + if (!SwimmingFragment.editorMode) { + float swimmerHeight = swimmer.collisionBody.getHeight(); + float minCameraOffset = camera.toWorldScale(screenHeight) - 3.5f * swimmerHeight; + float maxCameraOffset = camera.toWorldScale(screenHeight) - 4.0f * swimmerHeight; + camera.position.set(camera.position.x, Util.clamp(camera.position.y, + swimmer.position.y - minCameraOffset, swimmer.position.y - maxCameraOffset)); + } + } + + public void resolveCollisions(float deltaMs) { + obstacleManager.resolveCollisions(swimmer, deltaMs); + } + + public void drawActors(Canvas canvas) { + List actorsToDraw = new ArrayList<>(actors); + actorsToDraw.addAll(obstacleManager.getActors()); + Collections.sort(actorsToDraw); + for (int i = 0; i < actorsToDraw.size(); i++) { + actorsToDraw.get(i).draw(canvas); + } + } + + public void drawUiActors(Canvas canvas) { + for (int i = 0; i < uiActors.size(); i++) { + uiActors.get(i).draw(canvas); + } + } + + public int getStarCount() { + return currentScoreThreshold; + } + + public void onTouchDown() { + if (getState() == SwimmingState.SWIMMING) { + swimmer.diveDown(); + } + } + + public void createActor(Vector2D position, String objectType, Resources resources) { + if (BoundingBoxSpriteActor.TYPE_TO_RESOURCE_MAP.containsKey(objectType)) { + actors.add(BoundingBoxSpriteActor.create(position, objectType, resources)); + } + } + + public void sortActors() { + Collections.sort(actors); + } + + @Override + public List getActors() { + return actors; + } + + @Override + public void addActor(Actor actor) { + if (actor instanceof SwimmerActor) { + this.swimmer = (SwimmerActor) actor; + } else if (actor instanceof Camera) { + this.camera = (Camera) actor; + } else if (actor instanceof CameraShake) { + this.cameraShake = (CameraShake) actor; + } else if (actor instanceof ObstacleManager) { + this.obstacleManager = (ObstacleManager) actor; + } + actors.add(actor); + sortActors(); + } + + public void addUiActor(Actor actor) { + if (actor instanceof RectangularInstructionActor) { + this.instructions = (RectangularInstructionActor) actor; + } + uiActors.add(actor); + } + + public void setCountdownView(TextView countdownView) { + this.countdownView = countdownView; + } + + @Override + public void setLevelName(String levelName) { + this.levelName = levelName; + } + + public static int getMetersFromWorldY(float distance) { + return Math.max(0, (int) (-distance / WORLD_TO_METER_RATIO)); + } + + public static int getWorldYFromMeters(int meters) { + return -meters * WORLD_TO_METER_RATIO; + } + + private void setTextAndBump(final TextView textView, String text) { + float endScale = textView.getScaleX(); + float startScale = COUNTDOWN_BUMP_SCALE * textView.getScaleX(); + textView.setText(text); + if (!"Nexus 9".equals(Build.MODEL)) { + ValueAnimator scaleAnimation = UIUtil.animator(200, + new AccelerateDecelerateInterpolator(), + new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + float scaleValue = (float) valueAnimator.getAnimatedValue("scale"); + textView.setScaleX(scaleValue); + textView.setScaleY(scaleValue); + } + }, + UIUtil.floatValue("scale", startScale, endScale) + ); + scaleAnimation.start(); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingView.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingView.java new file mode 100644 index 000000000..d3a5237ed --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/SwimmingView.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.View; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; + +/** + * The game view for the swimming game. + */ +public class SwimmingView extends View { + private static final String TAG = SwimmingView.class.getSimpleName(); + public static final int WATER_BLUE = 0xffa6ffff; + public static final int LINES_BLUE = 0xff00d4d4; + + private static final int LANE_LINE_WIDTH = 10; + public static final int NUM_LANES = 5; + + private Paint swimmingLinesPaint; + + private SwimmingModel model; + private GestureDetector editorGestureDetector; + private ScaleGestureDetector scaleDetector; + private GestureListener gestureListener; + + public SwimmingView(Context context) { + this(context, null); + } + + public SwimmingView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SwimmingView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + swimmingLinesPaint = new Paint(); + swimmingLinesPaint.setColor(LINES_BLUE); + swimmingLinesPaint.setStyle(Style.FILL); + + gestureListener = new GestureListener(); + editorGestureDetector = new GestureDetector(context, gestureListener); + scaleDetector = new ScaleGestureDetector(context, new ScaleListener()); + } + + @Override + public void onDraw(Canvas canvas) { + if (model == null) { + return; + } + synchronized (model) { + // Draw background + canvas.drawColor(WATER_BLUE); + + canvas.save(); + + canvas.scale(model.camera.scale, model.camera.scale); + canvas.translate( + -model.camera.position.x + model.cameraShake.position.x, + -model.camera.position.y + model.cameraShake.position.y); + + drawSwimmingLines(canvas); + + model.drawActors(canvas); + + canvas.restore(); + + model.drawUiActors(canvas); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean handledTouch = false; + if (SwimmingFragment.editorMode) { + // Handle touch events in the editor. + + // Let the ScaleGestureDetector inspect all events. + handledTouch = scaleDetector.onTouchEvent(event); + + final int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_DOWN: + int index = event.getActionIndex(); + // If the user touches the screen, check to see if they have selected a polygon vertex, + // which they can then drag around the screen. + Vector2D worldCoords = model.camera.getWorldCoords(event.getX(index), event.getY(index)); + // Reset selection. + gestureListener.selectedActor = null; + + // model.actors will be sorted by z-index. Iterate over it backwards so that touches on + // elements are handled in reverse z-index order (i.e., actors in front will be selected + // before actors in back). + for (int i = model.actors.size() - 1; i >= 0; i--) { + Actor actor = model.actors.get(i); + if (actor instanceof Touchable + && ((Touchable) actor).canHandleTouchAt(worldCoords, model.camera.scale)) { + if (model.collisionMode == (actor instanceof CollisionActor)) { + // Only allow interactions with objects within the current selection mode (i.e., + // only collision objects in collision mode, only scenery objects in non-collision + // mode. + gestureListener.selectedActor = actor; + ((Touchable) actor).startTouchAt(worldCoords, model.camera.scale); + break; + } + } + } + break; + } + handledTouch = editorGestureDetector.onTouchEvent(event) || handledTouch; + } else { + // Handle in-game touch events. + if (model != null) { + final int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_DOWN: + model.onTouchDown(); + handledTouch = true; + break; + } + } + } + return handledTouch || super.onTouchEvent(event); + } + + public void setModel(SwimmingModel model) { + this.model = model; + } + + private void drawSwimmingLines(Canvas canvas) { + int laneWidth = SwimmingModel.LEVEL_WIDTH / NUM_LANES; + for (int i = 1; i < NUM_LANES; i++) { + canvas.drawRect(laneWidth * i - LANE_LINE_WIDTH / 2.0f, model.camera.yToWorld(0), + laneWidth * i + LANE_LINE_WIDTH / 2.0f, model.camera.yToWorld(canvas.getHeight()), + swimmingLinesPaint); + } + } + + private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + + @Override + public boolean onScale(ScaleGestureDetector detector) { + model.camera.scale *= detector.getScaleFactor(); + model.camera.scale = Math.max(0.1f, Math.min(model.camera.scale, 5.0f)); + return true; + } + } + + private class GestureListener extends SimpleOnGestureListener { + public Actor selectedActor; + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + Vector2D delta = Vector2D.get(distanceX / model.camera.scale, distanceY / model.camera.scale); + if (selectedActor != null) { + ((Touchable) selectedActor).handleMoveEvent(delta); + } else { + model.camera.position.add(delta); + } + delta.release(); + return true; + } + + @Override + public void onLongPress(MotionEvent event) { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + if (selectedActor != null) { + boolean handled = ((Touchable) selectedActor).handleLongPress(); + if (!handled) { + // If the selected actor doesn't handle the long press, the default behavior is to remove + // it. + model.actors.remove(selectedActor); + } + } else { + // Long press is not on a touchable actor. Create a new object and place it + // where the long press occurred. + DialogFragment dialogFragment = new CreateObjectDialogFragment( + model.camera.getWorldCoords(event.getX(), event.getY())); + dialogFragment.show(((Activity) getContext()).getFragmentManager(), "create_object"); + } + } + } + + private class CreateObjectDialogFragment extends DialogFragment { + private Vector2D center; + + public CreateObjectDialogFragment(Vector2D center) { + this.center = center; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final String[] items; + items = new String[model.collisionObjectTypes.size()]; + model.collisionObjectTypes.toArray(items); + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(com.google.android.apps.santatracker.doodles.R.string.create_object) + .setItems(items, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + model.createActor(center, items[which], getResources()); + } + }); + return builder.create(); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/TestTiltModel.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/TestTiltModel.java new file mode 100644 index 000000000..86b008b58 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/TestTiltModel.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import com.google.android.apps.santatracker.doodles.shared.Actor; + +import java.util.ArrayList; +import java.util.List; + +/** + * A basic tilt model to be used for testing. + */ +public class TestTiltModel implements TiltModel { + + private List actors; + + public TestTiltModel() { + actors = new ArrayList<>(); + } + + @Override + public List getActors() { + return actors; + } + + @Override + public void addActor(Actor actor) { + actors.add(actor); + } + + @Override + public void setLevelName(String levelName) { + // Do nothing. + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/TiltModel.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/TiltModel.java new file mode 100644 index 000000000..c6db5374b --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/TiltModel.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import com.google.android.apps.santatracker.doodles.shared.Actor; + +import java.util.List; + +/** + * A model in one of the tilt games, used to unify the loading of levels in the swimming and golf + * games. + */ +public interface TiltModel { + List getActors(); + + void addActor(Actor actor); + + void setLevelName(String levelName); +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ToggleableBounceActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ToggleableBounceActor.java new file mode 100644 index 000000000..5ec2ea2ff --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/ToggleableBounceActor.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.graphics.Canvas; +import android.graphics.Color; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * A BounceActor which can be toggled on an off with trigger polygons. + */ +public class ToggleableBounceActor extends BounceActor { + public static final String TYPE = "Toggleable Bouncy"; + protected static final String ON_TRIGGER_KEY = "on trigger"; + protected static final String OFF_TRIGGER_KEY = "off trigger"; + + private CollisionActor onTrigger; + private CollisionActor offTrigger; + public boolean enabled; + + public ToggleableBounceActor(Polygon collisionBody, + CollisionActor onTrigger, CollisionActor offTrigger) { + super(collisionBody); + this.onTrigger = onTrigger; + this.offTrigger = offTrigger; + + collisionBody.setPaintColors(Color.RED, Color.LTGRAY, 0x6400ff00); + onTrigger.collisionBody.setPaintColors(Color.GREEN, Color.RED, 0x6400ff00); + offTrigger.collisionBody.setPaintColors(Color.BLACK, Color.RED, 0x6400ff00); + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + onTrigger.update(deltaMs); + offTrigger.update(deltaMs); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + onTrigger.draw(canvas); + offTrigger.draw(canvas); + } + + @Override + public String getType() { + return ToggleableBounceActor.TYPE; + } + + @Override + public boolean canHandleTouchAt(Vector2D worldCoords, float cameraScale) { + return super.canHandleTouchAt(worldCoords, cameraScale) + || onTrigger.canHandleTouchAt(worldCoords, cameraScale) + || offTrigger.canHandleTouchAt(worldCoords, cameraScale); + } + + @Override + public void startTouchAt(Vector2D worldCoords, float cameraScale) { + super.startTouchAt(worldCoords, cameraScale); + onTrigger.startTouchAt(worldCoords, cameraScale); + offTrigger.startTouchAt(worldCoords, cameraScale); + } + + @Override + public boolean handleMoveEvent(Vector2D delta) { + return super.handleMoveEvent(delta) + || onTrigger.handleMoveEvent(delta) || offTrigger.handleMoveEvent(delta); + } + + @Override + public boolean handleLongPress() { + return super.handleLongPress() || onTrigger.handleLongPress() || offTrigger.handleLongPress(); + } + + @Override + public boolean resolveCollision(Actor other, float deltaMs) { + // Resolve trigger collisions. + if (onTrigger.collisionBody.contains(other.position)) { + enabled = true; + collisionBody.setPaintColors(Color.RED, Color.WHITE, 0x6400ff00); + } else if (offTrigger.collisionBody.contains(other.position)) { + enabled = false; + collisionBody.setPaintColors(Color.RED, Color.LTGRAY, 0x6400ff00); + } + + // Handle the actual collision. + if (enabled) { + return super.resolveCollision(other, deltaMs); + } + return false; + } + + @Override + public JSONObject toJSON() throws JSONException { + JSONObject json = super.toJSON(); + json.put(ON_TRIGGER_KEY, onTrigger.toJSON()); + json.put(OFF_TRIGGER_KEY, offTrigger.toJSON()); + return json; + } + + public static ToggleableBounceActor fromJSON(JSONObject json) throws JSONException { + return new ToggleableBounceActor(Polygon.fromJSON(json.getJSONArray(POLYGON_KEY)), + CollisionActor.fromJSON(json.getJSONObject(ON_TRIGGER_KEY)), + CollisionActor.fromJSON(json.getJSONObject(OFF_TRIGGER_KEY))); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/Touchable.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/Touchable.java new file mode 100644 index 000000000..ae23312ce --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/Touchable.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import com.google.android.apps.santatracker.doodles.shared.Vector2D; + +/** + * An actor which can be touched in the level editor. + */ +public interface Touchable { + boolean canHandleTouchAt(Vector2D worldCoords, float cameraScale); + void startTouchAt(Vector2D worldCoords, float cameraScale); + + /** + * Handle a move event internally. + * @param delta the movement vector + * @return true if the move event has been handled, false otherwise. + */ + boolean handleMoveEvent(Vector2D delta); + + /** + * Handle a long press internally. + * @return true if the long press has been handled, false otherwise. + */ + boolean handleLongPress(); +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/WatermelonActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/WatermelonActor.java new file mode 100644 index 000000000..70de7b965 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/WatermelonActor.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.content.res.Resources; +import android.graphics.Canvas; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.WatermelonBaseActor; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; +import com.google.android.apps.santatracker.doodles.shared.physics.Util; +import java.util.ArrayList; +import java.util.List; + +/** + * An actor for a watermelon which rolls down the screen. + */ +public class WatermelonActor extends BounceActor { + private static final float SCALE = 2.0f; + private static final float LEG_WIDTH = 50; + + public long ageMs; + public long delayMs; + private WatermelonBaseActor melonActor; + + private Vector2D spriteOffset = Vector2D.get(-LEG_WIDTH, 0); + + public WatermelonActor(WatermelonBaseActor actor, Polygon collisionBody) { + super(collisionBody); + this.melonActor = actor; + } + + public void setVelocity(Vector2D velocity) { + this.velocity.set(velocity); + melonActor.velocity.set(velocity); + } + + public void setPosition(Vector2D position) { + float collisionBodyOffsetX = position.x - this.position.x; + float collisionBodyOffsetY = position.y - this.position.y; + collisionBody.move(collisionBodyOffsetX, collisionBodyOffsetY); + + this.position.set(position).add(spriteOffset); + melonActor.position.set(position) + .add(spriteOffset.scale(0.5f)) + .add(melonActor.bodySprite.frameWidth, melonActor.bodySprite.frameHeight); + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + melonActor.update(deltaMs); + ageMs += deltaMs; + } + + @Override + public void draw(Canvas canvas) { + melonActor.draw(canvas); + super.draw(canvas); + } + + @Override + public boolean resolveCollision(Actor other, float deltaMs) { + // Just do bounding box checking since the watermelon's hitbox is a rectangle. + if (Util.pointIsWithinBounds(collisionBody.min, collisionBody.max, other.position)) { + return false; + } + return false; + } + + public static WatermelonActor create(Vector2D position, Resources resources) { + WatermelonBaseActor actor = new WatermelonBaseActor(resources); + Polygon collisionBody = getCollisionPolygon(position, + actor.bodySprite.frameWidth * SCALE, 3 * actor.bodySprite.frameHeight / 4 * SCALE); + actor.scale = SCALE; + + WatermelonActor watermelon = new WatermelonActor(actor, collisionBody); + watermelon.setPosition(position); + return watermelon; + } + + private static Polygon getCollisionPolygon(Vector2D spritePosition, float width, float height) { + List vertices = new ArrayList<>(); + // top left + vertices.add(Vector2D.get(spritePosition.x + LEG_WIDTH, spritePosition.y)); + // top right + vertices.add(Vector2D.get(spritePosition.x + width, spritePosition.y)); + // bottom right + vertices.add( + Vector2D.get(spritePosition.x + width, spritePosition.y + height)); + // bottom left + vertices.add( + Vector2D.get(spritePosition.x + LEG_WIDTH, spritePosition.y + height)); + return new Polygon(vertices); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/WatermelonEmitter.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/WatermelonEmitter.java new file mode 100644 index 000000000..d766ad258 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/tilt/WatermelonEmitter.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.tilt; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.physics.Polygon; +import java.util.ArrayList; +import java.util.List; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * An emitter of watermelons which can run over the golf ball. + */ +public class WatermelonEmitter extends CollisionActor { + public static final String TYPE = "Watermelon emitter"; + + public static final int NUM_WATERMELONS = 3; + public static final float WATERMELON_VELOCITY = 750.0f; + public static final long LIFETIME_MS = 7500; + + private List watermelons = new ArrayList<>(); + private long elapsedMs; + + public WatermelonEmitter(Polygon collisionBody, Resources resources) { + super(collisionBody); + this.zIndex = 1; + collisionBody.setPaintColors(0xffff6385, 0xff6cfc9b, 0x6400ff00); + + for (int i = 0; i < NUM_WATERMELONS; i++) { + WatermelonActor watermelon = WatermelonActor.create(collisionBody.min, resources); + watermelon.setVelocity(Vector2D.get(0, WATERMELON_VELOCITY)); + watermelon.delayMs = (i + 1) * LIFETIME_MS / NUM_WATERMELONS; + watermelons.add(watermelon); + } + } + + @Override + public void update(float deltaMs) { + elapsedMs += deltaMs; + for (int i = 0; i < watermelons.size(); i++) { + WatermelonActor watermelon = watermelons.get(i); + if (elapsedMs > watermelon.delayMs) { + watermelon.update(deltaMs); + if (watermelon.ageMs > LIFETIME_MS) { + reset(watermelon); + } + } + } + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + for (int i = 0; i < watermelons.size(); i++) { + WatermelonActor watermelon = watermelons.get(i); + watermelon.draw(canvas); + } + } + + @Override + public boolean resolveCollision(Actor other, float deltaMs) { + for (int i = 0; i < watermelons.size(); i++) { + WatermelonActor watermelon = watermelons.get(i); + if (watermelon.resolveCollision(other, deltaMs)) { + return true; + } + } + return false; + } + + @Override + public String getType() { + return WatermelonEmitter.TYPE; + } + + private void reset(WatermelonActor actor) { + actor.setPosition(collisionBody.min); + actor.ageMs = 0; + } + + public static WatermelonEmitter fromJSON(JSONObject json, Context context) throws JSONException { + return new WatermelonEmitter( + Polygon.fromJSON(json.getJSONArray(POLYGON_KEY)), context.getResources()); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloActor.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloActor.java new file mode 100644 index 000000000..35530ef60 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloActor.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.waterpolo; + + +import android.graphics.Canvas; +import android.util.Log; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.ActorTween.Callback; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite.AnimatedSpriteListener; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.shared.physics.Util; +import com.google.android.apps.santatracker.doodles.tilt.ColoredRectangleActor; +import java.util.HashMap; + +/** + * Actor for both the player and the opponent in the water polo game. + * The debug position marker is omitted. + */ +public class WaterPoloActor extends Actor { + private static final String TAG = WaterPoloActor.class.getSimpleName(); + + /** + * Labels for all the different sprites which make up the actor. + */ + public enum WaterPoloActorPart { + BodyIdle, + BodyIdleNoBall, // Used at end of game. + BodyEntrance, // Used when character enters the game. + BodyLeft, + BodyRight, + BodyBlock, + BodyThrow, + BodyPickUpBall, // Catch a new ball from the slide. + } + + private static final int RELEASE_THROW_FRAME = 2; + + HashMap sprites; + WaterPoloActorPart body; + AnimatedSprite currentSprite; + + float collisionWidthUnscaled; + float collisionHeightUnscaled; + ColoredRectangleActor collisionBox; + Callback shotBlockCallback; + + public WaterPoloActor() { + sprites = new HashMap<>(); + body = WaterPoloActorPart.BodyIdle; + } + + @Override + public void update(float deltaMs) { + super.update(deltaMs); + if (currentSprite == null) { + return; + } + currentSprite.update(deltaMs); + if (collisionBox != null) { + collisionBox.dimens = + Vector2D.get(collisionWidthUnscaled * scale, collisionHeightUnscaled * scale); + + // The collision box should be centered on the sprite. + float centerX = position.x - (currentSprite.anchor.x) + (currentSprite.frameWidth * 0.5f); + float centerY = position.y - (currentSprite.anchor.y) + (currentSprite.frameHeight * 0.5f); + collisionBox.position.set(centerX - collisionBox.dimens.x * 0.5f, + centerY - collisionBox.dimens.y * 0.5f); + } + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + if (currentSprite == null) { + Log.e(TAG, "Body part null: " + body); + return; + } + currentSprite.setPosition(position.x, position.y); + currentSprite.setScale(scale, scale); + currentSprite.setHidden(hidden); + currentSprite.draw(canvas); + } + + // Add a sprite to the actor for the given part. You need to call this for a part before + // trying to use that part. Offsets are measured from the actor's position + public void addSprite(WaterPoloActorPart part, int xOffset, int yOffset, AnimatedSprite sprite) { + // After picking up the ball, go straight to idle. + if (part == WaterPoloActorPart.BodyPickUpBall) { + sprite.addListener(new AnimatedSpriteListener() { + @Override + public void onLoop() { + idle(); + } + }); + } + + // This makes sure the sprite scales from self.position + sprite.setAnchor(-xOffset, yOffset); + + if (part != body) { + sprite.setHidden(true); + } + sprites.put(part, sprite); + } + + // The collision box position, relative to self.position, is hardcoded in update, because the + // opponents all have the same position. + public void setCollisionBox(float width, float height) { + collisionWidthUnscaled = width; + collisionHeightUnscaled = height; + collisionBox = new ColoredRectangleActor( + Vector2D.get(0, 0), + Vector2D.get(0, 0), + ColoredRectangleActor.UNSPECIFIED); + } + + // Returns YES iff (x, y) lies within the actor's collision box. + public boolean canBlock(float x, float y) { + if (hidden || body == WaterPoloActorPart.BodyEntrance || collisionBox == null) { + return false; + } + Vector2D worldCoords = Vector2D.get(x, y); + Vector2D lowerRight = Vector2D.get(collisionBox.position).add(collisionBox.dimens); + return Util.pointIsWithinBounds(collisionBox.position, lowerRight, worldCoords); + } + + public void idle() { + setBodyUnchecked(WaterPoloActorPart.BodyIdle); + } + + public void idleNoBall() { + setBodyUnchecked(WaterPoloActorPart.BodyIdleNoBall); + } + + public void pickUpBall() { + setBodyUnchecked(WaterPoloActorPart.BodyPickUpBall); + } + + public void swimLeft() { + if (body == WaterPoloActorPart.BodyBlock) { + AnimatedSprite sprite = sprites.get(WaterPoloActorPart.BodyBlock); + sprite.clearListeners(); + sprite.addListener(new AnimatedSpriteListener() { + @Override + public void onLoop() { + setBodyUnchecked(WaterPoloActorPart.BodyLeft); + } + + @Override + public void onFrame(int index) { + if (index == 3) { + if (shotBlockCallback != null) { + shotBlockCallback.call(); + shotBlockCallback = null; + } + } + } + }); + } else { + setBodyUnchecked(WaterPoloActorPart.BodyLeft); + } + } + + public void swimRight() { + if (body == WaterPoloActorPart.BodyBlock) { + AnimatedSprite sprite = sprites.get(WaterPoloActorPart.BodyBlock); + sprite.clearListeners(); + sprite.addListener(new AnimatedSpriteListener() { + @Override + public void onLoop() { + setBodyUnchecked(WaterPoloActorPart.BodyRight); + } + + @Override + public void onFrame(int index) { + if (index == 3) { + if (shotBlockCallback != null) { + shotBlockCallback.call(); + shotBlockCallback = null; + } + } + } + }); + } else { + setBodyUnchecked(WaterPoloActorPart.BodyRight); + } + } + + // The callback gets called when the actor is at the top of the blocking jump (so the game + // can deflect the ball at that instant). + public void blockShot(final Callback callback) { + AnimatedSprite sprite = sprites.get(WaterPoloActorPart.BodyBlock); + sprite.clearListeners(); + final WaterPoloActorPart previousBody = body; + shotBlockCallback = callback; + sprite.addListener(new AnimatedSpriteListener() { + @Override + public void onLoop() { + setBodyUnchecked(previousBody); + } + + @Override + public void onFrame(int index) { + if (index == 3) { + if (shotBlockCallback != null) { + shotBlockCallback.call(); + shotBlockCallback = null; + } + } + } + }); + setBodyUnchecked(WaterPoloActorPart.BodyBlock); + } + + // releaseCallback gets called when the actor releases the ball (so the game can swap in the real + // ball). endCallback will be called when the actor is done throwing and starts picking up another + // ball (so the game can start the grapeOnSlide animation at the correct time). + public void throwBall(final Callback releaseCallback, final Callback endCallback) { + AnimatedSprite sprite = sprites.get(WaterPoloActorPart.BodyThrow); + sprite.clearListeners(); + sprite.addListener(new AnimatedSpriteListener() { + @Override + public void onLoop() { + pickUpBall(); + endCallback.call(); + } + + @Override + public void onFrame(int index) { + if (index == RELEASE_THROW_FRAME) { + releaseCallback.call(); + } + } + }); + setBodyUnchecked(WaterPoloActorPart.BodyThrow); + } + + // Callback is called at the end of the animation, when actor is ready to play. + public void enter(final Callback callback) { + AnimatedSprite sprite = sprites.get(WaterPoloActorPart.BodyEntrance); + sprite.clearListeners(); + sprite.addListener(new AnimatedSpriteListener() { + @Override + public void onLoop() { + callback.call(); + } + }); + setBodyUnchecked(WaterPoloActorPart.BodyEntrance); + } + + private void setBodyUnchecked(WaterPoloActorPart part) { + AnimatedSprite newSprite = sprites.get(part); + if (newSprite == null) { + Log.e(TAG, "Error: sprite " + part + " not loaded."); + assert(false); + } + newSprite.setFrameIndex(0); + body = part; + update(0); + + currentSprite = newSprite; + } + +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloFragment.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloFragment.java new file mode 100644 index 000000000..e40d7a492 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloFragment.java @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.waterpolo; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.v4.content.ContextCompat; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.AndroidUtils; +import com.google.android.apps.santatracker.doodles.shared.DoodleConfig; +import com.google.android.apps.santatracker.doodles.shared.EventBus; +import com.google.android.apps.santatracker.doodles.shared.EventBus.EventBusListener; +import com.google.android.apps.santatracker.doodles.shared.GameFragment; +import com.google.android.apps.santatracker.doodles.shared.GameType; +import com.google.android.apps.santatracker.doodles.shared.HistoryManager; +import com.google.android.apps.santatracker.doodles.shared.PauseView; +import com.google.android.apps.santatracker.doodles.shared.PineappleLogger; +import com.google.android.apps.santatracker.doodles.shared.ScoreView; +import com.google.android.apps.santatracker.doodles.shared.sound.SoundManager; +import com.google.android.apps.santatracker.doodles.waterpolo.WaterPoloModel.State; + +import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.WATERPOLO_GAME_TYPE; + +/** + * Activity for the ported water polo game. + * Manages input & threads, delegates to WaterPoloModel & WaterPoloView for the rest. + */ +public class WaterPoloFragment extends GameFragment implements EventBusListener { + private static final String TAG = WaterPoloFragment.class.getSimpleName(); + + private WaterPoloView gameView; + private WaterPoloModel model; + private WaterPoloGestureDetector gestureDetector; + private EventBus eventBus; + private boolean mIsGameOver = false; + + public WaterPoloFragment() { + super(); + } + + public WaterPoloFragment(Context context, DoodleConfig doodleConfig, + PineappleLogger logger) { + super(context, doodleConfig, logger); + } + + @Override + protected ScoreView getScoreView() { + WaterPoloScoreView scoreView = new WaterPoloScoreView(context, this); + scoreView.setDoodleConfig(doodleConfig); + scoreView.setLogger(logger); + scoreView.setListener(levelFinishedListener); + scoreView.setModel(model); + return scoreView; + } + + @Override + protected PauseView getPauseView() { + WaterPoloPauseView pauseView = new WaterPoloPauseView(context); + pauseView.setDoodleConfig(doodleConfig); + pauseView.setLogger(logger); + pauseView.setListener(gamePausedListener); + + return pauseView; + } + + @Override + public void update(float deltaMs) { + if (!isPaused) { + model.update((long) deltaMs); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + if (context == null) { + return null; + } + eventBus = EventBus.getInstance(); + historyManager = new HistoryManager(context, new HistoryManager.HistoryListener() { + @Override + public void onFinishedLoading() { + } + + @Override + public void onFinishedSaving() { + } + }); + + wrapper = new FrameLayout(context); + + titleView = getTitleView(R.drawable.present_throw_loadingscreen, R.string.presentthrow); + wrapper.addView(titleView); + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + loadGame(); + } + }); + return wrapper; + } + + @Override + protected void firstPassLoadOnUiThread() { + wrapper.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return onTouchEvent(event); + } + }); + final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); + // Add game view & finish view. + gameView = new WaterPoloView(context); + wrapper.addView(gameView, 0, lp); + + pauseView = getPauseView(); + wrapper.addView(pauseView, 1); + scoreView = getScoreView(); + wrapper.addView(scoreView, 1); + } + + @Override + protected void secondPassLoadOnBackgroundThread() { + super.secondPassLoadOnBackgroundThread(); + eventBus.register(this); + model = new WaterPoloModel(context.getResources(), + getActivity().getApplicationContext()); + gameView.setModel(model); + if(scoreView instanceof WaterPoloScoreView) { + ((WaterPoloScoreView)scoreView).setModel(model); + } + } + + @Override + protected void finalPassLoadOnUiThread() { + gestureDetector = new WaterPoloGestureDetector() { + @Override + public void onPan(float radians) { + model.onFling(radians); + } + }; + + soundManager = SoundManager.getInstance(); + loadSounds(); + + onFinishedLoading(); + startHandlers(); + } + + @Override + protected void replay() { + super.replay(); + model.reset(false); + } + + @Override + protected void onDestroyHelper() { + if (gameView != null) { + gameView.setModel(null); + } + model = null; + } + + @Override + public void onEventReceived(int type, Object data) { + if (isDestroyed) { + return; + } + if (type == EventBus.SCORE_CHANGED) { + final Integer score = (Integer) data; + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + scoreView.updateCurrentScore( + AndroidUtils.getText(context.getResources(), R.string.waterpolo_score, score), + true); + } + }); + } else if (type == EventBus.PLAY_SOUND && soundManager != null) { + int resId = (int) data; + soundManager.play(resId); + } else if (type == EventBus.PAUSE_SOUND && soundManager != null) { + int resId = (int) data; + soundManager.pause(resId); + } else if (type == EventBus.MUTE_SOUNDS && soundManager != null) { + boolean shouldMute = (boolean) data; + if (shouldMute) { + soundManager.mute(); + } else { + soundManager.unmute(); + } + } else if (type == EventBus.GAME_STATE_CHANGED) { + mIsGameOver = false; + WaterPoloModel.State state = (WaterPoloModel.State) data; + if (state == State.WAITING) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + hideTitle(); + pauseView.showPauseButton(); + } + }); + } else if (state == State.GAME_OVER) { + mIsGameOver = true; + wrapper.postDelayed(new Runnable() { + @Override + public void run() { + if (model == null) { + return; + } + final int currentScore = model.score; + boolean shouldSave = false; + Integer bestStarCount = historyManager.getBestStarCount(GameType.WATER_POLO); + int starCount = getStarCount(); + if (bestStarCount == null || bestStarCount < starCount) { + historyManager.setBestStarCount(GameType.WATER_POLO, starCount); + shouldSave = true; + } + Double temp = historyManager.getBestScore(GameType.WATER_POLO); + int bestScore = temp == null ? -1 : (int) Math.round(temp); + if (currentScore > bestScore) { + bestScore = currentScore; + historyManager.setBestScore(GameType.WATER_POLO, currentScore); + shouldSave = true; + } + if (shouldSave) { + historyManager.save(); + } + + final int finalStarCount = starCount; + final int finalBestScore = bestScore; + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + for (int i = 0; i < finalStarCount; i++) { + scoreView.addStar(); + } + pauseView.hidePauseButton(); + scoreView.updateBestScore( + AndroidUtils.getText( + context.getResources(), R.string.waterpolo_score, finalBestScore)); + scoreView.setShareDrawable(getShareImageDrawable(finalStarCount)); + + scoreView.animateToEndState(); + } + }); + } + }, 2000); + } + } else if (type == EventBus.GAME_LOADED) { + long loadTimeMs = (long) data; + model.titleDurationMs = Math.max(0, model.titleDurationMs - loadTimeMs); + Log.d(TAG, "Waiting " + model.titleDurationMs + "ms and then hiding title."); + } + } + + private Drawable getShareImageDrawable(int starCount) { + return ContextCompat.getDrawable(getActivity(), R.drawable.winner); + } + + @Override + protected void loadSounds() { + super.loadSounds(); + soundManager.loadShortSound(context, R.raw.swimming_ice_splash_a); + soundManager.loadShortSound(context, R.raw.present_throw_character_appear); + soundManager.loadShortSound(context, R.raw.tennis_eliminate); + soundManager.loadShortSound(context, R.raw.present_throw_block); + soundManager.loadShortSound(context, R.raw.present_throw_goal); + soundManager.loadShortSound(context, R.raw.present_throw_throw); + } + + public boolean onTouchEvent(MotionEvent event) { + if (gestureDetector != null) { + gestureDetector.onTouchEvent(event); + return true; + } + return false; + } + + @Override + protected void resume() { + super.resume(); + if (uiRefreshHandler != null) { + uiRefreshHandler.start(gameView); + } + } + + @Override + protected String getGameType() { + return WATERPOLO_GAME_TYPE; + } + + @Override + protected float getScore() { + return model.score; + } + + @Override + protected int getShareImageId() { + return getStarCount(); + } + + private int getStarCount() { + int starCount = 0; + if (model.score > WaterPoloModel.ONE_STAR_THRESHOLD) { + starCount++; + } + if (model.score > WaterPoloModel.TWO_STAR_THRESHOLD) { + starCount++; + } + if (model.score > WaterPoloModel.THREE_STAR_THRESHOLD) { + starCount++; + } + return starCount; + } + + /** + * The gesture detector for the water polo game. Supports the fling gesture. + */ + private abstract class WaterPoloGestureDetector { + float downX; + float downY; + + void onTouchEvent(MotionEvent event) { + switch(event.getAction()) { + case (MotionEvent.ACTION_DOWN): + downX = event.getX(); + downY = event.getY(); + + break; + case (MotionEvent.ACTION_UP): + case (MotionEvent.ACTION_OUTSIDE): + float velocityX = event.getX() - downX; + float velocityY = event.getY() - downY; + + onPan((float) Math.atan2(velocityY, velocityX)); + break; + } + } + + public abstract void onPan(float radians); + } + + @Override + public boolean isGameOver() { + return mIsGameOver; + } +} + diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloModel.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloModel.java new file mode 100644 index 000000000..660ef883b --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloModel.java @@ -0,0 +1,944 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.waterpolo; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Paint; +import android.os.Vibrator; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.Actor; +import com.google.android.apps.santatracker.doodles.shared.ActorHelper; +import com.google.android.apps.santatracker.doodles.shared.ActorTween; +import com.google.android.apps.santatracker.doodles.shared.ActorTween.Callback; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite; +import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite.AnimatedSpriteListener; +import com.google.android.apps.santatracker.doodles.shared.BallActor; +import com.google.android.apps.santatracker.doodles.shared.CameraShake; +import com.google.android.apps.santatracker.doodles.shared.EmptyTween; +import com.google.android.apps.santatracker.doodles.shared.EventBus; +import com.google.android.apps.santatracker.doodles.shared.GameFragment; +import com.google.android.apps.santatracker.doodles.shared.Interpolator; +import com.google.android.apps.santatracker.doodles.shared.RectangularInstructionActor; +import com.google.android.apps.santatracker.doodles.shared.SpriteActor; +import com.google.android.apps.santatracker.doodles.shared.Sprites; +import com.google.android.apps.santatracker.doodles.shared.TextActor; +import com.google.android.apps.santatracker.doodles.shared.Tween; +import com.google.android.apps.santatracker.doodles.shared.TweenManager; +import com.google.android.apps.santatracker.doodles.shared.Vector2D; +import com.google.android.apps.santatracker.doodles.tilt.ColoredRectangleActor; +import com.google.android.apps.santatracker.doodles.waterpolo.WaterPoloActor.WaterPoloActorPart; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +/** + * Model for the Water Polo game. + */ +public class WaterPoloModel { + + /** + * A grape that the apple throws. + */ + class GrapeActor extends BallActor { + public boolean shotBlocked; + public int bounces; + GrapeActor(AnimatedSprite ballSprite) { + super(null, ballSprite, null, 3); + bounces = 0; + shotBlocked = false; + } + } + + /** + * High-level phases of the game are controlled by a state machine which uses these states. + */ + enum State { + TITLE, + WAITING, + PLAYING, + GAME_OVER + } + + private static final String TAG = WaterPoloModel.class.getSimpleName(); + + private static final float SHAKE_FALLOFF = 0.9f; + private static final int VIBRATION_SMALL = 40; + + public static final int WATER_POLO_HEIGHT = 960; + public static final int WATER_POLO_WIDTH = 540; + + public static final int ONE_STAR_THRESHOLD = 1; + public static final int TWO_STAR_THRESHOLD = 10; + public static final int THREE_STAR_THRESHOLD = 20; + + private static final float TIME_LEFT_TEXT_X = WATER_POLO_WIDTH * 0.5f; + private static final float TIME_LEFT_TEXT_Y = 12; + private static final float TIME_LEFT_TEXT_SCALE = 3.2f; + private static final String TIME_LEFT_UNDER_TEXT = "88:88"; + private static final int TIME_LEFT_TEXT_RGB = 0xFFFFBD2E; + private static final int TIME_LEFT_TEXT_GLOW_RGB = 0x88FF9A2E; + private static final int TIME_LEFT_UNDER_RGB = 0xFF3B200D; + + private static final float POINT_TEXT_ANIMATION_TIME = 1.6f; + + private static final int POINT_MINUS_TEXT_RGB = 0xffd61e1e; + private static final int POINT_PLUS_TEXT_RGB = 0xff4dab1f; + + // Currently throw delay is not supported. The constant and related variables are left in to + // facilitate prototyping in case throw delay would be supported in the future. + private static final float THROW_DELAY_SECONDS = 0.4f; + private static final float TOTAL_TIME = 30f; + private static final int BALL_SPEED = 1300; + + private static final int OPPONENT_ONE_ENTRANCE_THRESHOLD = 1; + private static final int OPPONENT_TWO_ENTRANCE_THRESHOLD = 4; + private static final int OPPONENT_THREE_ENTRANCE_THRESHOLD = 10; + + private static final int OPPONENT_ONE_SPEED = 60; + private static final int OPPONENT_TWO_SPEED = 120; + private static final int OPPONENT_THREE_SPEED = 170; + + private static final int MS_BETWEEN_TARGET_FLASHES = 1000; + + public CameraShake cameraShake; + public List actors; + private List effects; + + private Resources resources; + private EventBus eventBus; + private final Vibrator vibrator; + private TweenManager tweenManager; + + private WaterPoloActor player; + + private WaterPoloActor opponentOne; + private WaterPoloActor opponentTwo; + private WaterPoloActor opponentThree; + + private ColoredRectangleActor timeLeftFrameBorder; + private ColoredRectangleActor timeLeftFrame; + private TextActor timeLeftText; + private TextActor timeLeftTextGlow; + private TextActor timeLeftUnder; + + private List balls; + private SpriteActor slideBack; + private SpriteActor targetLeft; + private SpriteActor targetMiddle; + private SpriteActor targetRight; + private SpriteActor goal; + + private static final float GOAL_BOX_X = 108; + private static final float GOAL_BOX_Y = 75; + private static final float GOAL_BOX_WIDTH = 333; + private static final float GOAL_BOX_HEIGHT = 98; + + RectangularInstructionActor instructions; + + public State state; + public int score; + public int ballsThrown; + public long titleDurationMs = GameFragment.TITLE_DURATION_MS; + private float time; + private float msTillNextTargetPulse; + private boolean scoredAtLeastOneShot; + private boolean canThrow; + + private boolean didReset; + + public WaterPoloModel(Resources resources, Context context) { + this.resources = resources; + actors = new ArrayList<>(); + effects = new ArrayList<>(); + balls = new ArrayList<>(); + cameraShake = new CameraShake(); + actors.add(cameraShake); + tweenManager = new TweenManager(); + eventBus = EventBus.getInstance(); + vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + createActors(); + reset(true); + } + + private void createActors() { + Actor pool = actorWithIds(Sprites.present_throw_floor); + pool.zIndex = -3; + + // The pool image is 780x960, but the center 540x960 of that image is what corresponds + // to the game area, so offset the image to the left. The edges only show on screens with aspect + // ratios wider than 9:16. + pool.position.x = -120; + actors.add(pool); + + goal = actorWithIds(Sprites.present_throw_santabag); + goal.position.set(-14, 72); + goal.zIndex = -4; + goal.sprite.setLoop(false); + goal.sprite.setPaused(true); + goal.sprite.addListener(new AnimatedSpriteListener() { + @Override + public void onFinished() { + goal.sprite.setFrameIndex(0); + goal.sprite.setPaused(true); + } + }); + actors.add(goal); + + slideBack = actorWithIds(Sprites.present_throw_elfbag); + slideBack.zIndex = 4; + actors.add(slideBack); + + moveSlide(0); + + timeLeftFrame = new ColoredRectangleActor( + Vector2D.get(WATER_POLO_WIDTH * 0.35f, TIME_LEFT_TEXT_Y - 6), + Vector2D.get(WATER_POLO_WIDTH * 0.3f, 50)); + timeLeftFrame.setColor(0xff000000); + timeLeftFrame.zIndex = 4; + actors.add(timeLeftFrame); + + timeLeftFrameBorder = new ColoredRectangleActor( + Vector2D.get(WATER_POLO_WIDTH * 0.35f, TIME_LEFT_TEXT_Y - 6), + Vector2D.get(WATER_POLO_WIDTH * 0.3f, 50)); + timeLeftFrameBorder.setStyle(Paint.Style.STROKE); + timeLeftFrameBorder.setStrokeWidth(5); + timeLeftFrameBorder.setColor(0xff555555); + timeLeftFrameBorder.zIndex = 4; + actors.add(timeLeftFrameBorder); + + timeLeftUnder = new TextActor(TIME_LEFT_UNDER_TEXT); + timeLeftUnder.position.set(TIME_LEFT_TEXT_X, TIME_LEFT_TEXT_Y); + timeLeftUnder.scale = TIME_LEFT_TEXT_SCALE; + timeLeftUnder.setBold(true); + timeLeftUnder.setFont(resources.getAssets(), "dseg7.ttf"); + timeLeftUnder.setColor(TIME_LEFT_UNDER_RGB); + timeLeftUnder.alignCenter(); + timeLeftUnder.zIndex = 4; + actors.add(timeLeftUnder); + + timeLeftTextGlow = new TextActor("00:30"); + timeLeftTextGlow.position.set(TIME_LEFT_TEXT_X, TIME_LEFT_TEXT_Y); + timeLeftTextGlow.scale = TIME_LEFT_TEXT_SCALE; + timeLeftTextGlow.setBold(true); + timeLeftTextGlow.enableBlur(0.6f); + timeLeftTextGlow.setFont(resources.getAssets(), "dseg7.ttf"); + timeLeftTextGlow.setColor(TIME_LEFT_TEXT_GLOW_RGB); + timeLeftTextGlow.alignCenter(); + timeLeftTextGlow.zIndex = 5; + actors.add(timeLeftTextGlow); + + timeLeftText = new TextActor("00:30"); + timeLeftText.position.set(TIME_LEFT_TEXT_X, TIME_LEFT_TEXT_Y); + timeLeftText.scale = TIME_LEFT_TEXT_SCALE; + timeLeftText.setBold(true); + timeLeftText.setFont(resources.getAssets(), "dseg7.ttf"); + timeLeftText.setColor(TIME_LEFT_TEXT_RGB); + timeLeftText.alignCenter(); + timeLeftText.zIndex = 6; + actors.add(timeLeftText); + + targetLeft = createTarget(166, 128); + actors.add(targetLeft); + + targetMiddle = createTarget(273, 128); + actors.add(targetMiddle); + + targetRight = createTarget(380, 128); + actors.add(targetRight); + + // TODO: Change block sprites + opponentOne = createOpponent(0.8f, + Sprites.present_throw_def_orange_left, + Sprites.present_throw_def_orange_right, + Sprites.present_throw_def_orange_emerge, + Sprites.present_throw_def_orange_blocking); + actors.add(opponentOne); + + opponentTwo = createOpponent(0.9f, + Sprites.present_throw_def_green_left, + Sprites.present_throw_def_green_right, + Sprites.present_throw_def_green_emerge, + Sprites.present_throw_def_green_blocking); + actors.add(opponentTwo); + + opponentThree = createOpponent(1.0f, + Sprites.present_throw_def_red_left, + Sprites.present_throw_def_red_right, + Sprites.present_throw_def_red_emerge, + Sprites.present_throw_def_red_blocking); + actors.add(opponentThree); + + player = new WaterPoloActor(); + player.addSprite(WaterPoloActorPart.BodyIdle, -84, 180, + spriteWithIds(Sprites.present_throw_idle)); + player.addSprite(WaterPoloActorPart.BodyThrow, -84, 180, + spriteWithIds(Sprites.present_throw_throwing)); + player.addSprite(WaterPoloActorPart.BodyPickUpBall, -84, 180, + spriteWithIds(Sprites.present_throw_reloading)); + player.addSprite(WaterPoloActorPart.BodyIdleNoBall, -84, 180, + spriteWithIds(Sprites.present_throw_celebrate, 2)); + + actors.add(player); + + AnimatedSprite diagram = spriteWithIds(Sprites.present_throw_tutorials); + diagram.setFPS(7); + + instructions = new RectangularInstructionActor(resources, diagram); + instructions.hidden = true; + instructions.scale = 0.6f; + instructions.position.set(WATER_POLO_WIDTH * 0.5f - instructions.getScaledWidth() / 2, + WATER_POLO_HEIGHT * 0.46f - instructions.getScaledHeight() / 2f); + actors.add(instructions); + } + + SpriteActor createTarget(float x, float y) { + SpriteActor target = actorWithIds(Sprites.waterpolo_target); + target.sprite.setAnchor(target.sprite.frameWidth / 2, target.sprite.frameHeight / 2); + target.position.set(x, y); + target.hidden = true; + return target; + } + + WaterPoloActor createOpponent(float scale, + int[] leftSprite, int[] rightSprite, + int[] emergeSprite, int[] blockSprite) { + WaterPoloActor opponent = new WaterPoloActor(); + + opponent.addSprite(WaterPoloActorPart.BodyEntrance, -45, 142, + spriteWithIds(emergeSprite, 12)); + opponent.addSprite(WaterPoloActorPart.BodyLeft, -45, 142, + spriteWithIds(leftSprite, 6)); + opponent.addSprite(WaterPoloActorPart.BodyRight, -45, 142, + spriteWithIds(rightSprite, 6)); + opponent.addSprite(WaterPoloActorPart.BodyBlock, -45, 142, + spriteWithIds(blockSprite)); + opponent.scale = scale; + opponent.setCollisionBox(100, 90); + return opponent; + } + + /** + * Moves the slide left / right. Used to attach the slide to the side of the screen on different + * aspect ratio screens. + */ + public void moveSlide(float slideOffsetX) { + slideBack.position.set(300 + slideOffsetX, 760); + } + + // Put everything back to the beginning state. + // Used at start of game & also if user clicks replay. + public void reset(boolean firstPlay) { + tweenManager.removeAll(); + if (firstPlay) { + setState(State.TITLE); + } else { + setState(State.WAITING); + } + + // Remove all temporary effects + for (int i = effects.size() - 1; i >= 0; i--) { + Actor effect = effects.get(i); + actors.remove(effect); + effects.remove(effect); + } + + // Remove all balls + for (int i = balls.size() - 1; i >= 0; i--) { + BallActor ball = balls.get(i); + actors.remove(ball); + balls.remove(ball); + } + + score = 0; + scoredAtLeastOneShot = false; + ballsThrown = 0; + eventBus.sendEvent(EventBus.SCORE_CHANGED, score); + + // No opponents at start of game (give them 1 easy point to re-inforce that they are supposed + // to get goals, not attack the goalie). + opponentOne.hidden = true; + opponentTwo.hidden = true; + opponentThree.hidden = true; + + msTillNextTargetPulse = MS_BETWEEN_TARGET_FLASHES; + + // Y positions picked so opponents look evenly spaced when in perspective. + // X positions picked to make opponents come up on the left side (because they swim right + // first, so coming up on the left side gives room to swim) but not all at the same position + // (staggered looks better). + opponentOne.position.set(171, 300); + opponentTwo.position.set(271, 440); + opponentThree.position.set(171, 600); + player.position.set(198, 845); + player.idle(); + + canThrow = true; + maybePickUpAnotherBall(); + if (firstPlay) { + // TODO: If you swipe before the instructions show, they still show. + // Fix this by adding a state machine like the android games have. + tweenManager.add(new EmptyTween(1.3f) { + @Override + protected void onFinish() { + if (ballsThrown == 0) { + instructions.show(); + } + } + }); + } + didReset = true; + time = TOTAL_TIME; + } + + public void update(long deltaMs) { + // Track whether reset was called at any point. + // If so, this short-circuits the rest of the update. + didReset = false; + + if (state == State.PLAYING) { + time = time - ((int) deltaMs / 1000f); + if (time <= 0) { + time = 0; + player.idleNoBall(); + setState(State.GAME_OVER); + } + } + + updateTimeLeftText(); + + tweenManager.update(deltaMs); + if (didReset) { + return; + } + + for (int i = actors.size() - 1; i >= 0; i--) { + Actor actor = actors.get(i); + actor.update(deltaMs); + if (didReset) { + return; + } + } + + for (int i = balls.size() - 1; i >= 0; i--) { + updateBall(balls.get(i)); + } + + // Show the targets until the player gets at least 1 shot in the goal. + if (!scoredAtLeastOneShot) { + float msTillNextTargetPulseBefore = msTillNextTargetPulse; + msTillNextTargetPulse -= deltaMs; + if (msTillNextTargetPulseBefore > 0 && msTillNextTargetPulse <= 0) { + pulseTargets(); + } + } + + Collections.sort(actors); + } + + void updateTimeLeftText() { + String timeLeftString = "00:" + String.format(Locale.ENGLISH, "%02d", (int) time); + timeLeftText.setText(timeLeftString); + timeLeftTextGlow.setText(timeLeftString); + } + + private void updateBall(final GrapeActor ball) { + // Make the ball shrink as it travels into the distance. + float ballStartY = 753; + float ballEndY = 157; + if (!ball.shotBlocked) { + ball.scale = 0.5f + (0.5f * (ball.position.y - ballEndY) / (ballStartY - ballEndY)); + } + + // Only allow blocking if ball is traveling towards goal (otherwise ball can get stuck bouncing + // between opponents). + if (ball.velocity.y < 0) { + final WaterPoloActor blockingOpponent = getBlockingOpponentIfAny(ball); + if (blockingOpponent != null) { + // Draw a -1 at the ball + addPointText(ball.position.x, ball.position.y - 150, "-1", POINT_MINUS_TEXT_RGB); + + newScore(score - 1); + blockShot(ball, blockingOpponent); + } + } + + // TODO: at small scales, ball isn't centered over its position. + // TODO: randomize vertical position of splats + if (!ball.shotBlocked && goalBoxContains(ball.position.x, ball.position.y)) { + // Draw a +1 at the ball. + + if (ball.bounces == 2) { + addPointText(ball.position.x, ball.position.y, "+2", POINT_PLUS_TEXT_RGB); + newScore(score + 2); + } else { + addPointText(ball.position.x, ball.position.y, "+1", POINT_PLUS_TEXT_RGB); + newScore(score + 1); + } + scoreShot(ball); + } + + // Check if ball has left screen. If so, count it as a miss and get ready for another throw. + if ((ball.position.y < 0 && !ball.shotBlocked)) { + missShot(ball); + } + + // Check if ball touches the left and right wall and has not bounced off the wall twice. + // If so, bounce it off the wall. + // If not, remove the ball from play. + if (ball.position.x <= 0 || ball.position.x >= WATER_POLO_WIDTH) { + if (ball.bounces > 1 || ball.shotBlocked) { + missShot(ball); + } else { + ball.velocity.x = -ball.velocity.x; + ball.rotation = (float) (Math.atan(ball.velocity.y / ball.velocity.x) - (Math.PI / 2)); + ball.update(20); + ball.bounces++; + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.present_throw_block); + } + } + + // Ditto for the bottom wall. + if (ball.position.y > WATER_POLO_HEIGHT) { + if (ball.bounces > 1 || ball.shotBlocked) { + missShot(ball); + } else { + ball.velocity.y = -ball.velocity.y; + ball.rotation = (float) (Math.atan(ball.velocity.y / ball.velocity.x) - (Math.PI / 2)); + ball.update(20); + ball.bounces++; + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.present_throw_block); + } + } + } + + private void addBall(float radians) { + AnimatedSprite ballSprite = spriteWithIds(Sprites.present_throw_thrownpresent); + GrapeActor ball = new GrapeActor(ballSprite); + ball.shouldScaleWithHeight = false; + ball.zIndex = 20; + ball.position.set(player.position.x + 78, player.position.y - 89); + ball.clearStreak(); + + ball.rotation = radians + (float) Math.PI / 2; + ball.velocity.set(BALL_SPEED * (float) Math.cos(radians), + BALL_SPEED * (float) Math.sin(radians)); + ball.hidden = false; + + actors.add(ball); + balls.add(ball); + } + + + private void blockBall(final GrapeActor ball, WaterPoloActor blockingOpponent) { + float rotation = ball.velocity.x / 200; + float directionX = ball.velocity.x * 0.5f; + + if (ball.velocity.x > 0) { + directionX += 25; + } else { + directionX -= 25; + } + + float initialX = ball.position.x; + float finalX = initialX + directionX; + + float initialY = ball.position.y; + float midY = initialY - 140; + float finalY = initialY + 220; + + ball.velocity.set(0, 0); + ball.shotBlocked = true; + + final ActorTween secondYTween = new ActorTween(ball) { + @Override + protected void onFinish() { + if (actors.contains(ball)) { + missShot(ball); + } + } + } + .fromY(midY) + .toY(finalY) + .withInterpolator(Interpolator.EASE_IN) + .withDuration(0.4f); + + final ActorTween firstYTween = new ActorTween(ball) { + @Override + protected void onFinish() { + tweenManager.add(secondYTween); + } + } + .fromY(initialY) + .toY(midY) + .withInterpolator(Interpolator.EASE_OUT) + .withDuration(0.4f); + + final ActorTween xTween = new ActorTween(ball) + .fromX(initialX) + .toX(finalX) + .withRotation(0, rotation) + .withDuration(0.8f); + + tweenManager.add(firstYTween); + tweenManager.add(xTween); + } + + private boolean goalBoxContains(float x, float y) { + if (x < GOAL_BOX_X || x > GOAL_BOX_X + GOAL_BOX_WIDTH) { + return false; + } + if (y < GOAL_BOX_Y || y > GOAL_BOX_Y + GOAL_BOX_HEIGHT) { + return false; + } + return true; + } + + private void pulseTargets() { + targetLeft.hidden = false; + targetMiddle.hidden = false; + targetRight.hidden = false; + + targetLeft.alpha = 1; + targetMiddle.alpha = 1; + targetRight.alpha = 1; + + final float startScale = 1; + final float endScale = 0.6f; + final float bounceScale = 0.8f; + + final Tween fadeout = new Tween(0.2f) { + @Override + protected void updateValues(float percentDone) { + float alpha = Interpolator.FAST_IN.getValue(percentDone, 1, 0); + targetLeft.alpha = alpha; + targetMiddle.alpha = alpha; + targetRight.alpha = alpha; + } + + @Override + protected void onFinish() { + targetLeft.hidden = true; + targetMiddle.hidden = true; + targetRight.hidden = true; + msTillNextTargetPulse = MS_BETWEEN_TARGET_FLASHES; + } + }; + + final Tween bounceThree = new Tween(0.15f) { + @Override + protected void updateValues(float percentDone) { + float scale = Interpolator.FAST_IN.getValue(percentDone, bounceScale, endScale); + targetLeft.scale = scale; + targetMiddle.scale = scale; + targetRight.scale = scale; + } + + @Override + protected void onFinish() { + tweenManager.add(fadeout); + } + }; + + final Tween bounceTwo = new Tween(0.15f) { + @Override + protected void updateValues(float percentDone) { + float scale = Interpolator.FAST_IN.getValue(percentDone, bounceScale, endScale); + targetLeft.scale = scale; + targetMiddle.scale = scale; + targetRight.scale = scale; + } + + @Override + protected void onFinish() { + tweenManager.add(score == 0 ? bounceThree : fadeout); + } + }; + + final Tween bounceOne = new Tween(0.15f) { + @Override + protected void updateValues(float percentDone) { + float scale = Interpolator.FAST_IN.getValue(percentDone, bounceScale, endScale); + targetLeft.scale = scale; + targetMiddle.scale = scale; + targetRight.scale = scale; + } + + @Override + protected void onFinish() { + tweenManager.add(score == 0 ? bounceTwo : fadeout); + } + }; + + Tween shrinkIn = new Tween(0.3f) { + @Override + protected void updateValues(float percentDone) { + float scale = Interpolator.FAST_IN.getValue(percentDone, startScale, endScale); + targetLeft.scale = scale; + targetMiddle.scale = scale; + targetRight.scale = scale; + } + + @Override + protected void onFinish() { + tweenManager.add(score == 0 ? bounceOne : fadeout); + } + }; + + tweenManager.add(shrinkIn); + } + + WaterPoloActor getBlockingOpponentIfAny(GrapeActor ball) { + if (ball.shotBlocked) { + return null; // Already blocked once, let it go. + } + + if (opponentOne.canBlock(ball.position.x, ball.position.y)) { + return opponentOne; + } else if (opponentTwo.canBlock(ball.position.x, ball.position.y)) { + return opponentTwo; + } else if (opponentThree.canBlock(ball.position.x, ball.position.y)) { + return opponentThree; + } + return null; + } + + private void blockShot(final GrapeActor ball, final WaterPoloActor blockingOpponent) { + // Blocked! + ball.shotBlocked = true; + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.tennis_eliminate); + + blockingOpponent.blockShot(new Callback() { + @Override + public void call() { + blockBall(ball, blockingOpponent); + shake(1, VIBRATION_SMALL); + } + }); + } + + private void missShot(GrapeActor ball) { + actors.remove(ball); + balls.remove(ball); + } + + private void scoreShot(GrapeActor ball) { + actors.remove(ball); + balls.remove(ball); + + // Swap ball for splat. + final SpriteActor splat = actorWithIds(Sprites.orange_present_falling); + splat.position.set(ball.position.x - splat.sprite.frameWidth / 2, + ball.position.y - splat.sprite.frameHeight); + splat.zIndex = -1; + splat.sprite.setLoop(false); + splat.sprite.addListener(new AnimatedSpriteListener() { + @Override + public void onFinished() { + actors.remove(splat); + effects.remove(splat); + } + }); + actors.add(splat); + effects.add(splat); + + // Shake the goal. + goal.sprite.setPaused(false); + + // Play goal score sound. + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.present_throw_goal); + + // Shake the screen a little bit. + shake(1, VIBRATION_SMALL); + + // Reset ball. + ball.velocity.set(0, 0); + ball.position.set(player.position.x, player.position.y); + + // Time for more opponents? + if (score >= OPPONENT_ONE_ENTRANCE_THRESHOLD && opponentOne.hidden) { + bringInOpponent(opponentOne, OPPONENT_ONE_SPEED); + } + if (score >= OPPONENT_TWO_ENTRANCE_THRESHOLD && opponentTwo.hidden) { + bringInOpponent(opponentTwo, OPPONENT_TWO_SPEED); + } + if (score >= OPPONENT_THREE_ENTRANCE_THRESHOLD && opponentThree.hidden) { + bringInOpponent(opponentThree, OPPONENT_THREE_SPEED); + } + + scoredAtLeastOneShot = true; + } + + private void newScore(int newScore) { + score = newScore; + eventBus.sendEvent(EventBus.SCORE_CHANGED, score); + } + + private void addPointText(float x, float y, String pointText, int color) { + final TextActor pointTextActor = new TextActor(pointText); + + x = x - 30; + y = y - 70; + + pointTextActor.setColor(color); + + pointTextActor.setBold(true); + pointTextActor.position.set(x, y); + pointTextActor.scale = 5; + pointTextActor.zIndex = 1000; + actors.add(pointTextActor); + effects.add(pointTextActor); + tweenManager.add(new ActorTween(pointTextActor) { + @Override + protected void onFinish() { + actors.remove(pointTextActor); + effects.remove(pointTextActor); + } + } + .withDuration(POINT_TEXT_ANIMATION_TIME) + .withAlpha(1, 0) + .toY(y - 80) + .withInterpolator(Interpolator.FAST_IN)); + } + + private void bringInOpponent(final WaterPoloActor opponent, final float speed) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.present_throw_character_appear); + opponent.hidden = false; + opponent.enter(new Callback() { + @Override + public void call() { + tweenOpponentRight(opponent, speed); + } + }); + } + +// Move opponent to the right. Chain a tween to the left at the end for endless motion. + private void tweenOpponentRight(final WaterPoloActor opponent, final float speed) { + if (state != State.PLAYING) { + // Stop moving opponents side-to-side at end of game. + tweenOpponentLeft(opponent, speed); + return; + } + tweenOpponent(opponent, 400, speed, new Callback() { + @Override + public void call() { + tweenOpponentLeft(opponent, speed); + } + }); + opponent.swimRight(); + } + + // Move opponent to the left. Chain a tween to the right at the end for endless motion. + private void tweenOpponentLeft(final WaterPoloActor opponent, final float speed) { + tweenOpponent(opponent, 0, speed, new Callback() { + @Override + public void call() { + tweenOpponentRight(opponent, speed); + } + }); + opponent.swimLeft(); + } + + // Helper function for moving opponents left & right. + private void tweenOpponent(WaterPoloActor opponent, float x, float speed, Callback next) { + ActorTween tween = new ActorTween(opponent) + .toX(x) + .withDuration(ActorHelper.distanceBetween(opponent.position.x, 0, x, 0) / speed) + .whenFinished(next); + tweenManager.add(tween); + } + + private void maybePickUpAnotherBall() { + if (state == State.GAME_OVER) { + // No-op + } else if (ballsThrown == 0) { + // No-op + } else { + // No-op + } + } + + public void onFling(final float radians) { + if (state == State.GAME_OVER || balls.size() > 0) { + return; + } + if (state == State.WAITING) { + instructions.hide(); + setState(State.PLAYING); + } + canThrow = false; // No more throws until ball either goes in goal or leaves screen. + tweenManager.add(new EmptyTween(THROW_DELAY_SECONDS) { + @Override + protected void onFinish() { + canThrow = true; + } + }); + ballsThrown++; + + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.present_throw_throw); + + player.throwBall(new Callback() { + @Override + public void call() { + addBall(radians); + } + }, new Callback() { + @Override + public void call() { + maybePickUpAnotherBall(); + } + }); + } + + private SpriteActor actorWithIds(int[] ids) { + return new SpriteActor(spriteWithIds(ids), Vector2D.get(0, 0), Vector2D.get(0, 0)); + } + + private AnimatedSprite spriteWithIds(int[] ids, int fps) { + AnimatedSprite sprite = spriteWithIds(ids); + sprite.setFPS(fps); + + return sprite; + } + + private AnimatedSprite spriteWithIds(int[] ids) { + return AnimatedSprite.fromFrames(resources, ids); + } + + private void shake(float screenShakeMagnitude, long vibrationMs) { + vibrator.vibrate(vibrationMs); + if (screenShakeMagnitude > 0) { + cameraShake.shake(33, screenShakeMagnitude, SHAKE_FALLOFF); + } + } + + public void setState(State newState) { + state = newState; + eventBus.sendEvent(EventBus.GAME_STATE_CHANGED, newState); + + if (newState == State.TITLE) { + tweenManager.add(new EmptyTween(titleDurationMs / 1000.0f) { + @Override + protected void onFinish() { + setState(State.WAITING); + } + }); + } + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloPauseView.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloPauseView.java new file mode 100644 index 000000000..400390d5d --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloPauseView.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.waterpolo; + +import android.content.Context; +import android.view.View; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.PauseView; + +/** + * Special subclass of {@link PauseView} for Waterpolo. + */ +public class WaterPoloPauseView extends PauseView { + + public WaterPoloPauseView(Context context) { + super(context); + } + + @Override + protected void loadLayout(Context context) { + super.loadLayout(context); + + // Hide replay button + findViewById(R.id.replay_button).setVisibility(View.GONE); + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloScoreView.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloScoreView.java new file mode 100644 index 000000000..ecfe19508 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloScoreView.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.waterpolo; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.View; + +import com.google.android.apps.santatracker.doodles.R; +import com.google.android.apps.santatracker.doodles.shared.EventBus; +import com.google.android.apps.santatracker.doodles.shared.GameOverlayButton; +import com.google.android.apps.santatracker.doodles.shared.LaunchDecisionMaker; +import com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent; +import com.google.android.apps.santatracker.doodles.shared.ScoreView; + + +/** + * ScoreView for WaterPolo game. + */ +public class WaterPoloScoreView extends ScoreView { + + private WaterPoloModel mModel; + + public WaterPoloScoreView(Context context, OnShareClickedListener shareClickedListener) { + super(context, shareClickedListener); + } + + public WaterPoloScoreView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public WaterPoloScoreView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void goToMoreGames(Context context) { + EventBus.getInstance().sendEvent(EventBus.PLAY_SOUND, R.raw.menu_item_click); + logger.logEvent(new PineappleLogEvent + .Builder(PineappleLogEvent.DEFAULT_DOODLE_NAME, PineappleLogEvent.HOME_CLICKED) + .withEventSubType(listener.gameType()) + .build()); + if(mModel != null) { + int stars; + if (mModel.score > WaterPoloModel.THREE_STAR_THRESHOLD) { + stars = 3; + } else if (mModel.score > WaterPoloModel.TWO_STAR_THRESHOLD) { + stars = 2; + } else { + stars = 1; + } + + Bundle bundle = new Bundle(); + bundle.putInt(LaunchDecisionMaker.EXTRA_PRESENT_DROP_SCORE, mModel.score); + bundle.putInt(LaunchDecisionMaker.EXTRA_PRESENT_DROP_STARS, stars); + LaunchDecisionMaker.finishActivityWithResult(context, Activity.RESULT_OK, bundle); + } else { + LaunchDecisionMaker.finishActivity(context); + } + } + + @Override + protected void loadLayout(Context context) { + super.loadLayout(context); + + // Disable replay for this game + View replayButton = findViewById(R.id.replay_button); + replayButton.setVisibility(View.GONE); + + // Disable sharing for this game + GameOverlayButton shareButton = (GameOverlayButton) findViewById(R.id.share_button); + shareButton.setVisibility(View.GONE); + } + + public void setModel(WaterPoloModel model) { + mModel = model; + } +} diff --git a/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloView.java b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloView.java new file mode 100644 index 000000000..aef85a370 --- /dev/null +++ b/doodles/src/main/java/com/google/android/apps/santatracker/doodles/waterpolo/WaterPoloView.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.apps.santatracker.doodles.waterpolo; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.view.View; + +import com.google.android.apps.santatracker.doodles.shared.Actor; + +/** + * Handles rendering for the water polo game. + * Copy and pasted from JumpingView. + */ +public class WaterPoloView extends View { + private static final String TAG = WaterPoloView.class.getSimpleName(); + + private static final int COLOR_FLOOR = 0xFFA6FFFF; + + private WaterPoloModel model; + private float currentScale; + private float currentOffsetX = 0; // In game units + private float currentOffsetY = 0; + + public WaterPoloView(Context context) { + this(context, null); + } + + public WaterPoloView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public WaterPoloView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public void setModel(WaterPoloModel model) { + this.model = model; + } + + @Override + protected void onDraw(Canvas canvas) { + if (model == null) { + return; + } + synchronized (model) { + super.onDraw(canvas); + canvas.save(); + canvas.drawColor(COLOR_FLOOR); + + // Fit-to-screen & center. + currentScale = Math.min(canvas.getWidth() / (float) WaterPoloModel.WATER_POLO_WIDTH, + canvas.getHeight() / (float) WaterPoloModel.WATER_POLO_HEIGHT); + + currentOffsetX = (canvas.getWidth() / currentScale - WaterPoloModel.WATER_POLO_WIDTH) / 2; + currentOffsetY = (canvas.getHeight() / currentScale - WaterPoloModel.WATER_POLO_HEIGHT) / 2; + + model.moveSlide(currentOffsetX); + + canvas.scale(currentScale, currentScale); + canvas.translate(currentOffsetX - model.cameraShake.position.x, + currentOffsetY - model.cameraShake.position.y); + + for (int i = 0; i < model.actors.size(); i++) { // Avoiding iterator to avoid garbage. + Actor actor = model.actors.get(i); + if (!actor.hidden) { + actor.draw(canvas); + } + } + canvas.restore(); + } + } +} diff --git a/doodles/src/main/res/drawable-nodpi/debug_marker.png b/doodles/src/main/res/drawable-nodpi/debug_marker.png new file mode 100644 index 000000000..55fcdd01f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/debug_marker.png differ diff --git a/doodles/src/main/res/drawable-nodpi/empty_frame.png b/doodles/src/main/res/drawable-nodpi/empty_frame.png new file mode 100644 index 000000000..cbca00f67 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/empty_frame.png differ diff --git a/doodles/src/main/res/drawable-nodpi/intro.png b/doodles/src/main/res/drawable-nodpi/intro.png new file mode 100644 index 000000000..0dae3c045 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/intro.png differ diff --git a/doodles/src/main/res/drawable-nodpi/melon_shadow.png b/doodles/src/main/res/drawable-nodpi/melon_shadow.png new file mode 100644 index 000000000..22ffc246e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/melon_shadow.png differ diff --git a/doodles/src/main/res/drawable-nodpi/orange_present1.png b/doodles/src/main/res/drawable-nodpi/orange_present1.png new file mode 100644 index 000000000..1493c3136 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/orange_present1.png differ diff --git a/doodles/src/main/res/drawable-nodpi/orange_present2.png b/doodles/src/main/res/drawable-nodpi/orange_present2.png new file mode 100644 index 000000000..b8f57b2d6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/orange_present2.png differ diff --git a/doodles/src/main/res/drawable-nodpi/orange_present3.png b/doodles/src/main/res/drawable-nodpi/orange_present3.png new file mode 100644 index 000000000..646a47206 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/orange_present3.png differ diff --git a/doodles/src/main/res/drawable-nodpi/orange_present4.png b/doodles/src/main/res/drawable-nodpi/orange_present4.png new file mode 100644 index 000000000..4d97992b6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/orange_present4.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_01.png new file mode 100644 index 000000000..af446ab19 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_02.png new file mode 100644 index 000000000..91aa79119 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_03.png new file mode 100644 index 000000000..bc0a6dc4f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_04.png new file mode 100644 index 000000000..a8707c9c7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_05.png new file mode 100644 index 000000000..0f46fdfad Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_06.png new file mode 100644 index 000000000..45a981aff Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_07.png new file mode 100644 index 000000000..14158040d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_08.png new file mode 100644 index 000000000..057e33722 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_09.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_09.png new file mode 100644 index 000000000..748648666 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ascending_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_banner.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_banner.png new file mode 100644 index 000000000..d3277580f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_banner.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_01.png new file mode 100644 index 000000000..11d8fb2fb Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_02.png new file mode 100644 index 000000000..d2fb0b876 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_03.png new file mode 100644 index 000000000..6f251d964 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_04.png new file mode 100644 index 000000000..90124eeb8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_05.png new file mode 100644 index 000000000..3a83b8131 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_candy_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_01.png new file mode 100644 index 000000000..228a1e68a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_02.png new file mode 100644 index 000000000..7e8a4287f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_03.png new file mode 100644 index 000000000..28f03896f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_04.png new file mode 100644 index 000000000..1ba04f3a8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_05.png new file mode 100644 index 000000000..711111fb8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_06.png new file mode 100644 index 000000000..c91dd01c5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_07.png new file mode 100644 index 000000000..3c9c30050 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_08.png new file mode 100644 index 000000000..7f0300b18 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_09.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_09.png new file mode 100644 index 000000000..6ed643869 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_10.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_10.png new file mode 100644 index 000000000..57cb1ecd1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_11.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_11.png new file mode 100644 index 000000000..bf1e1efb6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_12.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_12.png new file mode 100644 index 000000000..c11c6377e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_13.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_13.png new file mode 100644 index 000000000..5cd5a3269 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_14.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_14.png new file mode 100644 index 000000000..b2843bba2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_15.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_15.png new file mode 100644 index 000000000..968eb5857 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_16.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_16.png new file mode 100644 index 000000000..0fa3d7522 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_17.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_17.png new file mode 100644 index 000000000..b3937c3bf Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_17.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_18.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_18.png new file mode 100644 index 000000000..1c34d325f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_18.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_19.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_19.png new file mode 100644 index 000000000..7dc8f2cff Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_19.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_20.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_20.png new file mode 100644 index 000000000..30858df0e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_20.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_21.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_21.png new file mode 100644 index 000000000..9cbe130e8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_21.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_22.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_22.png new file mode 100644 index 000000000..b3718be5d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_22.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_23.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_23.png new file mode 100644 index 000000000..1e9b9e1c5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_23.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_24.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_24.png new file mode 100644 index 000000000..a9c24fe6c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_24.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_25.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_25.png new file mode 100644 index 000000000..f200f0bfb Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_25.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_26.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_26.png new file mode 100644 index 000000000..4c830b5da Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_26.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_27.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_27.png new file mode 100644 index 000000000..5f725379e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_27.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_28.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_28.png new file mode 100644 index 000000000..2188d9083 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_28.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_29.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_29.png new file mode 100644 index 000000000..2fb1c2a56 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_29.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_30.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_30.png new file mode 100644 index 000000000..74079a0eb Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_canegrab_30.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_01.png new file mode 100644 index 000000000..de24a1b06 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_02.png new file mode 100644 index 000000000..352669f64 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_03.png new file mode 100644 index 000000000..ecae2036c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_04.png new file mode 100644 index 000000000..02120291a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_05.png new file mode 100644 index 000000000..15200ab77 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_06.png new file mode 100644 index 000000000..b3047eaac Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_07.png new file mode 100644 index 000000000..b115bc5fb Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_08.png new file mode 100644 index 000000000..48d2211d1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_09.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_09.png new file mode 100644 index 000000000..8157cf8c0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_10.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_10.png new file mode 100644 index 000000000..79486fcec Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_11.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_11.png new file mode 100644 index 000000000..dbcbf2008 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_12.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_12.png new file mode 100644 index 000000000..e3d04bfe9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_13.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_13.png new file mode 100644 index 000000000..1db8900e7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_14.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_14.png new file mode 100644 index 000000000..4e7b67b9f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_15.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_15.png new file mode 100644 index 000000000..2a4827393 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_16.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_16.png new file mode 100644 index 000000000..5f4422b0b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_17.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_17.png new file mode 100644 index 000000000..88f752f0b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_17.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_18.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_18.png new file mode 100644 index 000000000..d57bbe5e6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_18.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_19.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_19.png new file mode 100644 index 000000000..02edef24b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_19.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_20.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_20.png new file mode 100644 index 000000000..63ab62528 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_20.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_21.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_21.png new file mode 100644 index 000000000..d0e1c2820 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_dazed_21.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_01.png new file mode 100644 index 000000000..13714aefc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_02.png new file mode 100644 index 000000000..2ed1cc454 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_03.png new file mode 100644 index 000000000..71ef2029f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_04.png new file mode 100644 index 000000000..b319cb133 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_05.png new file mode 100644 index 000000000..0f46fdfad Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_06.png new file mode 100644 index 000000000..57428f1e4 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_07.png new file mode 100644 index 000000000..5dab82643 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_08.png new file mode 100644 index 000000000..f8ed1923b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_09.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_09.png new file mode 100644 index 000000000..5d4ffc73c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_descending_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_01.png new file mode 100644 index 000000000..edd8331bc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_02.png new file mode 100644 index 000000000..f0f6cbeba Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_03.png new file mode 100644 index 000000000..fc972a269 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_04.png new file mode 100644 index 000000000..cee0ff22d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_05.png new file mode 100644 index 000000000..7cabcba4e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_06.png new file mode 100644 index 000000000..ae534854c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_07.png new file mode 100644 index 000000000..9b2ce5f05 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_08.png new file mode 100644 index 000000000..5559997a0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_09.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_09.png new file mode 100644 index 000000000..d42997839 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_10.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_10.png new file mode 100644 index 000000000..ae534854c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_11.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_11.png new file mode 100644 index 000000000..7cabcba4e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_12.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_12.png new file mode 100644 index 000000000..cee0ff22d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_13.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_13.png new file mode 100644 index 000000000..fc972a269 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_14.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_14.png new file mode 100644 index 000000000..f0f6cbeba Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_15.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_15.png new file mode 100644 index 000000000..edd8331bc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_elf_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_01.png new file mode 100644 index 000000000..662c8f4f6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_02.png new file mode 100644 index 000000000..c088a9631 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_03.png new file mode 100644 index 000000000..10e3ae82e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_04.png new file mode 100644 index 000000000..368f07d5a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_05.png new file mode 100644 index 000000000..aa22cc071 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_06.png new file mode 100644 index 000000000..44d1fedbc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_07.png new file mode 100644 index 000000000..a0b1a7fd9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_08.png new file mode 100644 index 000000000..1357fdff5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_09.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_09.png new file mode 100644 index 000000000..ab438a5e5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_10.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_10.png new file mode 100644 index 000000000..83579501d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_11.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_11.png new file mode 100644 index 000000000..5488f606a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_12.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_12.png new file mode 100644 index 000000000..2f1756718 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_13.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_13.png new file mode 100644 index 000000000..5e78c6ca3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_14.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_14.png new file mode 100644 index 000000000..8b14191f3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_15.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_15.png new file mode 100644 index 000000000..7d9411c05 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_16.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_16.png new file mode 100644 index 000000000..9e4feff87 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_17.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_17.png new file mode 100644 index 000000000..979d56262 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_17.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_18.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_18.png new file mode 100644 index 000000000..3f491b68c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_18.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_19.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_19.png new file mode 100644 index 000000000..7f925e55e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_19.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_20.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_20.png new file mode 100644 index 000000000..454b8cc1f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_20.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_21.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_21.png new file mode 100644 index 000000000..1482e0824 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_21.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_22.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_22.png new file mode 100644 index 000000000..7dfcb5bb1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_22.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_23.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_23.png new file mode 100644 index 000000000..e425d8fd9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_23.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_24.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_24.png new file mode 100644 index 000000000..6794e4396 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_24.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_25.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_25.png new file mode 100644 index 000000000..72e7e836c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_25.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_26.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_26.png new file mode 100644 index 000000000..d2f80e62d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_26.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_27.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_27.png new file mode 100644 index 000000000..4eeeb37bc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_27.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_28.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_28.png new file mode 100644 index 000000000..c52f8d645 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_28.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_29.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_29.png new file mode 100644 index 000000000..567f9ebac Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_frozen_29.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_01.png new file mode 100644 index 000000000..cb7b00a1d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_02.png new file mode 100644 index 000000000..b6ca31472 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_03.png new file mode 100644 index 000000000..87b9cc23d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_04.png new file mode 100644 index 000000000..89b9d559e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_05.png new file mode 100644 index 000000000..1e237f879 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_06.png new file mode 100644 index 000000000..1fdf4b09e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_07.png new file mode 100644 index 000000000..d3ec1baba Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_08.png new file mode 100644 index 000000000..1070730e9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_09.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_09.png new file mode 100644 index 000000000..d3ec1baba Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_10.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_10.png new file mode 100644 index 000000000..1fdf4b09e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_11.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_11.png new file mode 100644 index 000000000..1e237f879 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_12.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_12.png new file mode 100644 index 000000000..89b9d559e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_13.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_13.png new file mode 100644 index 000000000..87b9cc23d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_14.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_14.png new file mode 100644 index 000000000..b6ca31472 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_15.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_15.png new file mode 100644 index 000000000..cb7b00a1d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_ice_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_loadingscreen.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_loadingscreen.png new file mode 100644 index 000000000..1d0a3ade0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_loadingscreen.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_01.png new file mode 100644 index 000000000..3194e8786 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_02.png new file mode 100644 index 000000000..3194e8786 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_03.png new file mode 100644 index 000000000..ca73a9ff0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_04.png new file mode 100644 index 000000000..ca73a9ff0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_05.png new file mode 100644 index 000000000..3194e8786 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_06.png new file mode 100644 index 000000000..3194e8786 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_07.png new file mode 100644 index 000000000..ca73a9ff0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_08.png new file mode 100644 index 000000000..ca73a9ff0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_09.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_09.png new file mode 100644 index 000000000..fb315c1bf Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_10.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_10.png new file mode 100644 index 000000000..fb315c1bf Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_11.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_11.png new file mode 100644 index 000000000..04c2350e1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_12.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_12.png new file mode 100644 index 000000000..35bf340aa Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_13.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_13.png new file mode 100644 index 000000000..4bed13f78 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_14.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_14.png new file mode 100644 index 000000000..4bed13f78 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_15.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_15.png new file mode 100644 index 000000000..3bd5a8bc9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_start_16.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_16.png new file mode 100644 index 000000000..d84a7e680 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_start_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_01.png new file mode 100644 index 000000000..bdcd1b73d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_02.png new file mode 100644 index 000000000..7ae84ffde Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_03.png new file mode 100644 index 000000000..251a4b441 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_04.png new file mode 100644 index 000000000..1a0712b81 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_05.png new file mode 100644 index 000000000..cbf66a58b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_06.png new file mode 100644 index 000000000..01c49bf65 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_07.png new file mode 100644 index 000000000..7d981540a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_08.png new file mode 100644 index 000000000..b5951235d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_09.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_09.png new file mode 100644 index 000000000..b47c9773e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_10.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_10.png new file mode 100644 index 000000000..2940e13aa Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_11.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_11.png new file mode 100644 index 000000000..478f73a90 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_12.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_12.png new file mode 100644 index 000000000..ef0ca5fb2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_13.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_13.png new file mode 100644 index 000000000..2f3546fa7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_14.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_14.png new file mode 100644 index 000000000..1a8d6c2b1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_15.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_15.png new file mode 100644 index 000000000..3c8e4a823 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_16.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_16.png new file mode 100644 index 000000000..aa068a3fc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimming_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_01.png new file mode 100644 index 000000000..a273ae147 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_02.png new file mode 100644 index 000000000..f2e5a0784 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_03.png new file mode 100644 index 000000000..44fe1d289 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_04.png new file mode 100644 index 000000000..97d521c15 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_05.png new file mode 100644 index 000000000..6fa9bcf73 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_06.png new file mode 100644 index 000000000..05fc5c70e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_07.png new file mode 100644 index 000000000..8ed969802 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_08.png new file mode 100644 index 000000000..11b700b05 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_09.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_09.png new file mode 100644 index 000000000..dec050d83 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_10.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_10.png new file mode 100644 index 000000000..e72519cf7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_11.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_11.png new file mode 100644 index 000000000..d51e20e34 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_12.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_12.png new file mode 100644 index 000000000..36d6da611 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_13.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_13.png new file mode 100644 index 000000000..567f9ebac Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_14.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_14.png new file mode 100644 index 000000000..567f9ebac Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_15.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_15.png new file mode 100644 index 000000000..567f9ebac Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_16.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_16.png new file mode 100644 index 000000000..567f9ebac Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_01.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_01.png new file mode 100644 index 000000000..8565c6c47 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_02.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_02.png new file mode 100644 index 000000000..5fd79d0b6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_03.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_03.png new file mode 100644 index 000000000..8565c6c47 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_04.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_04.png new file mode 100644 index 000000000..5fd79d0b6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_05.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_05.png new file mode 100644 index 000000000..0d0ea2fd1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_06.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_06.png new file mode 100644 index 000000000..b805315e5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_07.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_07.png new file mode 100644 index 000000000..fb93e8704 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_08.png b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_08.png new file mode 100644 index 000000000..8284356fe Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swim_tutorials_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swimming_candycane_endscreen.png b/doodles/src/main/res/drawable-nodpi/penguin_swimming_candycane_endscreen.png new file mode 100644 index 000000000..9d7aa266c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swimming_candycane_endscreen.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swimming_dazed_endscreen.png b/doodles/src/main/res/drawable-nodpi/penguin_swimming_dazed_endscreen.png new file mode 100644 index 000000000..d459bfb4b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swimming_dazed_endscreen.png differ diff --git a/doodles/src/main/res/drawable-nodpi/penguin_swimming_frozen_endscreen.png b/doodles/src/main/res/drawable-nodpi/penguin_swimming_frozen_endscreen.png new file mode 100644 index 000000000..1d93f1933 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/penguin_swimming_frozen_endscreen.png differ diff --git a/doodles/src/main/res/drawable-nodpi/pineapple_star_empty.png b/doodles/src/main/res/drawable-nodpi/pineapple_star_empty.png new file mode 100644 index 000000000..44f8012b1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/pineapple_star_empty.png differ diff --git a/doodles/src/main/res/drawable-nodpi/pineapple_star_filled.png b/doodles/src/main/res/drawable-nodpi/pineapple_star_filled.png new file mode 100644 index 000000000..c85ffb5bd Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/pineapple_star_filled.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_01.png new file mode 100644 index 000000000..5c9f2a949 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_02.png new file mode 100644 index 000000000..ceaaffb9d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_03.png new file mode 100644 index 000000000..5e8ab1af3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_04.png new file mode 100644 index 000000000..ae7ae0d17 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_05.png new file mode 100644 index 000000000..5c9f2a949 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_06.png new file mode 100644 index 000000000..ceaaffb9d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_07.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_07.png new file mode 100644 index 000000000..5e8ab1af3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_08.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_08.png new file mode 100644 index 000000000..ae7ae0d17 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_09.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_09.png new file mode 100644 index 000000000..f06d3c8e0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_10.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_10.png new file mode 100644 index 000000000..c61f811c7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_11.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_11.png new file mode 100644 index 000000000..5b6896165 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_12.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_12.png new file mode 100644 index 000000000..1595f45a6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_13.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_13.png new file mode 100644 index 000000000..f06d3c8e0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_14.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_14.png new file mode 100644 index 000000000..c61f811c7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_15.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_15.png new file mode 100644 index 000000000..5b6896165 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_16.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_16.png new file mode 100644 index 000000000..1595f45a6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_green_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_01.png new file mode 100644 index 000000000..2e254cd3f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_02.png new file mode 100644 index 000000000..084fa9a54 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_03.png new file mode 100644 index 000000000..6153dfc6c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_04.png new file mode 100644 index 000000000..084fa9a54 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_05.png new file mode 100644 index 000000000..2e254cd3f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_06.png new file mode 100644 index 000000000..084fa9a54 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_07.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_07.png new file mode 100644 index 000000000..6153dfc6c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_08.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_08.png new file mode 100644 index 000000000..084fa9a54 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_09.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_09.png new file mode 100644 index 000000000..1e57ff8b2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_10.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_10.png new file mode 100644 index 000000000..1b410d0ce Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_11.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_11.png new file mode 100644 index 000000000..39070b5d0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_12.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_12.png new file mode 100644 index 000000000..1b410d0ce Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_13.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_13.png new file mode 100644 index 000000000..1e57ff8b2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_14.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_14.png new file mode 100644 index 000000000..1b410d0ce Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_15.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_15.png new file mode 100644 index 000000000..39070b5d0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_16.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_16.png new file mode 100644 index 000000000..1b410d0ce Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_orange_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_01.png new file mode 100644 index 000000000..b43b8ff70 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_02.png new file mode 100644 index 000000000..12e81acb7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_03.png new file mode 100644 index 000000000..cd1ba4373 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_04.png new file mode 100644 index 000000000..12e81acb7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_05.png new file mode 100644 index 000000000..b43b8ff70 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_06.png new file mode 100644 index 000000000..12e81acb7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_07.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_07.png new file mode 100644 index 000000000..cd1ba4373 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_08.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_08.png new file mode 100644 index 000000000..12e81acb7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_09.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_09.png new file mode 100644 index 000000000..cf9762ea0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_10.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_10.png new file mode 100644 index 000000000..936c9fbb6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_11.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_11.png new file mode 100644 index 000000000..8c7253854 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_12.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_12.png new file mode 100644 index 000000000..936c9fbb6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_13.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_13.png new file mode 100644 index 000000000..cf9762ea0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_14.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_14.png new file mode 100644 index 000000000..936c9fbb6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_15.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_15.png new file mode 100644 index 000000000..8c7253854 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_16.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_16.png new file mode 100644 index 000000000..936c9fbb6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocker_red_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_01.png new file mode 100644 index 000000000..88a82a6ff Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_02.png new file mode 100644 index 000000000..cb2c8c4d4 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_03.png new file mode 100644 index 000000000..c07eb4e1c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_04.png new file mode 100644 index 000000000..c7ddecab5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_05.png new file mode 100644 index 000000000..dffdf459f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_06.png new file mode 100644 index 000000000..2061b74f0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_07.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_07.png new file mode 100644 index 000000000..f73cc34f2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_08.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_08.png new file mode 100644 index 000000000..5139ea973 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_09.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_09.png new file mode 100644 index 000000000..f3cac212c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_10.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_10.png new file mode 100644 index 000000000..e91015830 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_11.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_11.png new file mode 100644 index 000000000..f1288f857 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_12.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_12.png new file mode 100644 index 000000000..e506d1b96 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_green_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_01.png new file mode 100644 index 000000000..52d81f277 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_02.png new file mode 100644 index 000000000..8f977e42d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_03.png new file mode 100644 index 000000000..12f9ad263 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_04.png new file mode 100644 index 000000000..b82a1ebb6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_05.png new file mode 100644 index 000000000..565b47d38 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_06.png new file mode 100644 index 000000000..5e2463f59 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_07.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_07.png new file mode 100644 index 000000000..829772a24 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_08.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_08.png new file mode 100644 index 000000000..b5967fae4 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_09.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_09.png new file mode 100644 index 000000000..c68e3dbf7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_10.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_10.png new file mode 100644 index 000000000..574ed2e73 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_11.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_11.png new file mode 100644 index 000000000..6b4fb122a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_12.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_12.png new file mode 100644 index 000000000..71606c6ef Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_orange_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_01.png new file mode 100644 index 000000000..c90895d59 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_02.png new file mode 100644 index 000000000..b10bebfd5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_03.png new file mode 100644 index 000000000..7e714dcb2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_04.png new file mode 100644 index 000000000..518c6478d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_05.png new file mode 100644 index 000000000..513ce2d90 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_06.png new file mode 100644 index 000000000..6e13efb7a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_07.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_07.png new file mode 100644 index 000000000..5e777b2c2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_08.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_08.png new file mode 100644 index 000000000..d66fab739 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_09.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_09.png new file mode 100644 index 000000000..ea5d3d36a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_10.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_10.png new file mode 100644 index 000000000..2f2e2af29 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_11.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_11.png new file mode 100644 index 000000000..63c83c6d9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_12.png b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_12.png new file mode 100644 index 000000000..c84ac7215 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_blocking_red_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_celebrating_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_celebrating_01.png new file mode 100644 index 000000000..ea1cad029 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_celebrating_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_celebrating_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_celebrating_02.png new file mode 100644 index 000000000..ed2d0f21b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_celebrating_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_elfbag.png b/doodles/src/main/res/drawable-nodpi/present_throw_elfbag.png new file mode 100644 index 000000000..bde14c25f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_elfbag.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_floor.png b/doodles/src/main/res/drawable-nodpi/present_throw_floor.png new file mode 100644 index 000000000..8eb101c60 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_floor.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_loadingscreen.png b/doodles/src/main/res/drawable-nodpi/present_throw_loadingscreen.png new file mode 100644 index 000000000..34c4c65b7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_loadingscreen.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_01.png new file mode 100644 index 000000000..b682452cc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_02.png new file mode 100644 index 000000000..ed61dad0b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_03.png new file mode 100644 index 000000000..9d6a87320 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_04.png new file mode 100644 index 000000000..f1e6dd40f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_05.png new file mode 100644 index 000000000..efe58cca3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_06.png new file mode 100644 index 000000000..764725bd6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_07.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_07.png new file mode 100644 index 000000000..f11ecf92f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_08.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_08.png new file mode 100644 index 000000000..4bc140cc2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_09.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_09.png new file mode 100644 index 000000000..55a804246 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_10.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_10.png new file mode 100644 index 000000000..6c71be80a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_11.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_11.png new file mode 100644 index 000000000..ca1f7bb0d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_12.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_12.png new file mode 100644 index 000000000..ca1f7bb0d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_green_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_01.png new file mode 100644 index 000000000..e60560141 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_02.png new file mode 100644 index 000000000..2f0d744dc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_03.png new file mode 100644 index 000000000..ace47293e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_04.png new file mode 100644 index 000000000..dbb705db8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_05.png new file mode 100644 index 000000000..7764b7826 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_06.png new file mode 100644 index 000000000..4302e8b01 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_07.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_07.png new file mode 100644 index 000000000..a2f035078 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_08.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_08.png new file mode 100644 index 000000000..052464f99 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_09.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_09.png new file mode 100644 index 000000000..c6a210194 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_10.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_10.png new file mode 100644 index 000000000..59b4d6a3a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_11.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_11.png new file mode 100644 index 000000000..59b4d6a3a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_12.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_12.png new file mode 100644 index 000000000..59b4d6a3a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_orange_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_01.png new file mode 100644 index 000000000..e60560141 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_02.png new file mode 100644 index 000000000..2f0d744dc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_03.png new file mode 100644 index 000000000..ace47293e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_04.png new file mode 100644 index 000000000..dbb705db8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_05.png new file mode 100644 index 000000000..02d9a5ce6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_06.png new file mode 100644 index 000000000..47b07f655 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_07.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_07.png new file mode 100644 index 000000000..e32411422 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_08.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_08.png new file mode 100644 index 000000000..29c6d1c6d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_09.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_09.png new file mode 100644 index 000000000..105128f4b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_10.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_10.png new file mode 100644 index 000000000..8c08a0037 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_11.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_11.png new file mode 100644 index 000000000..8c08a0037 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_12.png b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_12.png new file mode 100644 index 000000000..8c08a0037 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_newblocker_red_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_reloading_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_reloading_01.png new file mode 100644 index 000000000..72319ff2c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_reloading_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_reloading_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_reloading_02.png new file mode 100644 index 000000000..17ae082f1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_reloading_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_reloading_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_reloading_03.png new file mode 100644 index 000000000..8c5c28972 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_reloading_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_santabag.png b/doodles/src/main/res/drawable-nodpi/present_throw_santabag.png new file mode 100644 index 000000000..9ef03f31b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_santabag.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_throwing_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_01.png new file mode 100644 index 000000000..7b523b823 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_throwing_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_02.png new file mode 100644 index 000000000..86fb3d1fb Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_throwing_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_03.png new file mode 100644 index 000000000..783c32117 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_throwing_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_04.png new file mode 100644 index 000000000..93a29ec3f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_throwing_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_05.png new file mode 100644 index 000000000..72034e09a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_throwing_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_06.png new file mode 100644 index 000000000..fcdc14c55 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_throwing_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_thrownpresent_orange.png b/doodles/src/main/res/drawable-nodpi/present_throw_thrownpresent_orange.png new file mode 100644 index 000000000..e5818f069 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_thrownpresent_orange.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_01.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_01.png new file mode 100644 index 000000000..7bd5161d9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_02.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_02.png new file mode 100644 index 000000000..679277fe8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_03.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_03.png new file mode 100644 index 000000000..ab5af3bf3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_04.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_04.png new file mode 100644 index 000000000..0fef855d5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_05.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_05.png new file mode 100644 index 000000000..df3d4e028 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_06.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_06.png new file mode 100644 index 000000000..63648bb42 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_07.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_07.png new file mode 100644 index 000000000..ed861356d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_08.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_08.png new file mode 100644 index 000000000..7123b47d0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_09.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_09.png new file mode 100644 index 000000000..5482259f0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_10.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_10.png new file mode 100644 index 000000000..532f846dd Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_11.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_11.png new file mode 100644 index 000000000..ae8e6a175 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_12.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_12.png new file mode 100644 index 000000000..4ea20eeca Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_13.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_13.png new file mode 100644 index 000000000..60ed8f0e1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_14.png b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_14.png new file mode 100644 index 000000000..6ba378a75 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/present_throw_tutorials_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_button_00.png b/doodles/src/main/res/drawable-nodpi/running_button_00.png new file mode 100644 index 000000000..659d2149c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_button_00.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_button_01.png b/doodles/src/main/res/drawable-nodpi/running_button_01.png new file mode 100644 index 000000000..f804cba55 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_button_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_button_02.png b/doodles/src/main/res/drawable-nodpi/running_button_02.png new file mode 100644 index 000000000..48e0ae38b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_button_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_finish_line.png b/doodles/src/main/res/drawable-nodpi/running_finish_line.png new file mode 100644 index 000000000..8b709079e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_finish_line.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_powerup_00.png b/doodles/src/main/res/drawable-nodpi/running_powerup_00.png new file mode 100644 index 000000000..1f5278241 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_powerup_00.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_powerup_01.png b/doodles/src/main/res/drawable-nodpi/running_powerup_01.png new file mode 100644 index 000000000..323cefacc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_powerup_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_powerup_02.png b/doodles/src/main/res/drawable-nodpi/running_powerup_02.png new file mode 100644 index 000000000..4ff6c6ddb Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_powerup_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_powerup_03.png b/doodles/src/main/res/drawable-nodpi/running_powerup_03.png new file mode 100644 index 000000000..7a1b6ceff Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_powerup_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_powerup_04.png b/doodles/src/main/res/drawable-nodpi/running_powerup_04.png new file mode 100644 index 000000000..da6362e6f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_powerup_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_powerup_05.png b/doodles/src/main/res/drawable-nodpi/running_powerup_05.png new file mode 100644 index 000000000..c4ff04c80 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_powerup_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_powerup_06.png b/doodles/src/main/res/drawable-nodpi/running_powerup_06.png new file mode 100644 index 000000000..65a4ca8de Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_powerup_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/running_powerup_07.png b/doodles/src/main/res/drawable-nodpi/running_powerup_07.png new file mode 100644 index 000000000..04c15d08f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/running_powerup_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowball01.png b/doodles/src/main/res/drawable-nodpi/snowball01.png new file mode 100644 index 000000000..452537e51 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowball01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowball02.png b/doodles/src/main/res/drawable-nodpi/snowball02.png new file mode 100644 index 000000000..c1e3069aa Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowball02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowball03.png b/doodles/src/main/res/drawable-nodpi/snowball03.png new file mode 100644 index 000000000..8be397010 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowball03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowball04.png b/doodles/src/main/res/drawable-nodpi/snowball04.png new file mode 100644 index 000000000..df180b0c6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowball04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowball05.png b/doodles/src/main/res/drawable-nodpi/snowball05.png new file mode 100644 index 000000000..d9d1128bc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowball05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowball06.png b/doodles/src/main/res/drawable-nodpi/snowball06.png new file mode 100644 index 000000000..bef53e535 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowball06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowball07.png b/doodles/src/main/res/drawable-nodpi/snowball07.png new file mode 100644 index 000000000..31e8658af Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowball07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowball08.png b/doodles/src/main/res/drawable-nodpi/snowball08.png new file mode 100644 index 000000000..65b6ab448 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowball08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowball_runner_trees1.png b/doodles/src/main/res/drawable-nodpi/snowball_runner_trees1.png new file mode 100644 index 000000000..d0a845baf Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowball_runner_trees1.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowball_runner_trees2.png b/doodles/src/main/res/drawable-nodpi/snowball_runner_trees2.png new file mode 100644 index 000000000..d7a046359 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowball_runner_trees2.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_01.png b/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_01.png new file mode 100644 index 000000000..b3102fb70 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_02.png b/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_02.png new file mode 100644 index 000000000..7e3f701de Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_03.png b/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_03.png new file mode 100644 index 000000000..57884c805 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_04.png b/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_04.png new file mode 100644 index 000000000..64fe3baaf Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_05.png new file mode 100644 index 000000000..5b1c9761e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_elf_squished_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_05.png new file mode 100644 index 000000000..cf1210e8e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_06.png b/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_06.png new file mode 100644 index 000000000..d30ab5ea1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_07.png b/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_07.png new file mode 100644 index 000000000..5c20c1151 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_08.png b/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_08.png new file mode 100644 index 000000000..c8035cb3c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_09.png b/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_09.png new file mode 100644 index 000000000..e43a34514 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_elfopponent_squished_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_01.png b/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_01.png new file mode 100644 index 000000000..f485afff9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_02.png b/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_02.png new file mode 100644 index 000000000..76f71db75 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_03.png b/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_03.png new file mode 100644 index 000000000..6f1f2efd5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_04.png b/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_04.png new file mode 100644 index 000000000..2dd902358 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_05.png new file mode 100644 index 000000000..ea1bb4ce4 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_reindeer_squished_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_01.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_01.png new file mode 100644 index 000000000..083de4884 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_02.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_02.png new file mode 100644 index 000000000..713264e48 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_03.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_03.png new file mode 100644 index 000000000..694fd4d09 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_04.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_04.png new file mode 100644 index 000000000..9d78ff3fc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_05.png new file mode 100644 index 000000000..6bdcbf82b Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_06.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_06.png new file mode 100644 index 000000000..0544872b0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_07.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_07.png new file mode 100644 index 000000000..17879fbe7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_08.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_08.png new file mode 100644 index 000000000..631f95cbe Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_09.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_09.png new file mode 100644 index 000000000..9e4eaa7b1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_10.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_10.png new file mode 100644 index 000000000..dcf7fc64e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_11.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_11.png new file mode 100644 index 000000000..ccf1518c7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_12.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_12.png new file mode 100644 index 000000000..ccf1518c7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_appearing_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_01.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_01.png new file mode 100644 index 000000000..6ff7b68ef Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_02.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_02.png new file mode 100644 index 000000000..306050c3a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_03.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_03.png new file mode 100644 index 000000000..cf9f2ce70 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_04.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_04.png new file mode 100644 index 000000000..73f176b10 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_05.png new file mode 100644 index 000000000..6ff7b68ef Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_06.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_06.png new file mode 100644 index 000000000..306050c3a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_07.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_07.png new file mode 100644 index 000000000..cf9f2ce70 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_08.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_08.png new file mode 100644 index 000000000..73f176b10 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_09.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_09.png new file mode 100644 index 000000000..40e833530 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_10.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_10.png new file mode 100644 index 000000000..545bc38f3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_11.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_11.png new file mode 100644 index 000000000..572acfd5a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_12.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_12.png new file mode 100644 index 000000000..87668305a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_13.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_13.png new file mode 100644 index 000000000..40e833530 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_14.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_14.png new file mode 100644 index 000000000..545bc38f3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_15.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_15.png new file mode 100644 index 000000000..572acfd5a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_16.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_16.png new file mode 100644 index 000000000..87668305a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_elf_opponent_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing01.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing01.png new file mode 100644 index 000000000..ef70e3e55 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing02.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing02.png new file mode 100644 index 000000000..6cc4beed0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing03.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing03.png new file mode 100644 index 000000000..35c465ae5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing04.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing04.png new file mode 100644 index 000000000..255795ef7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing05.png new file mode 100644 index 000000000..ef70e3e55 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing06.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing06.png new file mode 100644 index 000000000..6cc4beed0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing07.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing07.png new file mode 100644 index 000000000..35c465ae5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing08.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing08.png new file mode 100644 index 000000000..255795ef7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing09.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing09.png new file mode 100644 index 000000000..ef70e3e55 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing10.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing10.png new file mode 100644 index 000000000..6cc4beed0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing11.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing11.png new file mode 100644 index 000000000..35c465ae5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing12.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing12.png new file mode 100644 index 000000000..255795ef7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing13.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing13.png new file mode 100644 index 000000000..ef70e3e55 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing14.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing14.png new file mode 100644 index 000000000..6cc4beed0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing15.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing15.png new file mode 100644 index 000000000..35c465ae5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing16.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing16.png new file mode 100644 index 000000000..255795ef7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_losing16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal01.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal01.png new file mode 100644 index 000000000..173d5d746 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal02.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal02.png new file mode 100644 index 000000000..a7881ac98 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal03.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal03.png new file mode 100644 index 000000000..f65cfc1a8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal04.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal04.png new file mode 100644 index 000000000..1e6083ffd Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal05.png new file mode 100644 index 000000000..173d5d746 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal06.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal06.png new file mode 100644 index 000000000..a7881ac98 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal07.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal07.png new file mode 100644 index 000000000..f65cfc1a8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal08.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal08.png new file mode 100644 index 000000000..1e6083ffd Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal09.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal09.png new file mode 100644 index 000000000..173d5d746 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal10.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal10.png new file mode 100644 index 000000000..a7881ac98 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal11.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal11.png new file mode 100644 index 000000000..f65cfc1a8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal12.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal12.png new file mode 100644 index 000000000..1e6083ffd Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal13.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal13.png new file mode 100644 index 000000000..173d5d746 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal14.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal14.png new file mode 100644 index 000000000..a7881ac98 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal15.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal15.png new file mode 100644 index 000000000..f65cfc1a8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal16.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal16.png new file mode 100644 index 000000000..1e6083ffd Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_normal16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_01.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_01.png new file mode 100644 index 000000000..af68faf19 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_02.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_02.png new file mode 100644 index 000000000..1eac24824 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_03.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_03.png new file mode 100644 index 000000000..d936df008 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_04.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_04.png new file mode 100644 index 000000000..d609979cf Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_05.png new file mode 100644 index 000000000..af68faf19 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_06.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_06.png new file mode 100644 index 000000000..1eac24824 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_07.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_07.png new file mode 100644 index 000000000..d936df008 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_08.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_08.png new file mode 100644 index 000000000..d609979cf Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_09.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_09.png new file mode 100644 index 000000000..3c8a8c2a8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_10.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_10.png new file mode 100644 index 000000000..24e7e8d84 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_11.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_11.png new file mode 100644 index 000000000..92d1adba0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_12.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_12.png new file mode 100644 index 000000000..e1fe958dc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_13.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_13.png new file mode 100644 index 000000000..3c8a8c2a8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_14.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_14.png new file mode 100644 index 000000000..24e7e8d84 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_15.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_15.png new file mode 100644 index 000000000..92d1adba0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_16.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_16.png new file mode 100644 index 000000000..e1fe958dc Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_reindeer_opponent_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_01.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_01.png new file mode 100644 index 000000000..871852cc1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_02.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_02.png new file mode 100644 index 000000000..7ab70007e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_03.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_03.png new file mode 100644 index 000000000..2474d298f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_04.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_04.png new file mode 100644 index 000000000..2a41f0f69 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_05.png new file mode 100644 index 000000000..871852cc1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_06.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_06.png new file mode 100644 index 000000000..7ab70007e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_07.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_07.png new file mode 100644 index 000000000..2474d298f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_08.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_08.png new file mode 100644 index 000000000..2a41f0f69 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_09.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_09.png new file mode 100644 index 000000000..fc9317e52 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_10.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_10.png new file mode 100644 index 000000000..ccde5899d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_11.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_11.png new file mode 100644 index 000000000..203540533 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_12.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_12.png new file mode 100644 index 000000000..01cd58010 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_13.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_13.png new file mode 100644 index 000000000..fc9317e52 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_14.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_14.png new file mode 100644 index 000000000..ccde5899d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_15.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_15.png new file mode 100644 index 000000000..203540533 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_16.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_16.png new file mode 100644 index 000000000..01cd58010 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_snowman_opponent_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_elfopponent.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_elfopponent.png new file mode 100644 index 000000000..d4863e0e7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_elfopponent.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_reindeer.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_reindeer.png new file mode 100644 index 000000000..79f6d46ea Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_reindeer.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_runner.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_runner.png new file mode 100644 index 000000000..00443180d Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_runner.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_snowman.png b/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_snowman.png new file mode 100644 index 000000000..6498612d5 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_running_starting_snowman.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_sidestep.png b/doodles/src/main/res/drawable-nodpi/snowballrun_sidestep.png new file mode 100644 index 000000000..31316baa9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_sidestep.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_05.png new file mode 100644 index 000000000..2700abdad Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_06.png b/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_06.png new file mode 100644 index 000000000..cf598a9b8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_07.png b/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_07.png new file mode 100644 index 000000000..fd98092c3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_08.png b/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_08.png new file mode 100644 index 000000000..342524c8e Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_09.png b/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_09.png new file mode 100644 index 000000000..20e140294 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_snowman_squished_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_standing_elf.png b/doodles/src/main/res/drawable-nodpi/snowballrun_standing_elf.png new file mode 100644 index 000000000..93254928c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_standing_elf.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_standing_elfopponent.png b/doodles/src/main/res/drawable-nodpi/snowballrun_standing_elfopponent.png new file mode 100644 index 000000000..d9dbe11d8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_standing_elfopponent.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_standing_reindeer.png b/doodles/src/main/res/drawable-nodpi/snowballrun_standing_reindeer.png new file mode 100644 index 000000000..f263a71e6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_standing_reindeer.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_standing_snowman.png b/doodles/src/main/res/drawable-nodpi/snowballrun_standing_snowman.png new file mode 100644 index 000000000..5ed548682 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_standing_snowman.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_01.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_01.png new file mode 100644 index 000000000..55783baca Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_02.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_02.png new file mode 100644 index 000000000..96f13b0de Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_03.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_03.png new file mode 100644 index 000000000..e7b0f987c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_04.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_04.png new file mode 100644 index 000000000..1834e92e2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_05.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_05.png new file mode 100644 index 000000000..09d7522d4 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_06.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_06.png new file mode 100644 index 000000000..c22a797cd Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_07.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_07.png new file mode 100644 index 000000000..d9f51b7cd Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_08.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_08.png new file mode 100644 index 000000000..b9974ffda Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_09.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_09.png new file mode 100644 index 000000000..4faaa17d6 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_10.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_10.png new file mode 100644 index 000000000..9ec4be9a9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_10.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_11.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_11.png new file mode 100644 index 000000000..976e957a3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_11.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_12.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_12.png new file mode 100644 index 000000000..ae1dd2ca9 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_12.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_13.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_13.png new file mode 100644 index 000000000..848820873 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_13.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_14.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_14.png new file mode 100644 index 000000000..0dc3f0737 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_14.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_15.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_15.png new file mode 100644 index 000000000..603ee7a78 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_15.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_16.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_16.png new file mode 100644 index 000000000..d7885a8b1 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_16.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_17.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_17.png new file mode 100644 index 000000000..c557c6fbf Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_17.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_18.png b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_18.png new file mode 100644 index 000000000..0803a0d4c Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrun_tutorials_18.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrunner_background.png b/doodles/src/main/res/drawable-nodpi/snowballrunner_background.png new file mode 100644 index 000000000..665ba710a Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrunner_background.png differ diff --git a/doodles/src/main/res/drawable-nodpi/snowballrunner_loadingscreen.png b/doodles/src/main/res/drawable-nodpi/snowballrunner_loadingscreen.png new file mode 100644 index 000000000..87f88c346 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/snowballrunner_loadingscreen.png differ diff --git a/doodles/src/main/res/drawable-nodpi/swimming_rings_00.png b/doodles/src/main/res/drawable-nodpi/swimming_rings_00.png new file mode 100644 index 000000000..47e106517 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/swimming_rings_00.png differ diff --git a/doodles/src/main/res/drawable-nodpi/swimming_rings_01.png b/doodles/src/main/res/drawable-nodpi/swimming_rings_01.png new file mode 100644 index 000000000..c31b96cd3 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/swimming_rings_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/swimming_rings_02.png b/doodles/src/main/res/drawable-nodpi/swimming_rings_02.png new file mode 100644 index 000000000..162976753 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/swimming_rings_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/swimming_rings_03.png b/doodles/src/main/res/drawable-nodpi/swimming_rings_03.png new file mode 100644 index 000000000..9fcff99b2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/swimming_rings_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/swimming_rings_04.png b/doodles/src/main/res/drawable-nodpi/swimming_rings_04.png new file mode 100644 index 000000000..6e1ea4051 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/swimming_rings_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/swimming_rings_05.png b/doodles/src/main/res/drawable-nodpi/swimming_rings_05.png new file mode 100644 index 000000000..e60b150da Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/swimming_rings_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/swimming_rings_06.png b/doodles/src/main/res/drawable-nodpi/swimming_rings_06.png new file mode 100644 index 000000000..3828b4856 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/swimming_rings_06.png differ diff --git a/doodles/src/main/res/drawable-nodpi/swimming_rings_07.png b/doodles/src/main/res/drawable-nodpi/swimming_rings_07.png new file mode 100644 index 000000000..1dfb33ab0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/swimming_rings_07.png differ diff --git a/doodles/src/main/res/drawable-nodpi/swimming_rings_08.png b/doodles/src/main/res/drawable-nodpi/swimming_rings_08.png new file mode 100644 index 000000000..e7e39c8c0 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/swimming_rings_08.png differ diff --git a/doodles/src/main/res/drawable-nodpi/swimming_rings_09.png b/doodles/src/main/res/drawable-nodpi/swimming_rings_09.png new file mode 100644 index 000000000..a956e4ecd Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/swimming_rings_09.png differ diff --git a/doodles/src/main/res/drawable-nodpi/tutoappear_new_00.png b/doodles/src/main/res/drawable-nodpi/tutoappear_new_00.png new file mode 100644 index 000000000..72905ab2f Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/tutoappear_new_00.png differ diff --git a/doodles/src/main/res/drawable-nodpi/tutoappear_new_01.png b/doodles/src/main/res/drawable-nodpi/tutoappear_new_01.png new file mode 100644 index 000000000..6121a0ef2 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/tutoappear_new_01.png differ diff --git a/doodles/src/main/res/drawable-nodpi/tutoappear_new_02.png b/doodles/src/main/res/drawable-nodpi/tutoappear_new_02.png new file mode 100644 index 000000000..fbd1c3849 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/tutoappear_new_02.png differ diff --git a/doodles/src/main/res/drawable-nodpi/tutoappear_new_03.png b/doodles/src/main/res/drawable-nodpi/tutoappear_new_03.png new file mode 100644 index 000000000..5510d7ce8 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/tutoappear_new_03.png differ diff --git a/doodles/src/main/res/drawable-nodpi/tutoappear_new_04.png b/doodles/src/main/res/drawable-nodpi/tutoappear_new_04.png new file mode 100644 index 000000000..184edbfb7 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/tutoappear_new_04.png differ diff --git a/doodles/src/main/res/drawable-nodpi/tutoappear_new_05.png b/doodles/src/main/res/drawable-nodpi/tutoappear_new_05.png new file mode 100644 index 000000000..bec000cfe Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/tutoappear_new_05.png differ diff --git a/doodles/src/main/res/drawable-nodpi/waterpolo_target.png b/doodles/src/main/res/drawable-nodpi/waterpolo_target.png new file mode 100644 index 000000000..99413ce53 Binary files /dev/null and b/doodles/src/main/res/drawable-nodpi/waterpolo_target.png differ diff --git a/doodles/src/main/res/drawable/dim_overlay.xml b/doodles/src/main/res/drawable/dim_overlay.xml new file mode 100644 index 000000000..5f24df407 --- /dev/null +++ b/doodles/src/main/res/drawable/dim_overlay.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/doodles/src/main/res/drawable/game_button_default.xml b/doodles/src/main/res/drawable/game_button_default.xml new file mode 100644 index 000000000..20dca3249 --- /dev/null +++ b/doodles/src/main/res/drawable/game_button_default.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/doodles/src/main/res/drawable/game_button_focused.xml b/doodles/src/main/res/drawable/game_button_focused.xml new file mode 100644 index 000000000..f4bf6cfa4 --- /dev/null +++ b/doodles/src/main/res/drawable/game_button_focused.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/doodles/src/main/res/drawable/game_button_pressed.xml b/doodles/src/main/res/drawable/game_button_pressed.xml new file mode 100644 index 000000000..d68cf964a --- /dev/null +++ b/doodles/src/main/res/drawable/game_button_pressed.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/doodles/src/main/res/drawable/google.png b/doodles/src/main/res/drawable/google.png new file mode 100644 index 000000000..daefaa4a8 Binary files /dev/null and b/doodles/src/main/res/drawable/google.png differ diff --git a/doodles/src/main/res/drawable/ic_launcher.png b/doodles/src/main/res/drawable/ic_launcher.png new file mode 100644 index 000000000..e039fd8c0 Binary files /dev/null and b/doodles/src/main/res/drawable/ic_launcher.png differ diff --git a/doodles/src/main/res/drawable/pineapple_icon_pause.png b/doodles/src/main/res/drawable/pineapple_icon_pause.png new file mode 100644 index 000000000..c7c2b6e3a Binary files /dev/null and b/doodles/src/main/res/drawable/pineapple_icon_pause.png differ diff --git a/doodles/src/main/res/drawable/swimming_dive_arrow.png b/doodles/src/main/res/drawable/swimming_dive_arrow.png new file mode 100644 index 000000000..4eb9f3ea4 Binary files /dev/null and b/doodles/src/main/res/drawable/swimming_dive_arrow.png differ diff --git a/doodles/src/main/res/layout/activity_view.xml b/doodles/src/main/res/layout/activity_view.xml new file mode 100644 index 000000000..fe3fd2683 --- /dev/null +++ b/doodles/src/main/res/layout/activity_view.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/doodles/src/main/res/layout/fact_view.xml b/doodles/src/main/res/layout/fact_view.xml new file mode 100644 index 000000000..101d8d5e4 --- /dev/null +++ b/doodles/src/main/res/layout/fact_view.xml @@ -0,0 +1,28 @@ + + + + diff --git a/doodles/src/main/res/layout/game_overlay_button.xml b/doodles/src/main/res/layout/game_overlay_button.xml new file mode 100644 index 000000000..77c526e80 --- /dev/null +++ b/doodles/src/main/res/layout/game_overlay_button.xml @@ -0,0 +1,43 @@ + + + + + + + diff --git a/doodles/src/main/res/layout/pause_view.xml b/doodles/src/main/res/layout/pause_view.xml new file mode 100644 index 000000000..3d0303c26 --- /dev/null +++ b/doodles/src/main/res/layout/pause_view.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + +