() {
-
- @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
- På
- 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
- På
- 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
- På
- 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/CONTRIBUTING.md b/CONTRIBUTING.md
index 14a4fcffa..ebbb59e53 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,35 +1,28 @@
-# How to become a contributor and submit your own code
+# How to Contribute
-## Contributor License Agreements
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
-We'd love to accept your sample apps and patches! Before we can take them, we
-have to jump a couple of legal hurdles.
+## Contributor License Agreement
-Please fill out either the individual or corporate Contributor License Agreement (CLA).
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution;
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to to see
+your current agreements on file or to sign a new one.
- * If you are an individual writing original source code and you're sure you
- own the intellectual property, then you'll need to sign an [individual CLA]
- (https://developers.google.com/open-source/cla/individual).
- * If you work for a company that wants to allow you to contribute your work,
- then you'll need to sign a [corporate CLA]
- (https://developers.google.com/open-source/cla/corporate).
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
-Follow either of the two links above to access the appropriate CLA and
-instructions for how to sign and return it. Once we receive it, we'll be able to
-accept your pull requests.
+## Code reviews
-## Contributing A Patch
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult
+[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
+information on using pull requests.
-1. Submit an issue describing your proposed change to the repo in question.
-1. The repo owner will respond to your issue promptly.
-1. If your proposed change is accepted, and you haven't already done so, sign a
- Contributor License Agreement (see details above).
-1. Fork the desired repo, develop and test your code changes.
-1. Ensure that your code adheres to the existing style in the sample to which
- you are contributing. Refer to the
- [Android Code Style Guide]
- (https://source.android.com/source/code-style.html) for the
- recommended coding standards for this organization.
-1. Ensure that your code has an appropriate set of unit tests which all pass.
-1. Submit a pull request.
+## Community Guidelines
+This project follows
+[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/).
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 5779f2605..95f8e3802 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,12 +1,9 @@
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
+and *.ogg) are licensed under the CC-BY license. All other files are
licensed under the Apache 2 license.
-CC-BY-NC License
-----------------
-
-Attribution-NonCommercial-ShareAlike 4.0 International
+Attribution 4.0 International
=======================================================================
@@ -41,7 +38,7 @@ exhaustive, and do not form part of our licenses.
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
- wiki.creativecommons.org/Considerations_for_licensors
+ wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
@@ -56,24 +53,22 @@ exhaustive, and do not form part of our licenses.
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
- respect those requests where reasonable. More_considerations
- for the public:
- wiki.creativecommons.org/Considerations_for_licensees
+ respect those requests where reasonable. More considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
-Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
-Public License
+Creative Commons Attribution 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
-Attribution-NonCommercial-ShareAlike 4.0 International Public License
-("Public License"). To the extent this Public License may be
-interpreted as a contract, You are granted the Licensed Rights in
-consideration of Your acceptance of these terms and conditions, and the
-Licensor grants You such rights in consideration of benefits the
-Licensor receives from making the Licensed Material available under
-these terms and conditions.
+Attribution 4.0 International Public License ("Public License"). To the
+extent this Public License may be interpreted as a contract, You are
+granted the Licensed Rights in consideration of Your acceptance of
+these terms and conditions, and the Licensor grants You such rights in
+consideration of benefits the Licensor receives from making the
+Licensed Material available under these terms and conditions.
Section 1 -- Definitions.
@@ -92,11 +87,7 @@ Section 1 -- Definitions.
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
- c. BY-NC-SA Compatible License means a license listed at
- creativecommons.org/compatiblelicenses, approved by Creative
- Commons as essentially the equivalent of this Public License.
-
- d. Copyright and Similar Rights means copyright and/or similar rights
+ c. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
@@ -104,41 +95,29 @@ Section 1 -- Definitions.
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
- e. Effective Technological Measures means those measures that, in the
+ d. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
- f. Exceptions and Limitations means fair use, fair dealing, and/or
+ e. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
- g. License Elements means the license attributes listed in the name
- of a Creative Commons Public License. The License Elements of this
- Public License are Attribution, NonCommercial, and ShareAlike.
-
- h. Licensed Material means the artistic or literary work, database,
+ f. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
- i. Licensed Rights means the rights granted to You subject to the
+ g. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
- j. Licensor means the individual(s) or entity(ies) granting rights
+ h. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
- k. NonCommercial means not primarily intended for or directed towards
- commercial advantage or monetary compensation. For purposes of
- this Public License, the exchange of the Licensed Material for
- other material subject to Copyright and Similar Rights by digital
- file-sharing or similar means is NonCommercial provided there is
- no payment of monetary compensation in connection with the
- exchange.
-
- l. Share means to provide material to the public by any means or
+ i. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
@@ -146,13 +125,13 @@ Section 1 -- Definitions.
public may access the material from a place and at a time
individually chosen by them.
- m. Sui Generis Database Rights means rights other than copyright
+ j. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
- n. You means the individual or entity exercising the Licensed Rights
+ k. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
@@ -166,10 +145,9 @@ Section 2 -- Scope.
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
- in part, for NonCommercial purposes only; and
+ in part; and
- b. produce, reproduce, and Share Adapted Material for
- NonCommercial purposes only.
+ b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
@@ -199,13 +177,7 @@ Section 2 -- Scope.
Licensed Rights under the terms and conditions of this
Public License.
- b. Additional offer from the Licensor -- Adapted Material.
- Every recipient of Adapted Material from You
- automatically receives an offer from the Licensor to
- exercise the Licensed Rights in the Adapted Material
- under the conditions of the Adapter's License You apply.
-
- c. No downstream restrictions. You may not offer or impose
+ b. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
@@ -237,9 +209,7 @@ Section 2 -- Scope.
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
- reserves any right to collect such royalties, including when
- the Licensed Material is used other than for NonCommercial
- purposes.
+ reserves any right to collect such royalties.
Section 3 -- License Conditions.
@@ -284,28 +254,14 @@ following conditions.
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
+
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
- b. ShareAlike.
-
- In addition to the conditions in Section 3(a), if You Share
- Adapted Material You produce, the following conditions also apply.
-
- 1. The Adapter's License You apply must be a Creative Commons
- license with the same License Elements, this version or
- later, or a BY-NC-SA Compatible License.
-
- 2. You must include the text of, or the URI or hyperlink to, the
- Adapter's License You apply. You may satisfy this condition
- in any reasonable manner based on the medium, means, and
- context in which You Share Adapted Material.
-
- 3. You may not offer or impose any additional or different terms
- or conditions on, or apply any Effective Technological
- Measures to, Adapted Material that restrict exercise of the
- rights granted under the Adapter's License You apply.
+ 4. If You Share Adapted Material You produce, the Adapter's
+ License You apply must not prevent recipients of the Adapted
+ Material from complying with this Public License.
Section 4 -- Sui Generis Database Rights.
@@ -315,14 +271,12 @@ apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
- portion of the contents of the database for NonCommercial purposes
- only;
+ portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
- Rights (but not its individual contents) is Adapted Material,
- including for purposes of Section 3(b); and
+ Rights (but not its individual contents) is Adapted Material; and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
@@ -423,13 +377,16 @@ Section 8 -- Interpretation.
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
+
=======================================================================
-Creative Commons is not a party to its public licenses.
-Notwithstanding, Creative Commons may elect to apply one of its public
-licenses to material it publishes and in those instances will be
-considered the "Licensor." Except for the limited purpose of indicating
-that material is shared under a Creative Commons public license or as
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the “Licensor.” The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
@@ -437,8 +394,8 @@ of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
-the avoidance of doubt, this paragraph does not form part of the public
-licenses.
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
Creative Commons may be contacted at creativecommons.org.
diff --git a/README.md b/README.md
index c7a7108c0..ce9357c7b 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,29 @@
-Google Santa Tracker for Android
-================================
+Status: Archived
+================
+
+This repository has been archived and is no longer maintained.
+
+
+## Google Santa Tracker for Android 🎅🤶
## About
-[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.
-
+[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.
+
+
## Features
-* A beautiful materially designed village
-* 6 exciting games
-* 2 interactive Android Wear watchfaces (with sound!)
+* A beautiful designed village
+* Exciting games like Penguin Swim and Rocket Sleigh
+* Use of Dynamic Feature Modules (each game is a separate module, fetched dynamically on first run)
+* Interactive Android Wear watchfaces (with sound!)
* Videos, animations and more.
## Building the app
@@ -23,10 +34,9 @@ console, follow these steps:
* Create a new project
* Add Firebase to your Android app
- * 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
+ * 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
Now you should be able to plug your phone in (or fire up an emulator) and run:
@@ -34,24 +44,22 @@ 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
-compile the project. If you're unsure about this, use Android Studio and tick the appropriate boxes
-in the SDK Manager.
+Note: You'll need Android SDK version 28. 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
-licensed under the Apache 2 license. See the LICENSE file for details.
+All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav, *.ogg, *.m4a, *.webp) are
+licensed under the CC-BY license. All other files are licensed under the Apache 2 license.
+See the LICENSE file for details.
+ Copyright 2019 Google LLC
- Copyright 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
-
+
+ https://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..8bc648ff7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,66 +1,177 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
+ext {
+ versionName = "5.3.1"
+ versionCode = 53010005
+
+ minSdkVersion = 21
+ compileSdkVersion = 28
+ targetSdkVersion = 27
+
+ tools = '28.0.3'
+
+ supportAnnotations = "androidx.annotation:annotation:1.0.1"
+ appCompat = "androidx.appcompat:appcompat:1.0.2"
+ design = "com.google.android.material:material:1.0.0"
+ mediaRouter = "androidx.mediarouter:mediarouter:1.0.0"
+ wear = "androidx.wear:wear:1.0.0"
+ cardView = "androidx.cardview:cardview:1.0.0"
+ recyclerView = "androidx.recyclerview:recyclerview:1.0.0"
+ leanback = "androidx.leanback:leanback:1.0.0"
+ percent = "androidx.percentlayout:percentlayout:1.0.0"
+ customTabs = "androidx.browser:browser:1.0.0"
+ constraintLayout = 'androidx.constraintlayout:constraintlayout:1.1.3'
+ coreKtx = 'androidx.core:core-ktx:1.0.1'
+
+ supportWearable = "com.google.android.support:wearable:2.3.0"
+ providedWear = "com.google.android.wearable:wearable:2.3.0"
+
+ archLifecycle = '2.0.0'
+ archLifecycleRuntime = "androidx.lifecycle:lifecycle-runtime:$archLifecycle"
+ archLifecycleExtentions = "androidx.lifecycle:lifecycle-extensions:$archLifecycle"
+ archLifecycleCompiler = "androidx.lifecycle:lifecycle-compiler:$archLifecycle"
+
+ archRoom = "2.0.0"
+ archRoomRuntime = "androidx.room:room-runtime:$archRoom"
+ archRoomCompiler = "androidx.room:room-compiler:$archRoom"
+ archRoomTesting = "androidx.room:room-testing:$archRoom"
+
+ // https://developers.google.com/android/guides/releases
+ playServicesAnalytics = 'com.google.android.gms:play-services-analytics:16.0.4'
+ playServicesBase = 'com.google.android.gms:play-services-base:16.0.1'
+ playServicesCastFramework = 'com.google.android.gms:play-services-cast-framework:16.0.3'
+ playServicesGames = 'com.google.android.gms:play-services-games:16.0.0'
+ playServicesMaps = 'com.google.android.gms:play-services-maps:16.0.0'
+ playServicesNearby = 'com.google.android.gms:play-services-nearby:16.0.0'
+ playServicesWearable = 'com.google.android.gms:play-services-wearable:16.0.1'
+ playServicesPlaces = 'com.google.android.gms:play-services-places:16.0.0'
+ playServicesLocation = 'com.google.android.gms:play-services-location:16.0.0'
+ playServicesOssLicenses = 'com.google.android.gms:play-services-oss-licenses:16.0.1'
+
+ // https://firebase.google.com/support/release-notes/android
+ firebaseCore = 'com.google.firebase:firebase-core:16.0.4'
+ firebaseAppindexing = 'com.google.firebase:firebase-appindexing:16.0.1'
+ firebaseAppinvite = 'com.google.firebase:firebase-invites:16.0.4'
+ firebaseConfig = 'com.google.firebase:firebase-config:16.0.1'
+ firebaseCrash = 'com.google.firebase:firebase-crash:16.2.1'
+ firebaseMessaging = 'com.google.firebase:firebase-messaging:17.3.3'
+ firebaseStorage = 'com.google.firebase:firebase-storage:16.0.1'
+
+ dagger = '2.17'
+ daggerCore = "com.google.dagger:dagger:$dagger"
+ daggerAndroid = "com.google.dagger:dagger-android:$dagger"
+ daggerAndroidSupport = "com.google.dagger:dagger-android-support:$dagger"
+ daggerAndroidProcessor = "com.google.dagger:dagger-android-processor:$dagger"
+ daggerCompiler = "com.google.dagger:dagger-compiler:$dagger"
+
+ gson = 'com.google.code.gson:gson:2.8.5'
+
+ okhttp = 'com.squareup.okhttp3:okhttp:3.12.0'
+
+ androidMapsUtils = 'com.google.maps.android:android-maps-utils:0.5'
+
+ kotlinRuntime = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin"
+
+ leakCanary = 'com.squareup.leakcanary:leakcanary-android:1.6.1'
+ leakCanaryNoOp = 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
+
+ junit = 'junit:junit:4.12'
+
+ espresso = '3.1.1'
+ espressoCore = "androidx.test.espresso:espresso-core:$espresso"
+ espressoContrib = "androidx.test.espresso:espresso-contrib:$espresso"
+ espressoIntents = "androidx.test.espresso:espresso-intents:$espresso"
+ espressoAccessibility = "androidx.test.espresso:espresso-accessibility:$espresso"
+ esspressoWeb = "androidx.test.espresso:espresso-web:$espresso"
+ espressoConcurrent = "androidx.test.espresso.idling:idling-concurrent:$espresso"
+ espressoIdlingResource = "androidx.test.espresso:espresso-idling-resource:$espresso"
+
+ test = '1.1.1'
+ testingSupportRunner = "androidx.test:runner:$test"
+ testingSupportRules = "androidx.test:rules:$test"
+
+ seismic = 'com.squareup:seismic:1.0.2'
+
+ glide = 'com.github.bumptech.glide:glide:4.8.0'
+
+ truetime = 'com.github.instacart.truetime-android:library:3.4'
+
+ flexbox = 'com.google.android:flexbox:1.0.0'
+
+ easypermissions = 'pub.devrel:easypermissions:1.0.1'
+
+ mockitoAndroid = 'org.mockito:mockito-android:2.22.0'
+ mockitoCore = 'org.mockito:mockito-core:2.22.0'
+
+ robolectric = 'org.robolectric:robolectric:3.8'
+
+ playCore = 'com.google.android.play:core:1.3.6'
+
+ mergeAdapter = 'me.mvdw.recyclerviewmergeadapter:recyclerviewmergeadapter:2.1.0'
+}
+
buildscript {
- ext.androidHome = project.hasProperty('androidHome') ? androidHome : '../../../..'
+ ext.kotlin = '1.3.11'
+ ext.spotless = '3.15.0'
+ ext.ktlint = '0.28.0'
+ ext.googlejavaformat = '1.6'
repositories {
- // Required for offline build.
- // Links to the internal repositories for standard tools.
- maven { url "$androidHome/prebuilts/gradle-plugin" }
- maven { url "$androidHome/prebuilts/tools/common/m2/repository" }
-
- // When adding new dependencies, first enable jcenter(), then use the
- // scripts/copyOfflineDep.sh to copy the dependency into the offline-lib-repository folder
- maven { url "third_party/offline-lib-repository" }
+ google()
jcenter()
+ maven { url "https://plugins.gradle.org/m2/" }
}
+
dependencies {
- classpath 'com.android.tools.build:gradle:2.1.2'
- classpath 'com.google.gms:google-services:3.0.0'
+ classpath 'com.android.tools.build:gradle:3.3.0'
+ classpath 'com.google.gms:google-services:4.2.0'
+ classpath 'com.google.android.gms:oss-licenses-plugin:0.9.4'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin"
+ classpath "com.diffplug.spotless:spotless-plugin-gradle:$spotless"
}
}
subprojects {
- repositories {
- maven {
- url "../third_party/offline-lib-repository"
+ apply plugin: "com.diffplug.gradle.spotless"
+ spotless {
+ java {
+ target '**/*.java'
+ googleJavaFormat(rootProject.ext.googlejavaformat).aosp()
+ // This is a workaround to suppress the following:
+ // You have a misbehaving rule which can't make up its mind.
+ // This means that spotlessCheck will fail even after spotlessApply has run.
+ //
+ // This is a bug in a formatting rule, not Spotless itself, but Spotless can
+ // work around this bug and generate helpful bug reports for the broken rule
+ // if you add 'paddedCell()' to your build.gradle as such:
+ // See https://github.com/diffplug/spotless/blob/master/PADDEDCELL.md for more details
+ paddedCell()
+ }
+ kotlin {
+ target '**/*.kt'
+ ktlint(rootProject.ext.ktlint)
}
}
-}
-ext {
- tools = '23.0.1'
- support = '23.4.0'
- supportV4 = "com.android.support:support-v4:$support"
- supportAnnotations = "com.android.support:support-annotations:$support"
- appCompat = "com.android.support:appcompat-v7:$support"
- design = "com.android.support:design:$support"
- mediaRouter = "com.android.support:mediarouter-v7:$support"
- supportWearable = "com.google.android.support:wearable:1.4.0"
-
- cardView = "com.android.support:cardview-v7:$support"
- recyclerView = "com.android.support:recyclerview-v7:$support"
- leanback = "com.android.support:leanback-v17:$support"
- multidex = 'com.android.support:multidex:1.0.0'
-
- play = '9.2.1'
-
- 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"
- 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"
-
- 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"
-
- 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"
+ repositories {
+ google()
+ mavenCentral()
+ jcenter()
+ maven { url "https://jitpack.io" } // Needed for truetime
+ }
}
+
diff --git a/cityquiz/build.gradle b/cityquiz/build.gradle
new file mode 100644
index 000000000..e67cddb33
--- /dev/null
+++ b/cityquiz/build.gradle
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
+apply plugin: 'com.android.dynamic-feature'
+apply plugin: 'kotlin-android'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.tools
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
+ }
+}
+
+dependencies {
+ implementation project(':santa-tracker')
+}
diff --git a/cityquiz/src/main/AndroidManifest.xml b/cityquiz/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..c348d87d8
--- /dev/null
+++ b/cityquiz/src/main/AndroidManifest.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/City.kt b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/City.kt
new file mode 100644
index 000000000..40cdc6f1e
--- /dev/null
+++ b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/City.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.cityquiz
+
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.LatLngBounds
+
+class City(
+ lat: Double,
+ lng: Double,
+ val imageName: String,
+ val imageAuthor: String,
+ var name: String
+) {
+ val correctLocation: LatLng = LatLng(lat, lng)
+ var incorrectLocationOne: LatLng = correctLocation
+ var incorrectLocationTwo: LatLng = correctLocation
+
+ /**
+ * Provide bounds so map ensure all markers representing the city locations are visible.
+ *
+ * @return Bounds given city's locations.
+ */
+ val bounds: LatLngBounds
+ get() = LatLngBounds.Builder()
+ .include(correctLocation)
+ .include(incorrectLocationOne)
+ .include(incorrectLocationTwo)
+ .build()
+}
diff --git a/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityLocationComparator.kt b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityLocationComparator.kt
new file mode 100644
index 000000000..cebb3e6a0
--- /dev/null
+++ b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityLocationComparator.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.cityquiz
+
+import com.google.maps.android.SphericalUtil
+import java.util.Comparator
+
+/** Compare the distance between two Cities and the City of this comparator. */
+class CityLocationComparator(private val city: City) : Comparator {
+ override fun compare(c1: City, c2: City): Int {
+ val dist1 = SphericalUtil.computeDistanceBetween(
+ city.correctLocation, c1.correctLocation)
+ val dist2 = SphericalUtil.computeDistanceBetween(
+ city.correctLocation, c2.correctLocation)
+ return dist1.compareTo(dist2)
+ }
+}
diff --git a/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizActivity.kt b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizActivity.kt
new file mode 100644
index 000000000..121fffa9f
--- /dev/null
+++ b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizActivity.kt
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.cityquiz
+
+import android.graphics.drawable.Drawable
+import android.net.Uri
+import android.os.Bundle
+import android.os.Handler
+import android.view.View
+import android.widget.ImageView
+import android.widget.ProgressBar
+import android.widget.TextView
+import androidx.core.os.postDelayed
+import androidx.core.view.doOnLayout
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.DataSource
+import com.bumptech.glide.load.engine.GlideException
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
+import com.bumptech.glide.request.RequestListener
+import com.bumptech.glide.request.target.Target
+import com.google.android.apps.playgames.common.PlayGamesActivity
+import com.google.android.apps.santatracker.games.EndOfGameView
+import com.google.android.apps.santatracker.util.MapHelper
+import com.google.android.apps.santatracker.util.MeasurementManager
+import com.google.android.apps.santatracker.util.SantaLog
+import com.google.android.apps.santatracker.util.VectorUtil
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.MapStyleOptions
+import com.google.android.gms.maps.model.Marker
+import com.google.android.gms.maps.model.MarkerOptions
+import com.google.android.gms.tasks.OnCompleteListener
+import com.google.android.gms.tasks.Task
+import com.google.firebase.analytics.FirebaseAnalytics
+import com.google.firebase.remoteconfig.FirebaseRemoteConfig
+import com.google.firebase.storage.FirebaseStorage
+import java.lang.ref.WeakReference
+
+/** Main container for the City Quiz game. */
+class CityQuizActivity : PlayGamesActivity(), OnMapReadyCallback, GoogleMap.OnMarkerClickListener {
+
+ private lateinit var cityQuizGame: CityQuizGame
+
+ private lateinit var cityImageView: ImageView
+ private lateinit var cityImageProgressBar: ProgressBar
+ private lateinit var cloudOffImageView: ImageView
+ private lateinit var cityImageAuthorTextView: TextView
+ private lateinit var mapScrim: View
+ private lateinit var roundCountTextView: TextView
+ private lateinit var pointsTextView: TextView
+
+ private lateinit var supportMapFragment: SupportMapFragment
+ private lateinit var googleMap: GoogleMap
+
+ private var mapLaidOut: Boolean = false
+ private var mapReady: Boolean = false
+ private var initialRoundLoaded: Boolean = false
+
+ private val cityImageGlideListener = CityImageGlideListener(this)
+ private val handler = Handler()
+
+ private lateinit var analytics: FirebaseAnalytics
+
+ override fun getLayoutId() = R.layout.activity_city_quiz
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val roundCount = FirebaseRemoteConfig.getInstance().getLong(CITY_QUIZ_ROUND_COUNT_CONFIG_KEY)
+ cityQuizGame = CityQuizGame(this, roundCount.toInt())
+
+ // [ANALYTICS]
+ analytics = FirebaseAnalytics.getInstance(this)
+ MeasurementManager.recordScreenView(analytics,
+ getString(com.google.android.apps.santatracker.common.R.string.analytics_screen_city_quiz))
+
+ cityImageView = findViewById(R.id.cityQuizImageView)
+ cityImageProgressBar = findViewById(R.id.cityImageProgressBar)
+ cloudOffImageView = findViewById(R.id.cloudOffImageView)
+ cityImageAuthorTextView = findViewById(R.id.cityImageAuthorTextView)
+ mapScrim = findViewById(R.id.map_scrim)
+ roundCountTextView = findViewById(R.id.roundCountTextView)
+ pointsTextView = findViewById(R.id.pointsTextView)
+
+ // Clicking the "offline" image will attempt a reload
+ cloudOffImageView.setOnClickListener {
+ cityQuizGame.currentRound?.city?.let { city ->
+ loadCityImage(city.imageName, city.imageAuthor)
+ }
+ }
+
+ // Map scrim prevents clicking on map
+ mapScrim.setOnClickListener {
+ // No-op, eat the click
+ }
+
+ supportMapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
+
+ supportMapFragment.view?.doOnLayout {
+ mapLaidOut = true
+ loadInitialRound()
+ }
+ supportMapFragment.getMapAsync(this)
+ }
+
+ override fun getGameId(): String {
+ return getString(com.google.android.apps.playgames.R.string.city_quiz_game_id)
+ }
+
+ override fun getGameTitle(): String {
+ return getString(com.google.android.apps.santatracker.common.R.string.cityquiz)
+ }
+
+ override fun onMapReady(googleMap: GoogleMap) {
+ mapReady = true
+ this.googleMap = googleMap
+
+ googleMap.setMapStyle(MapStyleOptions.loadRawResourceStyle(this,
+ com.google.android.apps.santatracker.common.R.raw.map_style))
+ googleMap.setOnMarkerClickListener(this)
+
+ loadInitialRound()
+ }
+
+ /**
+ * Load the initial round only if the map is ready and laid out and has not been already loaded.
+ */
+ private fun loadInitialRound() {
+ if (mapLaidOut && mapReady && !initialRoundLoaded) {
+ loadRound()
+ initialRoundLoaded = true
+ }
+ }
+
+ /** Load the current round of the game for user interaction. */
+ private fun loadRound() {
+ if (isFinishing || supportMapFragment.view == null) {
+ // The user exit the game between rounds.
+ return
+ }
+
+ updateScore()
+
+ // Get next city in game.
+ val city = cityQuizGame.currentRound?.city ?: return
+
+ // Load city image
+ loadCityImage(city.imageName, city.imageAuthor)
+
+ // Set up city markers
+ googleMap.clear()
+
+ if (BuildConfig.DEBUG) {
+ SantaLog.d(TAG, "Moving to ${city.name}")
+ }
+ googleMap.animateCamera(
+ CameraUpdateFactory.newLatLngBounds(
+ city.bounds, MapHelper.getMapPadding(supportMapFragment)))
+
+ // Add markers and set appropriate tags.
+ val locationMarker = googleMap.addMarker(
+ MarkerOptions()
+ .position(city.correctLocation)
+ .icon(VectorUtil.vectorToBitmap(this, R.drawable.ic_pin_blue)))
+ locationMarker.tag = CORRECT_MARKER
+
+ val firsIncorrectLocationMarker = googleMap.addMarker(
+ MarkerOptions()
+ .position(city.incorrectLocationOne)
+ .icon(VectorUtil.vectorToBitmap(this, R.drawable.ic_pin_blue)))
+ firsIncorrectLocationMarker.tag = FIRST_FAKE_MARKER
+
+ val secondIncorrectLocationMarker = googleMap.addMarker(
+ MarkerOptions()
+ .position(city.incorrectLocationTwo)
+ .icon(VectorUtil.vectorToBitmap(this, R.drawable.ic_pin_blue)))
+ secondIncorrectLocationMarker.tag = SECOND_FAKE_MARKER
+ }
+
+ /**
+ * Load the image matching the given image name into the city ImageView.
+ *
+ * @param imageName Name used to retrieve the image from Firebase Storage.
+ * @param imageAuthor Name used to give attribution for the image.
+ */
+ private fun loadCityImage(imageName: String, imageAuthor: String) {
+ if (isFinishing) {
+ return
+ }
+ // Clear current image
+ Glide.with(this)
+ .load(com.google.android.apps.playgames.R.color.cityQuizPrimaryGreenDark)
+ .transition(DrawableTransitionOptions.withCrossFade())
+ .into(cityImageView)
+
+ cityImageProgressBar.visibility = View.VISIBLE
+ showImageAuthor(false)
+ showOnlineUI()
+
+ // Load new image
+ val task = FirebaseStorage.getInstance().reference.child(imageName).downloadUrl
+ task.addOnCompleteListener(this, LoadCityImageTaskCompleteListener(this, imageAuthor))
+
+ // After timeout check if image URL has been retrieved, if not update UI.
+ handler.postDelayed(IMAGE_LOAD_TIMEOUT_MILLIS) {
+ if (!task.isComplete) {
+ // Firebase was did not complete image URL retrieval.
+ cityImageProgressBar.visibility = View.GONE
+ showOfflineUI()
+ }
+ }
+ }
+
+ private class LoadCityImageTaskCompleteListener(
+ activity: CityQuizActivity,
+ private val imageAuthor: String
+ ) : OnCompleteListener {
+ private val activityRef = WeakReference(activity)
+
+ override fun onComplete(task: Task) {
+ val activity = activityRef.get()
+ if (activity == null || activity.isFinishing) {
+ return
+ }
+ activity.cityImageProgressBar.visibility = View.GONE
+
+ if (task.isSuccessful) {
+ val uri = task.result
+ if (BuildConfig.DEBUG) {
+ SantaLog.d(TAG, "Image uri: $uri")
+ }
+
+ Glide.with(activity)
+ .load(uri)
+ .transition(DrawableTransitionOptions.withCrossFade())
+ .listener(activity.cityImageGlideListener)
+ .into(activity.cityImageView)
+
+ activity.cityImageAuthorTextView.text = activity.resources.getString(R.string.photo_by, imageAuthor)
+ activity.showImageAuthor(true)
+ } else {
+ if (BuildConfig.DEBUG) {
+ SantaLog.e(TAG, "Unable to get image URI from Firebase Storage", task.exception)
+ }
+ activity.showOfflineUI()
+ }
+ }
+ }
+
+ private fun showOfflineUI() {
+ cloudOffImageView.visibility = View.VISIBLE
+ mapScrim.visibility = View.VISIBLE
+ }
+
+ private fun showOnlineUI() {
+ cloudOffImageView.visibility = View.GONE
+ mapScrim.visibility = View.GONE
+ }
+
+ private fun updateScore() {
+ // Update game information, round count and score.
+ roundCountTextView.text = getString(
+ R.string.round_count_fmt,
+ cityQuizGame.currentRoundCount + 1,
+ cityQuizGame.totalRoundCount)
+ pointsTextView.text = getString(R.string.game_score_fmt, cityQuizGame.calculateScore())
+ }
+
+ private fun showImageAuthor(visible: Boolean) {
+ if (visible) {
+ cityImageAuthorTextView.visibility = TextView.VISIBLE
+ } else {
+ cityImageAuthorTextView.visibility = TextView.INVISIBLE
+ }
+ }
+
+ override fun onMarkerClick(marker: Marker): Boolean {
+ // Check if the round is already solved, if so ignore the marker click.
+ if (cityQuizGame.isFinished || cityQuizGame.currentRound?.isSolved == true) {
+ return true
+ }
+
+ val currentRound = cityQuizGame.currentRound ?: return false
+
+ // Identify which marker was tapped and update the round status.
+ val tag = marker.tag as Int
+ currentRound.updateLocationStatus(tag, true)
+
+ // Check if user tapped on the correct marker and if move to the next round.
+ if (tag == 0) {
+ marker.setIcon(VectorUtil.vectorToBitmap(this, R.drawable.ic_pin_green))
+ updateScore()
+
+ // [ANALYTICS]
+ val numIncorrectAttempts = 5 - currentRound.calculateRoundScore()
+ MeasurementManager.recordCorrectCitySelected(
+ analytics,
+ currentRound.city.imageName,
+ numIncorrectAttempts)
+
+ googleMap.animateCamera(
+ CameraUpdateFactory.newLatLng(currentRound.city.correctLocation),
+ object : GoogleMap.CancelableCallback {
+ override fun onFinish() {
+ showCityInfo(marker)
+ }
+
+ override fun onCancel() {
+ showCityInfo(marker)
+ }
+ })
+
+ // Wait a while before moving to next round or end of game.
+ handler.postDelayed(NEXT_ROUND_DELAY) {
+ cityQuizGame.moveToNextRound()
+ // Check if the last round has completed.
+ if (!cityQuizGame.isFinished) {
+ loadRound()
+ } else {
+ // or exit. For now I will clear the markers.
+ goToGameSummary()
+ pointsTextView.text = getString(
+ R.string.game_score_fmt,
+ cityQuizGame.calculateScore())
+ }
+ }
+ } else {
+ // [ANALYTICS]
+ cityQuizGame.currentRound?.let { round ->
+ MeasurementManager.recordIncorrectCitySelected(analytics, round.city.imageName)
+ }
+
+ marker.setIcon(VectorUtil.vectorToBitmap(this, R.drawable.ic_pin_red))
+ }
+
+ return true
+ }
+
+ private fun showCityInfo(marker: Marker) {
+ marker.title = cityQuizGame.currentRound?.city?.name
+ marker.showInfoWindow()
+ }
+
+ private fun goToGameSummary() {
+ // Show the end-game view
+ val gameView = findViewById(R.id.view_end_game) as EndOfGameView
+ gameView.initialize(cityQuizGame.calculateScore(),
+ {
+ // Restart this activity
+ recreate()
+ },
+ {
+ // Back to the village
+ finish()
+ })
+
+ // Show end game view over everything
+ gameView.visibility = View.VISIBLE
+ gameView.z = 1000f
+ }
+
+ // Listener to handle Glide action completion.
+ private class CityImageGlideListener(activity: CityQuizActivity) : RequestListener {
+ private val weakActivity = WeakReference(activity)
+
+ override fun onLoadFailed(
+ e: GlideException?,
+ model: Any?,
+ target: Target?,
+ isFirstResource: Boolean
+ ): Boolean {
+ // Glide failed to load image.
+ if (weakActivity.get() != null) {
+ SantaLog.e(TAG, "Glide unable to load city image.")
+ weakActivity.get()?.showOfflineUI()
+ }
+ return false
+ }
+
+ override fun onResourceReady(
+ resource: Drawable?,
+ model: Any?,
+ target: Target?,
+ dataSource: DataSource?,
+ isFirstResource: Boolean
+ ): Boolean {
+ if (weakActivity.get() != null) {
+ // Glide loaded image, hide "cloud off" ImageView and show author TextView.
+ weakActivity.get()?.showOnlineUI()
+ weakActivity.get()?.showImageAuthor(true)
+ }
+ return false
+ }
+ }
+
+ companion object {
+ private const val TAG = "CityQuizActivity"
+ private const val NEXT_ROUND_DELAY = 3500L
+ private const val CORRECT_MARKER = 0
+ private const val FIRST_FAKE_MARKER = 1
+ private const val SECOND_FAKE_MARKER = 2
+ private const val IMAGE_LOAD_TIMEOUT_MILLIS = 5000L // 5 seconds
+ private const val CITY_QUIZ_ROUND_COUNT_CONFIG_KEY = "CityQuizRoundCount"
+ }
+}
diff --git a/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizGame.kt b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizGame.kt
new file mode 100644
index 000000000..b2fce68de
--- /dev/null
+++ b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizGame.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.cityquiz
+
+import android.content.Context
+
+/** Represents a City Quiz Game. */
+class CityQuizGame(context: Context, roundCount: Int = DEFAULT_ROUND_COUNT) {
+ private val cityQuizRounds = CityQuizUtil.getCities(context, roundCount).map(::CityQuizRound)
+
+ var currentRoundCount: Int = 0
+ private set
+
+ /**
+ * Get the current round of the game. If the game is over null is returned.
+ *
+ * @return Current round or null if game is over.
+ */
+ val currentRound: CityQuizRound?
+ get() = cityQuizRounds.getOrNull(currentRoundCount)
+
+ val totalRoundCount: Int
+ get() = cityQuizRounds.size
+
+ val isFinished: Boolean
+ get() = currentRoundCount >= cityQuizRounds.size
+
+ fun moveToNextRound() {
+ currentRoundCount++
+ }
+
+ /**
+ * Calculates the sum of all solved rounds of the game.
+ *
+ * @return The current score of the game.
+ */
+ fun calculateScore() = cityQuizRounds.sumBy(CityQuizRound::calculateRoundScore)
+
+ companion object {
+ private const val DEFAULT_ROUND_COUNT = 5
+ }
+}
diff --git a/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizRound.kt b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizRound.kt
new file mode 100644
index 000000000..31ac24aa1
--- /dev/null
+++ b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizRound.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.cityquiz
+
+/** Represents a round in a City Quiz Game. */
+class CityQuizRound(val city: City) {
+
+ // Location status indicates whether each location has been touched.
+ // position 0 = location, 1 = incorrectLocationOne, 2 = incorrectLocationTwo
+ private val locationStatus: BooleanArray = BooleanArray(3)
+
+ val isSolved: Boolean
+ get() = locationStatus[0]
+
+ fun updateLocationStatus(pos: Int, value: Boolean) {
+ locationStatus[pos] = value
+ }
+
+ /**
+ * Calculates the score of this round. Only solved rounds are worth points. Correct guess is
+ * worth 5 points, incorrect guesses are worth -1 point.
+ *
+ * @return The points gained in this round. 0 if round is not yet solved.
+ */
+ fun calculateRoundScore(): Int {
+ var score = 0
+ // 5 points for getting the correct city
+ if (locationStatus[0]) {
+ score = 5
+ if (locationStatus[1]) {
+ score--
+ }
+ if (locationStatus[2]) {
+ score--
+ }
+ }
+ return score
+ }
+}
diff --git a/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizUtil.kt b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizUtil.kt
new file mode 100644
index 000000000..618b049db
--- /dev/null
+++ b/cityquiz/src/main/java/com/google/android/apps/santatracker/cityquiz/CityQuizUtil.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.cityquiz
+
+import android.content.Context
+import com.google.android.apps.santatracker.util.SantaLog
+import org.json.JSONArray
+import org.json.JSONException
+import java.util.ArrayList
+
+/** Utility class to assist with loading city data into City Quiz Games. */
+object CityQuizUtil {
+ private const val TAG = "CityQuizUtil"
+
+ /**
+ * Retrieve a random list of cities.
+ *
+ * @param amountOfCities Max number of cities to retrieve.
+ * @return Random list of cities. If amountOfCities is more than the amount of cities available, all cities
+ * are returned.
+ */
+ fun getCities(context: Context, amountOfCities: Int): List {
+ val allCities = getCities(context)
+ allCities.shuffle()
+ // Only return the cities that will be used in the game.
+ return allCities.subList(0, amountOfCities.coerceAtMost(allCities.size))
+ }
+
+ private fun getCities(context: Context): MutableList {
+ val cities = ArrayList()
+ val jCities = getCitiesFromFile(context)
+
+ for (i in 0 until jCities.length()) {
+ try {
+ val jCity = jCities.getJSONObject(i)
+ val lat = jCity.getDouble("lat")
+ val lng = jCity.getDouble("lng")
+ val cityResourceName = jCity.getString("name")
+ val cityNameResourceId = context.resources
+ .getIdentifier(cityResourceName, "string", context.packageName)
+
+ // Check if city name string resource is found.
+ val cityName = if (cityNameResourceId != 0) {
+ // Use string resource for city name.
+ context.resources.getString(cityNameResourceId)
+ } else {
+ // Use default English city name.
+ jCity.getString("default_name")
+ }
+
+ val imageUrl = jCity.getString("image_name")
+ val imageAuthor = jCity.getString("image_author")
+ val city = City(lat, lng, imageUrl, imageAuthor, cityName)
+ cities.add(city)
+ } catch (e: JSONException) {
+ SantaLog.e(TAG, "Unable to get city from json, $e")
+ }
+ }
+
+ // Check if there are enough cities to set fake ones.
+ if (cities.size > 3) {
+ // Set fake locations for each city.
+ val tempCities = ArrayList(cities)
+
+ for (city in cities) {
+ // Sort tempCities in order of closest to the current city.
+ tempCities.sortWith(CityLocationComparator(city))
+
+ // Get the closest three cities, excluding the current city.
+ val closestCities = tempCities.subList(1, 4)
+ closestCities.shuffle()
+
+ // Choose the first two of the three cities from the closestCities list.
+ city.incorrectLocationOne = closestCities[0].correctLocation
+ city.incorrectLocationTwo = closestCities[1].correctLocation
+ }
+ }
+
+ return cities
+ }
+
+ private fun getCitiesFromFile(context: Context) = try {
+ val inputStream = context.resources.openRawResource(R.raw.city_quiz_cities)
+ inputStream.bufferedReader().use { r ->
+ JSONArray(r.readText())
+ }
+ } catch (e: Exception) {
+ SantaLog.e(TAG, "Unable to parse city quiz json, $e")
+ JSONArray()
+ }
+}
diff --git a/cityquiz/src/main/res/drawable-hdpi/ic_pin_blue.webp b/cityquiz/src/main/res/drawable-hdpi/ic_pin_blue.webp
new file mode 100644
index 000000000..ddb925b46
Binary files /dev/null and b/cityquiz/src/main/res/drawable-hdpi/ic_pin_blue.webp differ
diff --git a/cityquiz/src/main/res/drawable-hdpi/ic_pin_green.webp b/cityquiz/src/main/res/drawable-hdpi/ic_pin_green.webp
new file mode 100644
index 000000000..90a6911de
Binary files /dev/null and b/cityquiz/src/main/res/drawable-hdpi/ic_pin_green.webp differ
diff --git a/cityquiz/src/main/res/drawable-hdpi/ic_pin_red.webp b/cityquiz/src/main/res/drawable-hdpi/ic_pin_red.webp
new file mode 100644
index 000000000..25ec01aab
Binary files /dev/null and b/cityquiz/src/main/res/drawable-hdpi/ic_pin_red.webp differ
diff --git a/cityquiz/src/main/res/drawable-hdpi/ornament_general_full.webp b/cityquiz/src/main/res/drawable-hdpi/ornament_general_full.webp
new file mode 100644
index 000000000..dc067c66c
Binary files /dev/null and b/cityquiz/src/main/res/drawable-hdpi/ornament_general_full.webp differ
diff --git a/cityquiz/src/main/res/drawable-mdpi/ic_pin_blue.webp b/cityquiz/src/main/res/drawable-mdpi/ic_pin_blue.webp
new file mode 100644
index 000000000..e65cb4da9
Binary files /dev/null and b/cityquiz/src/main/res/drawable-mdpi/ic_pin_blue.webp differ
diff --git a/cityquiz/src/main/res/drawable-mdpi/ic_pin_green.webp b/cityquiz/src/main/res/drawable-mdpi/ic_pin_green.webp
new file mode 100644
index 000000000..8f4c88381
Binary files /dev/null and b/cityquiz/src/main/res/drawable-mdpi/ic_pin_green.webp differ
diff --git a/cityquiz/src/main/res/drawable-mdpi/ic_pin_red.webp b/cityquiz/src/main/res/drawable-mdpi/ic_pin_red.webp
new file mode 100644
index 000000000..b8f54fec5
Binary files /dev/null and b/cityquiz/src/main/res/drawable-mdpi/ic_pin_red.webp differ
diff --git a/cityquiz/src/main/res/drawable-mdpi/ornament_general_full.webp b/cityquiz/src/main/res/drawable-mdpi/ornament_general_full.webp
new file mode 100644
index 000000000..8a97344e1
Binary files /dev/null and b/cityquiz/src/main/res/drawable-mdpi/ornament_general_full.webp differ
diff --git a/cityquiz/src/main/res/drawable-xhdpi/ic_pin_blue.webp b/cityquiz/src/main/res/drawable-xhdpi/ic_pin_blue.webp
new file mode 100644
index 000000000..5c7b533f9
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xhdpi/ic_pin_blue.webp differ
diff --git a/cityquiz/src/main/res/drawable-xhdpi/ic_pin_green.webp b/cityquiz/src/main/res/drawable-xhdpi/ic_pin_green.webp
new file mode 100644
index 000000000..dd5939c5c
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xhdpi/ic_pin_green.webp differ
diff --git a/cityquiz/src/main/res/drawable-xhdpi/ic_pin_red.webp b/cityquiz/src/main/res/drawable-xhdpi/ic_pin_red.webp
new file mode 100644
index 000000000..3197350ee
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xhdpi/ic_pin_red.webp differ
diff --git a/cityquiz/src/main/res/drawable-xhdpi/ornament_general_full.webp b/cityquiz/src/main/res/drawable-xhdpi/ornament_general_full.webp
new file mode 100644
index 000000000..6c1c4204f
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xhdpi/ornament_general_full.webp differ
diff --git a/cityquiz/src/main/res/drawable-xxhdpi/ic_pin_blue.webp b/cityquiz/src/main/res/drawable-xxhdpi/ic_pin_blue.webp
new file mode 100644
index 000000000..307bca1ee
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xxhdpi/ic_pin_blue.webp differ
diff --git a/cityquiz/src/main/res/drawable-xxhdpi/ic_pin_green.webp b/cityquiz/src/main/res/drawable-xxhdpi/ic_pin_green.webp
new file mode 100644
index 000000000..f4082682a
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xxhdpi/ic_pin_green.webp differ
diff --git a/cityquiz/src/main/res/drawable-xxhdpi/ic_pin_red.webp b/cityquiz/src/main/res/drawable-xxhdpi/ic_pin_red.webp
new file mode 100644
index 000000000..485cf425b
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xxhdpi/ic_pin_red.webp differ
diff --git a/cityquiz/src/main/res/drawable-xxhdpi/ornament_general_full.webp b/cityquiz/src/main/res/drawable-xxhdpi/ornament_general_full.webp
new file mode 100644
index 000000000..d887a5e29
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xxhdpi/ornament_general_full.webp differ
diff --git a/cityquiz/src/main/res/drawable-xxxhdpi/ic_pin_blue.webp b/cityquiz/src/main/res/drawable-xxxhdpi/ic_pin_blue.webp
new file mode 100644
index 000000000..c21b76fa8
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xxxhdpi/ic_pin_blue.webp differ
diff --git a/cityquiz/src/main/res/drawable-xxxhdpi/ic_pin_green.webp b/cityquiz/src/main/res/drawable-xxxhdpi/ic_pin_green.webp
new file mode 100644
index 000000000..beac64e2c
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xxxhdpi/ic_pin_green.webp differ
diff --git a/cityquiz/src/main/res/drawable-xxxhdpi/ic_pin_red.webp b/cityquiz/src/main/res/drawable-xxxhdpi/ic_pin_red.webp
new file mode 100644
index 000000000..8fa04c73e
Binary files /dev/null and b/cityquiz/src/main/res/drawable-xxxhdpi/ic_pin_red.webp differ
diff --git a/cityquiz/src/main/res/drawable/rounded_rect_city.xml b/cityquiz/src/main/res/drawable/rounded_rect_city.xml
new file mode 100644
index 000000000..2d2064e0f
--- /dev/null
+++ b/cityquiz/src/main/res/drawable/rounded_rect_city.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cityquiz/src/main/res/layout/activity_city_quiz.xml b/cityquiz/src/main/res/layout/activity_city_quiz.xml
new file mode 100644
index 000000000..d80a6062a
--- /dev/null
+++ b/cityquiz/src/main/res/layout/activity_city_quiz.xml
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cityquiz/src/main/res/raw/city_quiz_cities.json b/cityquiz/src/main/res/raw/city_quiz_cities.json
new file mode 100644
index 000000000..f56c54d98
--- /dev/null
+++ b/cityquiz/src/main/res/raw/city_quiz_cities.json
@@ -0,0 +1,498 @@
+[
+ {
+ "default_name": "Provideniya, Russia",
+ "name": "provideniya_russia_city",
+ "lat": 64.436249,
+ "lng": -173.233337,
+ "image_name": "provideniya_russia_city.jpg",
+ "image_author": "Leo B"
+ },
+ {
+ "default_name": "Wellington, New Zealand",
+ "name": "wellington_new_zealand_city",
+ "lat": -41.28648,
+ "lng": 174.776217,
+ "image_name": "wellington_new_zealand_city.jpg",
+ "image_author": "Vladimir Minakov"
+ },
+ {
+ "default_name": "Invercargill, New Zealand",
+ "name": "invercargill_new_zealand_city",
+ "lat": -46.4131866,
+ "lng": 168.3537731,
+ "image_name": "invercargill_new_zealand_city.jpg",
+ "image_author": "Frank Block"
+ },
+ {
+ "default_name": "Honiara, Solomon Islands",
+ "name": "honiara_solomon_islands_city",
+ "lat": -9.426761,
+ "lng": 159.948735,
+ "image_name": "honiara_solomon_islands_city.jpg",
+ "image_author": "Kiwi Bill"
+ },
+ {
+ "default_name": "Magadan, Russia",
+ "name": "magadan_russia_city",
+ "lat": 59.55632,
+ "lng": 150.81308,
+ "image_name": "magadan_russia_city.jpg",
+ "image_author": "Alexey Gnezdilov"
+ },
+ {
+ "default_name": "Andersen AFB, Guam",
+ "name": "andersen_afb_guam_city",
+ "lat": 13.58505,
+ "lng": 144.93237,
+ "image_name": "andersen_afb_guam_city.jpg",
+ "image_author": "massu"
+ },
+ {
+ "default_name": "Atlantic City, USA",
+ "name": "atlantic_city_usa_city",
+ "lat": 39.3643,
+ "lng": -74.4229,
+ "image_name": "atlantic_city_usa_city.jpg",
+ "image_author": "Marco Verch"
+ },
+ {
+ "default_name": "Yosemite National Park, USA",
+ "name": "yosemite_national_park_usa_city",
+ "lat": 37.8651,
+ "lng": -119.5383,
+ "image_name": "yosemite_national_park_usa_city.jpg",
+ "image_author": "David Iliff"
+ },
+ {
+ "default_name": "Kyoto, Japan",
+ "name": "kyoto_japan_city",
+ "lat": 35.0116,
+ "lng": 135.768,
+ "image_name": "kyoto_japan_city.jpg",
+ "image_author": "Wikipedia"
+ },
+ {
+ "default_name": "Machu Picchu, Peru",
+ "name": "machu_picchu_peru_city",
+ "lat": -13.1631,
+ "lng": -72.545,
+ "image_name": "machu_picchu_peru_city.jpg",
+ "image_author": "Martin St-Amant"
+ },
+ {
+ "default_name": "Florence, Italy",
+ "name": "florence_italy_city",
+ "lat": 43.7696,
+ "lng": 11.2558,
+ "image_name": "florence_italy_city.jpg",
+ "image_author": "Caius Bonus"
+ },
+ {
+ "default_name": "Reykjavik, Iceland",
+ "name": "reykjavik_iceland_city",
+ "lat": 64.126521,
+ "lng": -21.817439,
+ "image_name": "reykjavik_iceland_city.jpg",
+ "image_author": "Bjørn Giesenbauer"
+ },
+ {
+ "default_name": "Hanover, Germany",
+ "name": "hanover_germany_city",
+ "lat": 52.37705,
+ "lng": 9.741665,
+ "image_name": "hanover_germany_city.jpg",
+ "image_author": "Thomas Wolf"
+ },
+ {
+ "default_name": "Hamburg, Germany",
+ "name": "hamburg_germany_city",
+ "lat": 53.550669,
+ "lng": 9.992999,
+ "image_name": "hamburg_germany_city.jpg",
+ "image_author": "Wikipedia"
+ },
+ {
+ "default_name": "Mountain View, USA",
+ "name": "mountain_view_usa_city",
+ "lat": 37.42201,
+ "lng": -122.083758,
+ "image_name": "mountain_view_usa_city.jpg",
+ "image_author": "Jijithecat"
+ },
+ {
+ "default_name": "Banff, Canada",
+ "name": "banff_canada_city",
+ "lat": 51.178363,
+ "lng": -115.570769,
+ "image_name": "banff_canada_city.jpg",
+ "image_author": "Sesivany"
+ },
+ {
+ "default_name": "Warsaw, Poland",
+ "name": "warsaw_poland_city",
+ "lat": 52.229676,
+ "lng": 21.012229,
+ "image_name": "warsaw_poland_city.jpg",
+ "image_author": "Adrian Grycuk"
+ },
+ {
+ "default_name": "Stockholm, Sweden",
+ "name": "stockholm_sweden_city",
+ "lat": 59.329323,
+ "lng": 18.068581,
+ "image_name": "stockholm_sweden_city.jpg",
+ "image_author": "Brorsson"
+ },
+ {
+ "default_name": "Budapest, Hungary",
+ "name": "budapest_hungary_city",
+ "lat": 47.501937,
+ "lng": 19.042439,
+ "image_name": "budapest_hungary_city.jpg",
+ "image_author": "The Photographer"
+ },
+ {
+ "default_name": "Paris, France",
+ "name": "paris_france_city",
+ "lat": 48.8588377,
+ "lng": 2.2775173,
+ "image_name": "paris_france_city.jpg",
+ "image_author": "Benh LIEU SONG"
+ },
+ {
+ "default_name": "London, UK",
+ "name": "london_uk_city",
+ "lat": 51.5285582,
+ "lng": -0.2416809,
+ "image_name": "london_uk_city.jpg",
+ "image_author": "David Liff"
+ },
+ {
+ "default_name": "Moscow, Russia",
+ "name": "moscow_russia_city",
+ "lat": 55.7494733,
+ "lng": 37.3523203,
+ "image_name": "moscow_russia_city.jpg",
+ "image_author": "David Liff"
+ },
+ {
+ "default_name": "Dubai, UAE",
+ "name": "dubai_uae_city",
+ "lat": 25.074096,
+ "lng": 54.9479139,
+ "image_name": "dubai_uae_city.jpg",
+ "image_author": "Joi Ito"
+ },
+ {
+ "default_name": "New York City, USA",
+ "name": "new_york_city_usa_city",
+ "lat": 40.740702,
+ "lng": -73.991751,
+ "image_name": "new_york_city_usa_city.jpg",
+ "image_author": "Cadiomals"
+ },
+ {
+ "default_name": "San Francisco, USA",
+ "name": "san_francisco_usa_city",
+ "lat": 37.799061,
+ "lng": -122.468519,
+ "image_name": "san_francisco_usa_city.jpg",
+ "image_author": "RyanJWilmot"
+ },
+ {
+ "default_name": "Madrid, Spain",
+ "name": "madrid_spain_city",
+ "lat": 40.4168,
+ "lng": -3.7038,
+ "image_name": "madrid_spain_city.jpg",
+ "image_author": "Sebastian Dubiel"
+ },
+ {
+ "default_name": "Barcelona, Spain",
+ "name": "barcelona_spain_city",
+ "lat": 41.3851,
+ "lng": 2.1734,
+ "image_name": "barcelona_spain_city.jpg",
+ "image_author": "Bernard Gagnon"
+ },
+ {
+ "default_name": "Mumbai, India",
+ "name": "mumbai_india_city",
+ "lat": 18.9398259,
+ "lng": 72.8332789,
+ "image_name": "mumbai_india_city.jpg",
+ "image_author": "Joe Ravi"
+ },
+ {
+ "default_name": "Shanghai, China",
+ "name": "shanghai_china_city",
+ "lat": 31.0862279,
+ "lng": 121.4547637,
+ "image_name": "shanghai_china_city.jpg",
+ "image_author": "Henrik Hansson"
+ },
+ {
+ "default_name": "Ediburgh, Scotland",
+ "name": "ediburgh_scotland_city",
+ "lat": 55.9485977,
+ "lng": -3.2021022,
+ "image_name": "ediburgh_scotland_city.jpg",
+ "image_author": "Kim Traynor"
+ },
+ {
+ "default_name": "Port Douglas, Australia",
+ "name": "port_douglas_australia_city",
+ "lat": -16.4876294,
+ "lng": 145.47,
+ "image_name": "port_douglas_australia_city.jpg",
+ "image_author": "Malcolmj"
+ },
+ {
+ "default_name": "Istanbul, Turkey",
+ "name": "istanbul_turkey_city",
+ "lat": 41.008587,
+ "lng": 28.9779863,
+ "image_name": "istanbul_turkey_city.jpg",
+ "image_author": "Arild Vågen"
+ },
+ {
+ "default_name": "Denaru Island, Fiji",
+ "name": "denaru_island_fiji_city",
+ "lat": -17.7732571,
+ "lng": 177.3657703,
+ "image_name": "denaru_island_fiji_city.jpg",
+ "image_author": "Andreas Faessler"
+ },
+ {
+ "default_name": "Mexico City, Mexico",
+ "name": "mexico_city_mexico_city",
+ "lat": 23.6345,
+ "lng": -102.5528,
+ "image_name": "mexico_city_mexico_city.jpg",
+ "image_author": "schlaeger"
+ },
+ {
+ "default_name": "Rio De Janiero, Brazil",
+ "name": "rio_de_janiero_brazil_city",
+ "lat": -22.9068,
+ "lng": -43.1729,
+ "image_name": "rio_de_janiero_brazil_city.jpg",
+ "image_author": "Hailey Pachedo de Olivera"
+ },
+ {
+ "default_name": "Grand Canyon National Park, ZA, USA",
+ "name": "grand_canyon_national_park_za_usa_city",
+ "lat": 36.1128,
+ "lng": -113.9961,
+ "image_name": "grand_canyon_national_park_za_usa_city.jpg",
+ "image_author": "Julius Reque"
+ },
+ {
+ "default_name": "Grand Tetons National Park, WY, USA",
+ "name": "grand_tetons_national_park_wy_usa_city",
+ "lat": 43.7904,
+ "lng": -110.6818,
+ "image_name": "grand_tetons_national_park_wy_usa_city.jpg",
+ "image_author": "Jon Sullivan"
+ },
+ {
+ "default_name": "Canyonlands National Park, UT, USA",
+ "name": "canyonlands_national_park_ut_usa_city",
+ "lat": 38.3269,
+ "lng": -109.8783,
+ "image_name": "canyonlands_national_park_ut_usa_city.jpg",
+ "image_author": "Flickr"
+ },
+ {
+ "default_name": "Nashville, TN, USA",
+ "name": "nashville_tn_usa_city",
+ "lat": 36.1627,
+ "lng": -86.7816,
+ "image_name": "nashville_tn_usa_city.jpg",
+ "image_author": "Kaldari"
+ },
+ {
+ "default_name": "New Orleans, LA, USA",
+ "name": "new_orleans_la_usa_city",
+ "lat": 29.9511,
+ "lng": -90.0715,
+ "image_name": "new_orleans_la_usa_city.jpg",
+ "image_author": "Nowhereman86"
+ },
+ {
+ "default_name": "Rome, Italy",
+ "name": "rome_italy_city",
+ "lat": 41.9028,
+ "lng": 12.4964,
+ "image_name": "rome_italy_city.jpg",
+ "image_author": "David Liff"
+ },
+ {
+ "default_name": "Berlin, Germany",
+ "name": "berlin_germany_city",
+ "lat": 52.52,
+ "lng": 13.405,
+ "image_name": "berlin_germany_city.jpg",
+ "image_author": "Jurgen Matem"
+ },
+ {
+ "default_name": "Washington, DC, USA",
+ "name": "washington_dc_usa_city",
+ "lat": 38.8799,
+ "lng": -77.0365,
+ "image_name": "washington_dc_usa_city.jpg",
+ "image_author": "Matt Wade"
+ },
+ {
+ "default_name": "Dublin, Ireland",
+ "name": "dublin_ireland_city",
+ "lat": 53.3497,
+ "lng": -6.2603,
+ "image_name": "dublin_ireland_city.jpg",
+ "image_author": "Donadlytong"
+ },
+ {
+ "default_name": "Zurich, Switzerland",
+ "name": "zurich_switzerland_city",
+ "lat": 47.3769,
+ "lng": 8.5417,
+ "image_name": "zurich_switzerland_city.jpg",
+ "image_author": "Roland zh"
+ },
+ {
+ "default_name": "Tokyo, Japan",
+ "name": "tokyo_japan_city",
+ "lat": 35.6895,
+ "lng": 139.6917,
+ "image_name": "tokyo_japan_city.jpg",
+ "image_author": "Morio"
+ },
+ {
+ "default_name": "Atlanta, GA, USA",
+ "name": "atlanta_ga_usa_city",
+ "lat": 33.749,
+ "lng": -85.388,
+ "image_name": "atlanta_ga_usa_city.jpg",
+ "image_author": "Mike"
+ },
+ {
+ "default_name": "Chicago, IL, USA",
+ "name": "chicago_il_usa_city",
+ "lat": 41.8781,
+ "lng": -87.6298,
+ "image_name": "chicago_il_usa_city.jpg",
+ "image_author": "mindfrieze"
+ },
+ {
+ "default_name": "Port Of Spain, Trinidad and Tobago",
+ "name": "port_of_spain_trinidad_and_tobago_city",
+ "lat": 10.6617,
+ "lng": -61.5194,
+ "image_name": "port_of_spain_trinidad_and_tobago_city.jpg",
+ "image_author": "Christianwelsh"
+ },
+ {
+ "default_name": "Kingston, Jamaica",
+ "name": "kingston_jamaica_city",
+ "lat": 18.017924,
+ "lng": -76.805464,
+ "image_name": "kingston_jamaica_city.jpg",
+ "image_author": "Wolmadrian"
+ },
+ {
+ "default_name": "Panama City, Panama",
+ "name": "panama_city_panama_city",
+ "lat": 9.1012,
+ "lng": -79.4029,
+ "image_name": "panama_city_panama_city.jpg",
+ "image_author": "123 Hollic"
+ },
+ {
+ "default_name": "Miami Florida, USA",
+ "name": "miami_florida_usa_city",
+ "lat": 25.7617,
+ "lng": -80.1918,
+ "image_name": "miami_florida_usa_city.jpg",
+ "image_author": "D Ramey Logan"
+ },
+ {
+ "default_name": "Buenos Aires, Argentina",
+ "name": "buenos_aires_argentina_city",
+ "lat": -34.6037,
+ "lng": -58.3816,
+ "image_name": "buenos_aires_argentina_city.jpg",
+ "image_author": "Dario Alpern"
+ },
+ {
+ "default_name": "Sao Paulo, Brazil",
+ "name": "sao_paulo_brazil_city",
+ "lat": -23.5505,
+ "lng": -46.6333,
+ "image_name": "sao_paulo_brazil_city.jpg",
+ "image_author": "The Photographer"
+ },
+ {
+ "default_name": "Bogota, Columbia",
+ "name": "bogota_columbia_city",
+ "lat": 4.711,
+ "lng": -74.0721,
+ "image_name": "bogota_columbia_city.jpg",
+ "image_author": "PUTIS"
+ },
+ {
+ "default_name": "Santiago, Chile",
+ "name": "santiago_chile_city",
+ "lat": -33.4489,
+ "lng": -70.6693,
+ "image_name": "santiago_chile_city.jpg",
+ "image_author": "Foncea"
+ },
+ {
+ "default_name": "Quito, Ecuador",
+ "name": "quito_ecuador_city",
+ "lat": "-0/1807",
+ "lng": -78.4678,
+ "image_name": "quito_ecuador_city.jpg",
+ "image_author": "Diego Delso"
+ },
+ {
+ "default_name": "Guatemala City, Guatemala",
+ "name": "guatemala_city_guatemala_city",
+ "lat": 14.6349,
+ "lng": -90.5069,
+ "image_name": "guatemala_city_guatemala_city.jpg",
+ "image_author": "Rigostar"
+ },
+ {
+ "default_name": "La Paz, Bolivia",
+ "name": "la_paz_bolivia_city",
+ "lat": -16.4897,
+ "lng": -68.1193,
+ "image_name": "la_paz_bolivia_city.jpg",
+ "image_author": "Paul Richter"
+ },
+ {
+ "default_name": "Lagos, Nigeria",
+ "name": "lagos_nigeria_city",
+ "lat": 6.5244,
+ "lng": 3.3792,
+ "image_name": "lagos_nigeria_city.jpg",
+ "image_author": "Benji Robertson"
+ },
+ {
+ "default_name": "New Delhi, India",
+ "name": "new_delhi_india_city",
+ "lat": 28.6139,
+ "lng": 77.209,
+ "image_name": "new_delhi_india_city.jpg",
+ "image_author": "Ville Miettinen"
+ },
+ {
+ "default_name": "Cape Town, South Africa",
+ "name": "cape_town_south_africa_city",
+ "lat": -33.9249,
+ "lng": 18.4241,
+ "image_name": "cape_town_south_africa_city.jpg",
+ "image_author": "Warrickball"
+ }
+]
\ No newline at end of file
diff --git a/cityquiz/src/main/res/values-af/strings.xml b/cityquiz/src/main/res/values-af/strings.xml
new file mode 100644
index 000000000..e66e1c362
--- /dev/null
+++ b/cityquiz/src/main/res/values-af/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Waar is dit?
+ %1$d van %2$d
+ %1$d punte
+ Foto deur: %1$s
+
diff --git a/cityquiz/src/main/res/values-ar-rXB/strings.xml b/cityquiz/src/main/res/values-ar-rXB/strings.xml
new file mode 100644
index 000000000..f3eaa06d5
--- /dev/null
+++ b/cityquiz/src/main/res/values-ar-rXB/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Where is this?
+ %1$d of %2$d
+ %1$d points
+ Photo by: %1$s
+
diff --git a/cityquiz/src/main/res/values-bg/strings.xml b/cityquiz/src/main/res/values-bg/strings.xml
new file mode 100644
index 000000000..4f846c298
--- /dev/null
+++ b/cityquiz/src/main/res/values-bg/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Къде е това?
+ %1$d от %2$d
+ %1$d точки
+ Снимка от: %1$s
+
diff --git a/cityquiz/src/main/res/values-ca/strings.xml b/cityquiz/src/main/res/values-ca/strings.xml
new file mode 100644
index 000000000..6e53fdc48
--- /dev/null
+++ b/cityquiz/src/main/res/values-ca/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ On és això?
+ %1$d de %2$d
+ %1$d punts
+ Fotografia de: %1$s
+
diff --git a/cityquiz/src/main/res/values-da/strings.xml b/cityquiz/src/main/res/values-da/strings.xml
new file mode 100644
index 000000000..db64d2ee1
--- /dev/null
+++ b/cityquiz/src/main/res/values-da/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Hvor er det?
+ %1$d af %2$d
+ %1$d point
+ Foto: %1$s
+
diff --git a/cityquiz/src/main/res/values-de-rAT/strings.xml b/cityquiz/src/main/res/values-de-rAT/strings.xml
new file mode 100644
index 000000000..08d57fa84
--- /dev/null
+++ b/cityquiz/src/main/res/values-de-rAT/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Wo ist dieser Ort?
+ %1$d von %2$d
+ %1$d Punkte
+ Foto: %1$s
+
diff --git a/cityquiz/src/main/res/values-de-rCH/strings.xml b/cityquiz/src/main/res/values-de-rCH/strings.xml
new file mode 100644
index 000000000..08d57fa84
--- /dev/null
+++ b/cityquiz/src/main/res/values-de-rCH/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Wo ist dieser Ort?
+ %1$d von %2$d
+ %1$d Punkte
+ Foto: %1$s
+
diff --git a/cityquiz/src/main/res/values-de/strings.xml b/cityquiz/src/main/res/values-de/strings.xml
new file mode 100644
index 000000000..08d57fa84
--- /dev/null
+++ b/cityquiz/src/main/res/values-de/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Wo ist dieser Ort?
+ %1$d von %2$d
+ %1$d Punkte
+ Foto: %1$s
+
diff --git a/cityquiz/src/main/res/values-en-rGB/strings.xml b/cityquiz/src/main/res/values-en-rGB/strings.xml
new file mode 100644
index 000000000..7f7d34b8e
--- /dev/null
+++ b/cityquiz/src/main/res/values-en-rGB/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Where is this?
+ %1$d of %2$d
+ %1$d points
+ Photo by: %1$s
+
diff --git a/cityquiz/src/main/res/values-en-rIE/strings.xml b/cityquiz/src/main/res/values-en-rIE/strings.xml
new file mode 100644
index 000000000..7f7d34b8e
--- /dev/null
+++ b/cityquiz/src/main/res/values-en-rIE/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Where is this?
+ %1$d of %2$d
+ %1$d points
+ Photo by: %1$s
+
diff --git a/cityquiz/src/main/res/values-en-rIN/strings.xml b/cityquiz/src/main/res/values-en-rIN/strings.xml
new file mode 100644
index 000000000..7f7d34b8e
--- /dev/null
+++ b/cityquiz/src/main/res/values-en-rIN/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Where is this?
+ %1$d of %2$d
+ %1$d points
+ Photo by: %1$s
+
diff --git a/cityquiz/src/main/res/values-en-rSG/strings.xml b/cityquiz/src/main/res/values-en-rSG/strings.xml
new file mode 100644
index 000000000..7f7d34b8e
--- /dev/null
+++ b/cityquiz/src/main/res/values-en-rSG/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Where is this?
+ %1$d of %2$d
+ %1$d points
+ Photo by: %1$s
+
diff --git a/cityquiz/src/main/res/values-en-rXA/strings.xml b/cityquiz/src/main/res/values-en-rXA/strings.xml
new file mode 100644
index 000000000..46a5847f6
--- /dev/null
+++ b/cityquiz/src/main/res/values-en-rXA/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ [Ŵĥéŕé îš ţĥîš¿ one two]
+ [ᐅ%1$dᐊ öƒ ᐅ%2$dᐊ one two three]
+ [ᐅ%1$dᐊ þöîñţš one two three]
+ [Þĥöţö бý: ᐅ%1$sᐊ one two three]
+
diff --git a/cityquiz/src/main/res/values-en-rXC/strings.xml b/cityquiz/src/main/res/values-en-rXC/strings.xml
new file mode 100644
index 000000000..d8d873005
--- /dev/null
+++ b/cityquiz/src/main/res/values-en-rXC/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Where is this?
+ %1$d of %2$d
+ %1$d points
+ Photo by: %1$s
+
diff --git a/cityquiz/src/main/res/values-en-rZA/strings.xml b/cityquiz/src/main/res/values-en-rZA/strings.xml
new file mode 100644
index 000000000..7f7d34b8e
--- /dev/null
+++ b/cityquiz/src/main/res/values-en-rZA/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Where is this?
+ %1$d of %2$d
+ %1$d points
+ Photo by: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rAR/strings.xml b/cityquiz/src/main/res/values-es-rAR/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rAR/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rBO/strings.xml b/cityquiz/src/main/res/values-es-rBO/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rBO/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rCL/strings.xml b/cityquiz/src/main/res/values-es-rCL/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rCL/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rCO/strings.xml b/cityquiz/src/main/res/values-es-rCO/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rCO/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rCR/strings.xml b/cityquiz/src/main/res/values-es-rCR/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rCR/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rDO/strings.xml b/cityquiz/src/main/res/values-es-rDO/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rDO/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rEC/strings.xml b/cityquiz/src/main/res/values-es-rEC/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rEC/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rGT/strings.xml b/cityquiz/src/main/res/values-es-rGT/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rGT/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rHN/strings.xml b/cityquiz/src/main/res/values-es-rHN/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rHN/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rMX/strings.xml b/cityquiz/src/main/res/values-es-rMX/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rMX/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rNI/strings.xml b/cityquiz/src/main/res/values-es-rNI/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rNI/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rPA/strings.xml b/cityquiz/src/main/res/values-es-rPA/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rPA/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rPE/strings.xml b/cityquiz/src/main/res/values-es-rPE/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rPE/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rPR/strings.xml b/cityquiz/src/main/res/values-es-rPR/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rPR/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rPY/strings.xml b/cityquiz/src/main/res/values-es-rPY/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rPY/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rSV/strings.xml b/cityquiz/src/main/res/values-es-rSV/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rSV/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rUS/strings.xml b/cityquiz/src/main/res/values-es-rUS/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rUS/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rUY/strings.xml b/cityquiz/src/main/res/values-es-rUY/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rUY/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es-rVE/strings.xml b/cityquiz/src/main/res/values-es-rVE/strings.xml
new file mode 100644
index 000000000..e50027bdb
--- /dev/null
+++ b/cityquiz/src/main/res/values-es-rVE/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Sabes qué lugar es este?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-es/strings.xml b/cityquiz/src/main/res/values-es/strings.xml
new file mode 100644
index 000000000..160a39282
--- /dev/null
+++ b/cityquiz/src/main/res/values-es/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ¿Dónde está?
+ %1$d de %2$d
+ %1$d puntos
+ Foto de %1$s
+
diff --git a/cityquiz/src/main/res/values-et/strings.xml b/cityquiz/src/main/res/values-et/strings.xml
new file mode 100644
index 000000000..27922ea5f
--- /dev/null
+++ b/cityquiz/src/main/res/values-et/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Kus see on?
+ %1$d/%2$d
+ %1$d punkti
+ Foto autor: %1$s
+
diff --git a/cityquiz/src/main/res/values-fi/strings.xml b/cityquiz/src/main/res/values-fi/strings.xml
new file mode 100644
index 000000000..2c859b64b
--- /dev/null
+++ b/cityquiz/src/main/res/values-fi/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Missä tämä on?
+ %1$d/%2$d
+ %1$d pistettä
+ Kuvaaja: %1$s
+
diff --git a/cityquiz/src/main/res/values-fil/strings.xml b/cityquiz/src/main/res/values-fil/strings.xml
new file mode 100644
index 000000000..257ab1f3a
--- /dev/null
+++ b/cityquiz/src/main/res/values-fil/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Saan ito?
+ %1$d sa %2$d
+ %1$d puntos
+ Litratong kuha ni: %1$s
+
diff --git a/cityquiz/src/main/res/values-fr-rCA/strings.xml b/cityquiz/src/main/res/values-fr-rCA/strings.xml
new file mode 100644
index 000000000..e08c76f4f
--- /dev/null
+++ b/cityquiz/src/main/res/values-fr-rCA/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Où est-ce?
+ %1$d sur %2$d
+ %1$d points
+ Photo par : %1$s
+
diff --git a/cityquiz/src/main/res/values-fr-rCH/strings.xml b/cityquiz/src/main/res/values-fr-rCH/strings.xml
new file mode 100644
index 000000000..8fe653fce
--- /dev/null
+++ b/cityquiz/src/main/res/values-fr-rCH/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Où est-ce ?
+ %1$d sur %2$d
+ %1$d points
+ Photo de : %1$s
+
diff --git a/cityquiz/src/main/res/values-fr/strings.xml b/cityquiz/src/main/res/values-fr/strings.xml
new file mode 100644
index 000000000..8fe653fce
--- /dev/null
+++ b/cityquiz/src/main/res/values-fr/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Où est-ce ?
+ %1$d sur %2$d
+ %1$d points
+ Photo de : %1$s
+
diff --git a/cityquiz/src/main/res/values-gsw/strings.xml b/cityquiz/src/main/res/values-gsw/strings.xml
new file mode 100644
index 000000000..08d57fa84
--- /dev/null
+++ b/cityquiz/src/main/res/values-gsw/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Wo ist dieser Ort?
+ %1$d von %2$d
+ %1$d Punkte
+ Foto: %1$s
+
diff --git a/cityquiz/src/main/res/values-hr/strings.xml b/cityquiz/src/main/res/values-hr/strings.xml
new file mode 100644
index 000000000..592080817
--- /dev/null
+++ b/cityquiz/src/main/res/values-hr/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Gdje se nalazi ovo?
+ %1$d od %2$d
+ Broj bodova: %1$d
+ Autor fotografije: %1$s
+
diff --git a/cityquiz/src/main/res/values-id/strings.xml b/cityquiz/src/main/res/values-id/strings.xml
new file mode 100644
index 000000000..f54270334
--- /dev/null
+++ b/cityquiz/src/main/res/values-id/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Di manakah lokasi ini?
+ %1$d dari %2$d
+ %1$d poin
+ Foto oleh: %1$s
+
diff --git a/cityquiz/src/main/res/values-in/strings.xml b/cityquiz/src/main/res/values-in/strings.xml
new file mode 100644
index 000000000..f54270334
--- /dev/null
+++ b/cityquiz/src/main/res/values-in/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Di manakah lokasi ini?
+ %1$d dari %2$d
+ %1$d poin
+ Foto oleh: %1$s
+
diff --git a/cityquiz/src/main/res/values-it/strings.xml b/cityquiz/src/main/res/values-it/strings.xml
new file mode 100644
index 000000000..0ac1d8b5d
--- /dev/null
+++ b/cityquiz/src/main/res/values-it/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Dove si trova?
+ %1$d di %2$d
+ %1$d punti
+ Foto di: %1$s
+
diff --git a/cityquiz/src/main/res/values-ja/strings.xml b/cityquiz/src/main/res/values-ja/strings.xml
new file mode 100644
index 000000000..5c7ec00bd
--- /dev/null
+++ b/cityquiz/src/main/res/values-ja/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ここはどこでしょうか?
+ %1$d / %2$d
+ %1$d ポイント
+ 撮影: %1$s
+
diff --git a/cityquiz/src/main/res/values-ko/strings.xml b/cityquiz/src/main/res/values-ko/strings.xml
new file mode 100644
index 000000000..58e147108
--- /dev/null
+++ b/cityquiz/src/main/res/values-ko/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ 여기가 어디인가요?
+ %2$d회 중 %1$d회
+ %1$d점
+ 사진: %1$s
+
diff --git a/cityquiz/src/main/res/values-ln/strings.xml b/cityquiz/src/main/res/values-ln/strings.xml
new file mode 100644
index 000000000..8fe653fce
--- /dev/null
+++ b/cityquiz/src/main/res/values-ln/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Où est-ce ?
+ %1$d sur %2$d
+ %1$d points
+ Photo de : %1$s
+
diff --git a/cityquiz/src/main/res/values-lt/strings.xml b/cityquiz/src/main/res/values-lt/strings.xml
new file mode 100644
index 000000000..27c3b2d91
--- /dev/null
+++ b/cityquiz/src/main/res/values-lt/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Kur tai yra?
+ %1$d iš %2$d
+ %1$d tšk.
+ %1$s nuotrauka
+
diff --git a/cityquiz/src/main/res/values-lv/strings.xml b/cityquiz/src/main/res/values-lv/strings.xml
new file mode 100644
index 000000000..b3c53f1ac
--- /dev/null
+++ b/cityquiz/src/main/res/values-lv/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Kur tas atrodas?
+ %1$d no %2$d
+ %1$d punkti
+ Fotoattēla autors: %1$s
+
diff --git a/cityquiz/src/main/res/values-ml/strings.xml b/cityquiz/src/main/res/values-ml/strings.xml
new file mode 100644
index 000000000..893409997
--- /dev/null
+++ b/cityquiz/src/main/res/values-ml/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ ഇത് എവിടെയാണ്?
+ %1$d / %2$d
+ %1$d പോയിന്റുകൾ
+ ഫോട്ടോ എടുത്തത്: %1$s
+
diff --git a/cityquiz/src/main/res/values-mo/strings.xml b/cityquiz/src/main/res/values-mo/strings.xml
new file mode 100644
index 000000000..bb56a1180
--- /dev/null
+++ b/cityquiz/src/main/res/values-mo/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Unde este?
+ %1$d din %2$d
+ Puncte: %1$d
+ Fotografie de: %1$s
+
diff --git a/cityquiz/src/main/res/values-nb/strings.xml b/cityquiz/src/main/res/values-nb/strings.xml
new file mode 100644
index 000000000..4be8db66a
--- /dev/null
+++ b/cityquiz/src/main/res/values-nb/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Hvor er dette?
+ %1$d av %2$d
+ %1$d poeng
+ Foto av: %1$s
+
diff --git a/cityquiz/src/main/res/values-no/strings.xml b/cityquiz/src/main/res/values-no/strings.xml
new file mode 100644
index 000000000..4be8db66a
--- /dev/null
+++ b/cityquiz/src/main/res/values-no/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Hvor er dette?
+ %1$d av %2$d
+ %1$d poeng
+ Foto av: %1$s
+
diff --git a/cityquiz/src/main/res/values-pl/strings.xml b/cityquiz/src/main/res/values-pl/strings.xml
new file mode 100644
index 000000000..eb2daccf2
--- /dev/null
+++ b/cityquiz/src/main/res/values-pl/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Gdzie to jest?
+ %1$d z %2$d
+ Punkty: %1$d
+ Zdjęcie: %1$s
+
diff --git a/cityquiz/src/main/res/values-pt-rBR/strings.xml b/cityquiz/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 000000000..f3e8f9c4b
--- /dev/null
+++ b/cityquiz/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Onde é isso?
+ %1$d de %2$d
+ %1$d pontos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-pt-rPT/strings.xml b/cityquiz/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 000000000..7ff983580
--- /dev/null
+++ b/cityquiz/src/main/res/values-pt-rPT/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Sabe onde fica?
+ %1$d de %2$d
+ %1$d pontos
+ Foto por: %1$s
+
diff --git a/cityquiz/src/main/res/values-pt/strings.xml b/cityquiz/src/main/res/values-pt/strings.xml
new file mode 100644
index 000000000..f3e8f9c4b
--- /dev/null
+++ b/cityquiz/src/main/res/values-pt/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Onde é isso?
+ %1$d de %2$d
+ %1$d pontos
+ Foto de: %1$s
+
diff --git a/cityquiz/src/main/res/values-ro/strings.xml b/cityquiz/src/main/res/values-ro/strings.xml
new file mode 100644
index 000000000..bb56a1180
--- /dev/null
+++ b/cityquiz/src/main/res/values-ro/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Unde este?
+ %1$d din %2$d
+ Puncte: %1$d
+ Fotografie de: %1$s
+
diff --git a/cityquiz/src/main/res/values-ru/strings.xml b/cityquiz/src/main/res/values-ru/strings.xml
new file mode 100644
index 000000000..014995856
--- /dev/null
+++ b/cityquiz/src/main/res/values-ru/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Где это находится?
+ %1$d из %2$d
+ Очков: %1$d
+ Фото: %1$s
+
diff --git a/cityquiz/src/main/res/values-sl/strings.xml b/cityquiz/src/main/res/values-sl/strings.xml
new file mode 100644
index 000000000..d2ee7580d
--- /dev/null
+++ b/cityquiz/src/main/res/values-sl/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Kje je to?
+ %1$d od %2$d
+ Število točk: %1$d
+ Avtor fotografije: %1$s
+
diff --git a/cityquiz/src/main/res/values-sv/strings.xml b/cityquiz/src/main/res/values-sv/strings.xml
new file mode 100644
index 000000000..32f748192
--- /dev/null
+++ b/cityquiz/src/main/res/values-sv/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Var är det här?
+ %1$d av %2$d
+ %1$d poäng
+ Foto av %1$s
+
diff --git a/cityquiz/src/main/res/values-ta/strings.xml b/cityquiz/src/main/res/values-ta/strings.xml
new file mode 100644
index 000000000..81567b127
--- /dev/null
+++ b/cityquiz/src/main/res/values-ta/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ இந்த இடம் எங்கே உள்ளது?
+ %1$d / %2$d
+ %1$d புள்ளிகள்
+ படமெடுத்தவர்: %1$s
+
diff --git a/cityquiz/src/main/res/values-th/strings.xml b/cityquiz/src/main/res/values-th/strings.xml
new file mode 100644
index 000000000..e30378f82
--- /dev/null
+++ b/cityquiz/src/main/res/values-th/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ สถานที่นี้อยู่ที่ใด
+ %1$d จาก %2$d
+ %1$d คะแนน
+ รูปภาพโดย: %1$s
+
diff --git a/cityquiz/src/main/res/values-tl/strings.xml b/cityquiz/src/main/res/values-tl/strings.xml
new file mode 100644
index 000000000..257ab1f3a
--- /dev/null
+++ b/cityquiz/src/main/res/values-tl/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Saan ito?
+ %1$d sa %2$d
+ %1$d puntos
+ Litratong kuha ni: %1$s
+
diff --git a/cityquiz/src/main/res/values-uk/strings.xml b/cityquiz/src/main/res/values-uk/strings.xml
new file mode 100644
index 000000000..6457d096c
--- /dev/null
+++ b/cityquiz/src/main/res/values-uk/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Де це?
+ %1$d з %2$d
+ Балів: %1$d
+ Автор фото: %1$s
+
diff --git a/cityquiz/src/main/res/values-vi/strings.xml b/cityquiz/src/main/res/values-vi/strings.xml
new file mode 100644
index 000000000..66b4ba5a5
--- /dev/null
+++ b/cityquiz/src/main/res/values-vi/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Địa điểm này ở đâu?
+ %1$d / %2$d
+ %1$d điểm
+ Ảnh của: %1$s
+
diff --git a/cityquiz/src/main/res/values-zh-rCN/strings.xml b/cityquiz/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 000000000..498d21149
--- /dev/null
+++ b/cityquiz/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ 这是哪里?
+ 第 %1$d 回合,共 %2$d 回合
+ %1$d 分
+ 拍摄者:%1$s
+
diff --git a/cityquiz/src/main/res/values-zh-rHK/strings.xml b/cityquiz/src/main/res/values-zh-rHK/strings.xml
new file mode 100644
index 000000000..05ec50417
--- /dev/null
+++ b/cityquiz/src/main/res/values-zh-rHK/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ 這是什麼地方?
+ 第 %1$d 回合,共 %2$d 回合
+ %1$d 分
+ 攝影師:%1$s
+
diff --git a/cityquiz/src/main/res/values-zh-rTW/strings.xml b/cityquiz/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 000000000..0b9332b7a
--- /dev/null
+++ b/cityquiz/src/main/res/values-zh-rTW/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ 這是哪裡?
+ 第 %1$d 回合 (共 %2$d 回合)
+ %1$d 分
+ 拍攝者:%1$s
+
diff --git a/cityquiz/src/main/res/values-zh/strings.xml b/cityquiz/src/main/res/values-zh/strings.xml
new file mode 100644
index 000000000..498d21149
--- /dev/null
+++ b/cityquiz/src/main/res/values-zh/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ 这是哪里?
+ 第 %1$d 回合,共 %2$d 回合
+ %1$d 分
+ 拍摄者:%1$s
+
diff --git a/cityquiz/src/main/res/values/colors.xml b/cityquiz/src/main/res/values/colors.xml
new file mode 100644
index 000000000..56165f71c
--- /dev/null
+++ b/cityquiz/src/main/res/values/colors.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/cityquiz/src/main/res/values/strings.xml b/cityquiz/src/main/res/values/strings.xml
new file mode 100644
index 000000000..4ea3e7455
--- /dev/null
+++ b/cityquiz/src/main/res/values/strings.xml
@@ -0,0 +1,21 @@
+
+
+ Where is this?
+ %1$d of %2$d
+ %1$d points
+ Photo by: %1$s
+
diff --git a/cityquiz/src/main/res/values/styles.xml b/cityquiz/src/main/res/values/styles.xml
new file mode 100644
index 000000000..6c65774ee
--- /dev/null
+++ b/cityquiz/src/main/res/values/styles.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/common/build.gradle b/common/build.gradle
index 757fa6cf2..8e80dcc75 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -1,26 +1,62 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
android {
- compileSdkVersion 23
+ compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.tools
defaultConfig {
- minSdkVersion 15
- targetSdkVersion 23
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ }
+
+ // Disable translation lint checks until we get the translation pipeline running
+ lintOptions {
+ disable 'ExtraTranslation', 'MissingTranslation'
}
}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
+ implementation rootProject.ext.kotlinRuntime
+
+ implementation rootProject.ext.appCompat
- compile rootProject.ext.supportV4
+ implementation rootProject.ext.coreKtx
- compile rootProject.ext.playServicesAnalytics
- compile rootProject.ext.playServicesBase
- compile rootProject.ext.playServicesBasement
- compile rootProject.ext.playServicesGames
+ implementation rootProject.ext.playServicesBase
+ implementation rootProject.ext.playServicesGames
+ implementation rootProject.ext.playServicesMaps
- compile rootProject.ext.firebaseCore
- compile rootProject.ext.firebaseAnalytics
- compile rootProject.ext.firebaseAppinvite
-}
\ No newline at end of file
+ implementation rootProject.ext.firebaseConfig
+ implementation rootProject.ext.firebaseCore
+ implementation rootProject.ext.firebaseAppinvite
+ implementation rootProject.ext.firebaseCrash
+
+ implementation rootProject.ext.archLifecycleRuntime
+ implementation rootProject.ext.archLifecycleExtentions
+
+ implementation rootProject.ext.constraintLayout
+ implementation rootProject.ext.flexbox
+
+ implementation rootProject.ext.glide
+
+ implementation rootProject.ext.playCore
+}
diff --git a/common/lint.xml b/common/lint.xml
new file mode 100644
index 000000000..ba0b137e5
--- /dev/null
+++ b/common/lint.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/common/proguard-rules.pro b/common/proguard-rules.pro
deleted file mode 100644
index e2c580fb8..000000000
--- a/common/proguard-rules.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /Users/lwray/Desktop/Stuff/adt-bundle-mac-x86_64-20131030/sdk/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/common/src/debug/res/drawable-hdpi/ic_launcher_foreground.webp b/common/src/debug/res/drawable-hdpi/ic_launcher_foreground.webp
new file mode 100644
index 000000000..497814d93
Binary files /dev/null and b/common/src/debug/res/drawable-hdpi/ic_launcher_foreground.webp differ
diff --git a/common/src/debug/res/drawable-mdpi/ic_launcher_foreground.webp b/common/src/debug/res/drawable-mdpi/ic_launcher_foreground.webp
new file mode 100644
index 000000000..a46dafafc
Binary files /dev/null and b/common/src/debug/res/drawable-mdpi/ic_launcher_foreground.webp differ
diff --git a/common/src/debug/res/drawable-xhdpi/ic_launcher_foreground.webp b/common/src/debug/res/drawable-xhdpi/ic_launcher_foreground.webp
new file mode 100644
index 000000000..4ebb18807
Binary files /dev/null and b/common/src/debug/res/drawable-xhdpi/ic_launcher_foreground.webp differ
diff --git a/common/src/debug/res/drawable-xxhdpi/ic_launcher_foreground.webp b/common/src/debug/res/drawable-xxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 000000000..dbcf8d819
Binary files /dev/null and b/common/src/debug/res/drawable-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/common/src/debug/res/drawable-xxxhdpi/ic_launcher_foreground.webp b/common/src/debug/res/drawable-xxxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 000000000..5731b4012
Binary files /dev/null and b/common/src/debug/res/drawable-xxxhdpi/ic_launcher_foreground.webp differ
diff --git a/common/src/debug/res/mipmap-hdpi/ic_launcher_santa.webp b/common/src/debug/res/mipmap-hdpi/ic_launcher_santa.webp
new file mode 100644
index 000000000..381cc4b66
Binary files /dev/null and b/common/src/debug/res/mipmap-hdpi/ic_launcher_santa.webp differ
diff --git a/common/src/debug/res/mipmap-mdpi/ic_launcher_santa.webp b/common/src/debug/res/mipmap-mdpi/ic_launcher_santa.webp
new file mode 100644
index 000000000..722732ea5
Binary files /dev/null and b/common/src/debug/res/mipmap-mdpi/ic_launcher_santa.webp differ
diff --git a/common/src/debug/res/mipmap-xhdpi/ic_launcher_santa.webp b/common/src/debug/res/mipmap-xhdpi/ic_launcher_santa.webp
new file mode 100644
index 000000000..eedfde28e
Binary files /dev/null and b/common/src/debug/res/mipmap-xhdpi/ic_launcher_santa.webp differ
diff --git a/common/src/debug/res/mipmap-xxhdpi/ic_launcher_santa.webp b/common/src/debug/res/mipmap-xxhdpi/ic_launcher_santa.webp
new file mode 100644
index 000000000..42b3ccd01
Binary files /dev/null and b/common/src/debug/res/mipmap-xxhdpi/ic_launcher_santa.webp differ
diff --git a/common/src/debug/res/mipmap-xxxhdpi/ic_launcher_santa.webp b/common/src/debug/res/mipmap-xxxhdpi/ic_launcher_santa.webp
new file mode 100644
index 000000000..51bf21518
Binary files /dev/null and b/common/src/debug/res/mipmap-xxxhdpi/ic_launcher_santa.webp differ
diff --git a/common/src/debug/res/values/debug_settings.xml b/common/src/debug/res/values/debug_settings.xml
new file mode 100644
index 000000000..81a97624c
--- /dev/null
+++ b/common/src/debug/res/values/debug_settings.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ false
+
+
diff --git a/common/src/debug/res/xml/config_analytics_global.xml b/common/src/debug/res/xml/config_analytics_global.xml
new file mode 100644
index 000000000..5b91db2f8
--- /dev/null
+++ b/common/src/debug/res/xml/config_analytics_global.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ verbose
+ true
+
+
diff --git a/common/src/debug/res/xml/google_now_actions.xml b/common/src/debug/res/xml/google_now_actions.xml
new file mode 100644
index 000000000..53515ef32
--- /dev/null
+++ b/common/src/debug/res/xml/google_now_actions.xml
@@ -0,0 +1,62 @@
+
+
+
+
+ com.google.android.apps.santatracker
+ 1
+ Santa Tracker
+
+ ShowAction
+ com.google.android.apps.santatracker.SHOW_SANTA
+ show $SantaSynonym:santa
+ show santa on Google Santa Tracker
+
+
+ $SantaSynonym
+ Santa
+ Santa Claus
+ Saint Nicholas
+ Father Christmas
+ Kris Kringle
+
+
+ ActivateAction
+ com.google.android.apps.santatracker.PLAY_GAME
+ play $SantaGame:game game
+ play $SantaGame:game
+ play Elf Jetpack game on Google Santa Tracker
+
+
+ $SantaGame
+ Elf Jetpack
+ Memory
+ Gumball
+ Rocket Sleigh
+ Dasher Dancer
+
+
+ ActivateAction
+ com.google.android.apps.santatracker.PLAY_RANDOM_GAME
+ play game
+ play a game
+ play games
+ play game on Google Santa Tracker
+
+
diff --git a/common/src/main/AndroidManifest.xml b/common/src/main/AndroidManifest.xml
index aaff8795b..99a15d1b0 100644
--- a/common/src/main/AndroidManifest.xml
+++ b/common/src/main/AndroidManifest.xml
@@ -1,10 +1,33 @@
+
+ package="com.google.android.apps.santatracker.common">
-
+
+
+
+
+
+
diff --git a/common/src/main/java/com/google/android/apps/santatracker/AudioConstants.kt b/common/src/main/java/com/google/android/apps/santatracker/AudioConstants.kt
new file mode 100644
index 000000000..96ae7ef81
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/AudioConstants.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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
+
+object AudioConstants {
+ const val DEFAULT_BACKGROUND_VOLUME = 0.2f
+ const val DEFAULT_SOUND_EFFECT_VOLUME = 0.4f
+}
\ No newline at end of file
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
deleted file mode 100644
index 8b8609a00..000000000
--- a/common/src/main/java/com/google/android/apps/santatracker/AudioPlayer.java
+++ /dev/null
@@ -1,137 +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.apps.santatracker;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.media.MediaPlayer.OnPreparedListener;
-import android.util.SparseArray;
-
-public class AudioPlayer {
-
- private Context mContext;
- private SparseArray mStreams;
- private boolean mMuted = false;
-
- private static float VOLUME_MULTIPLIER = 0.25f;
-
- public AudioPlayer(Context context) {
- mContext = context;
- mStreams = new SparseArray<>();
- this.mMuted = false;
- }
-
- public void playTrack(final int resId, final boolean loop) {
- MediaPlayer mediaPlayer = MediaPlayer.create(mContext, resId);
- // Not all devices support audio (i.e. watches)
- if (mediaPlayer != null) {
- mStreams.put(resId, mediaPlayer);
- mediaPlayer.setLooping(loop);
- mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
- public void onPrepared(MediaPlayer mp) {
- startMedia(mp);
- }
- });
- mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
- public void onCompletion(MediaPlayer mp) {
- if (!mp.isLooping()) {
- mp.release();
- mStreams.remove(resId);
- }
- }
- });
- }
- }
-
- public void playTrackIfNotAlreadyPlaying(final int resId, final boolean loop) {
- if (mStreams.get(resId) == null) {
- playTrack(resId, loop);
- }
- }
-
- public void playTrackExclusive(final int resId, final boolean loop) {
- boolean restart = false;
- MediaPlayer mp = mStreams.get(resId);
- try {
- if (mp == null || !mp.isPlaying()) {
- restart = true;
- }
- } catch (IllegalStateException e) {
- // Media player was not initialised or was released
- restart = true;
- }
-
- if (restart) {
- stopAll();
- playTrack(resId, loop);
- }
- }
-
- private void startMedia(MediaPlayer mp) {
- if (mMuted) {
- mp.setVolume(0f, 0f);
- } else {
- mp.setVolume(VOLUME_MULTIPLIER, VOLUME_MULTIPLIER);
- }
- mp.start();
- }
-
- public void stop(int resId) {
- MediaPlayer mp = mStreams.get(resId);
- if (mp != null) {
- mp.stop();
- mp.release();
- mStreams.remove(resId);
- }
- }
-
- public void muteAll() {
- mMuted = true;
- for (int i = 0; i < mStreams.size(); i++) {
- mStreams.valueAt(i).setVolume(0f, 0f);
- }
- }
-
- public void unMuteAll() {
- mMuted = false;
- for (int i = 0; i < mStreams.size(); i++) {
- mStreams.valueAt(i).setVolume(VOLUME_MULTIPLIER, VOLUME_MULTIPLIER);
- }
- }
-
- public void pauseAll() {
- for (int i = 0; i < mStreams.size(); i++) {
- mStreams.valueAt(i).pause();
- }
- }
-
- public void resumeAll() {
- for (int i = 0; i < mStreams.size(); i++) {
- startMedia(mStreams.valueAt(i));
- }
- }
-
- public void stopAll() {
- // Stop all audio
- for (int i = 0; i < mStreams.size(); i++) {
- MediaPlayer mp = mStreams.valueAt(i);
- mp.release();
- mStreams.removeAt(i);
- }
- }
-}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/AudioPlayer.kt b/common/src/main/java/com/google/android/apps/santatracker/AudioPlayer.kt
new file mode 100644
index 000000000..3017eef38
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/AudioPlayer.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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
+
+import android.content.Context
+import android.media.MediaPlayer
+import android.util.SparseArray
+
+class AudioPlayer(private val context: Context) {
+ private val streams: SparseArray = SparseArray()
+ private var muted = false
+
+ fun playTrack(resId: Int, loop: Boolean) {
+ val mediaPlayer = MediaPlayer.create(context, resId)
+ // Not all devices support audio (i.e. watches)
+ if (mediaPlayer != null) {
+ streams.put(resId, mediaPlayer)
+ mediaPlayer.isLooping = loop
+ mediaPlayer.setOnPreparedListener { mp -> startMedia(mp) }
+ mediaPlayer.setOnCompletionListener { mp ->
+ if (!mp.isLooping) {
+ mp.release()
+ streams.remove(resId)
+ }
+ }
+ }
+ }
+
+ fun playTrackExclusive(resId: Int, loop: Boolean) {
+ var restart = false
+ val mp = streams.get(resId)
+ try {
+ if (mp == null || !mp.isPlaying) {
+ restart = true
+ }
+ } catch (e: IllegalStateException) {
+ // Media player was not initialised or was released
+ restart = true
+ }
+
+ if (restart) {
+ stopAll()
+ playTrack(resId, loop)
+ }
+ }
+
+ private fun startMedia(mp: MediaPlayer) {
+ if (muted) {
+ mp.setVolume(0f, 0f)
+ } else {
+ mp.setVolume(AudioConstants.DEFAULT_BACKGROUND_VOLUME,
+ AudioConstants.DEFAULT_BACKGROUND_VOLUME)
+ }
+ mp.start()
+ }
+
+ fun stop(resId: Int) {
+ val mp = streams.get(resId)
+ if (mp != null) {
+ mp.stop()
+ mp.release()
+ streams.remove(resId)
+ }
+ }
+
+ fun stopAll() {
+ // Stop all audio
+ for (i in 0 until streams.size()) {
+ val mp = streams.valueAt(i)
+ if (mp != null) {
+ mp.stop()
+ mp.release()
+ streams.removeAt(i)
+ }
+ }
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/Intents.kt b/common/src/main/java/com/google/android/apps/santatracker/Intents.kt
new file mode 100644
index 000000000..14d8ec896
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/Intents.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+
+object Intents {
+ private const val PACKAGE = "com.google.android.apps.santatracker.messaging"
+ // These variable names below are usually named XXX_ACTION, but naming as XXX_INTENT to tell
+ // the difference from the ACTION_XXXX for FCM
+ const val SYNC_CONFIG_INTENT = "$PACKAGE.SYNC_CONFIG"
+ const val SYNC_ROUTE_INTENT = "$PACKAGE.SYNC_ROUTE"
+ const val FINISH_TRACKER_INTENT = "$PACKAGE.FINISH_TRACKER"
+
+ /** URL for YouTube video IDs. */
+ private const val VIDEO_URL = "https://www.youtube.com/watch?v=%s"
+
+ /**
+ * Constructs an Intent that plays back a YouTube video. If the YouTube app is installed, the
+ * video will be played back directly in full screen mode. if the YouTube app is not available
+ * (e.g. not installed or disabled), the video is launched in a browser instead.
+ *
+ * @param videoId YouTube Video id.
+ */
+ @JvmStatic
+ fun getYoutubeIntent(context: Context, videoId: String): Intent {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("vnd.youtube://$videoId")
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ putExtra("force_fullscreen", true)
+ }
+
+ val resolvers = context.packageManager.queryIntentActivities(intent, 0) ?: emptyList()
+ return if (resolvers.isNotEmpty()) {
+ // Devices with YouTube installed will get the native full-screen player
+ intent
+ } else {
+ // If YouTube is not available, load open the video in the browser
+ Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse(VIDEO_URL.format(videoId))
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/com/google/android/apps/santatracker/common/CheckableImageButton.kt b/common/src/main/java/com/google/android/apps/santatracker/common/CheckableImageButton.kt
new file mode 100644
index 000000000..011862f17
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/common/CheckableImageButton.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.common
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.view.accessibility.AccessibilityEvent
+import android.widget.Checkable
+import androidx.appcompat.widget.AppCompatImageButton
+import androidx.core.view.AccessibilityDelegateCompat
+import androidx.core.view.ViewCompat
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
+
+class CheckableImageButton @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = androidx.appcompat.R.attr.imageButtonStyle
+) : AppCompatImageButton(context, attrs, defStyleAttr), Checkable {
+
+ private var _checked: Boolean = false
+ set(value) {
+ if (value != field) {
+ refreshDrawableState()
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)
+ }
+ field = value
+ }
+
+ init {
+ ViewCompat.setAccessibilityDelegate(
+ this,
+ object : AccessibilityDelegateCompat() {
+ override fun onInitializeAccessibilityEvent(host: View, event: AccessibilityEvent) {
+ super.onInitializeAccessibilityEvent(host, event)
+ event.isChecked = isChecked
+ }
+
+ override fun onInitializeAccessibilityNodeInfo(
+ host: View,
+ info: AccessibilityNodeInfoCompat
+ ) {
+ super.onInitializeAccessibilityNodeInfo(host, info)
+ info.isCheckable = true
+ info.isChecked = isChecked
+ }
+ })
+ }
+
+ override fun setChecked(checked: Boolean) {
+ _checked = checked
+ }
+
+ override fun isChecked(): Boolean {
+ return _checked
+ }
+
+ override fun toggle() {
+ _checked = !_checked
+ }
+
+ override fun onCreateDrawableState(extraSpace: Int): IntArray {
+ return if (_checked) {
+ View.mergeDrawableStates(
+ super.onCreateDrawableState(extraSpace + DRAWABLE_STATE_CHECKED.size),
+ DRAWABLE_STATE_CHECKED)
+ } else {
+ super.onCreateDrawableState(extraSpace)
+ }
+ }
+
+ companion object {
+ private val DRAWABLE_STATE_CHECKED = intArrayOf(android.R.attr.state_checked)
+ }
+}
\ No newline at end of file
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
deleted file mode 100644
index e2f02d079..000000000
--- a/common/src/main/java/com/google/android/apps/santatracker/common/NotificationConstants.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * 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.common;
-
-/**
- * Constants that are used in both the Application and the Wearable modules.
- */
-public final class NotificationConstants {
-
- public static final String KEY_LOCATION = "location";
-
- private NotificationConstants() {};
-
- // Only one ID because we only show one notification at a time.
- 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";
- public static final String KEY_NOTIFICATION_TYPE = "notification-type";
- public static final String KEY_TITLE = "title";
- public static final String KEY_CONTENT = "content";
- public static final String KEY_LOCATION_PHOTO = "location-photo";
- public static final String KEY_LOCATION_MAP = "location-map";
- public static final String KEY_LOCATION_FACT = "location-fact";
- public static final String KEY_TIMESTAMP = "timestap";
- public static final String KEY_FINAL_ARRIVAL = "finalArrival";
- public static final String KEY_FACT = "fact";
- public static final String KEY_STATUS = "status";
- public static final String KEY_IMAGEURL = "imageurl";
-
- public static final String ACTION_DISMISS
- = "com.google.android.apps.santatracker.DISMISS";
-
- public static final String ACTION_SEND
- = "com.google.android.apps.santatracker.SEND";
-}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/common/NotificationConstants.kt b/common/src/main/java/com/google/android/apps/santatracker/common/NotificationConstants.kt
new file mode 100644
index 000000000..a526a53e0
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/common/NotificationConstants.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.common
+
+/** Constants that are used in both the Application and the Wearable modules. */
+object NotificationConstants {
+ const val CHANNEL_ID = "santa-general"
+
+ // Only one ID because we only show one notification at a time.
+ const val NOTIFICATION_ID = 9876435
+
+ const val NOTIFICATION_TAKEOFF = 1
+
+ const val TAKEOFF_PATH = "/takeoff"
+ const val KEY_NOTIFICATION_ID = "notification-id"
+ const val KEY_NOTIFICATION_TYPE = "notification-type"
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/common/TitleTextView.kt b/common/src/main/java/com/google/android/apps/santatracker/common/TitleTextView.kt
new file mode 100644
index 000000000..ac0f14f31
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/common/TitleTextView.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.common
+
+import android.content.Context
+import android.graphics.Rect
+import android.os.Build
+import android.text.Layout
+import android.text.Spannable
+import android.text.method.TransformationMethod
+import android.util.AttributeSet
+import android.view.View
+import android.widget.TextView
+import androidx.appcompat.widget.AppCompatTextView
+import androidx.core.os.LocaleListCompat
+
+/**
+ * A special version of [AppCompatTextView] that replaces spaces with line breaks in order to
+ * explicitly adjust the position of line breaks. Currently, this behavior is only for Japanese and
+ * Korean. In other locales, this view only sets [Layout.BREAK_STRATEGY_HIGH_QUALITY].
+ */
+class TitleTextView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) :
+ AppCompatTextView(context, attrs, defStyleAttr) {
+
+ init {
+ if (Build.VERSION.SDK_INT >= 23) {
+ breakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY
+ }
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ val tags = LocaleListCompat.getAdjustedDefault().toLanguageTags()
+ if (tags.startsWith("ja") || tags.startsWith("ko")) {
+ transformationMethod = TitleTransformationMethod(w)
+ }
+ }
+
+ private class TitleTransformationMethod internal constructor(private val mWidth: Int) :
+ TransformationMethod {
+
+ override fun getTransformation(source: CharSequence, view: View): CharSequence {
+ if (source is Spannable) {
+ return source
+ }
+ val builder = StringBuilder()
+ val textView = view as TextView
+ val paint = textView.paint
+ var head = 0
+ var tail = 0 // The position of the last possible line break
+ val length = source.length
+ for (i in 0 until length) {
+ val c = source[i]
+ if (isLineBreak(c)) {
+ if (mWidth < Layout.getDesiredWidth(source, head, i, paint)) { // Don't fit
+ if (head == tail) { // This chunk of text is too long to fit in one line
+ // Just give up and let the system handle it
+ return source
+ } else {
+ builder.append(source, head, tail)
+ builder.append('\n')
+ tail += 1
+ head = tail
+ }
+ } else {
+ tail = i
+ }
+ }
+ }
+ if (mWidth < Layout.getDesiredWidth(source, head, length, paint) && head < tail) {
+ builder.append(source, head, tail)
+ builder.append('\n')
+ head = tail + 1
+ }
+ builder.append(source, head, length)
+ return builder
+ }
+
+ private fun isLineBreak(c: Char): Boolean {
+ return c == ' '
+ }
+
+ override fun onFocusChanged(
+ view: View,
+ sourceText: CharSequence,
+ focused: Boolean,
+ direction: Int,
+ previouslyFocusedRect: Rect
+ ) {
+ // Do nothing
+ }
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/config/BooleanConfigParam.kt b/common/src/main/java/com/google/android/apps/santatracker/config/BooleanConfigParam.kt
new file mode 100644
index 000000000..042d2da9c
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/config/BooleanConfigParam.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.config
+
+/** Boolean configuration value. */
+class BooleanConfigParam(key: String) : ConfigParam(key) {
+
+ override fun getValue(config: Config): Boolean {
+ config.firebaseRemoteConfig.getValue(key)
+ return config.firebaseRemoteConfig.getBoolean(key)
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/config/Config.kt b/common/src/main/java/com/google/android/apps/santatracker/config/Config.kt
new file mode 100644
index 000000000..8c74488a0
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/config/Config.kt
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.config
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import androidx.annotation.VisibleForTesting
+import com.google.android.apps.santatracker.common.BuildConfig
+import com.google.android.apps.santatracker.common.R
+import com.google.android.apps.santatracker.data.WebSceneState
+import com.google.android.apps.santatracker.data.webSceneState
+import com.google.android.apps.santatracker.util.SantaLog
+import com.google.android.gms.tasks.Task
+import com.google.android.gms.tasks.Tasks
+import com.google.firebase.remoteconfig.FirebaseRemoteConfig
+import com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchThrottledException
+import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings
+import java.util.ArrayList
+import java.util.concurrent.TimeUnit
+
+/**
+ * Wrapper class for accessing Firebase Remote Config. Making it open because we want it to be
+ * mocked in tests.
+ */
+open class Config {
+ open val firebaseRemoteConfig: FirebaseRemoteConfig = FirebaseRemoteConfig.getInstance().apply {
+ setConfigSettings(CONFIG_SETTINGS)
+ setDefaults(R.xml.remote_config_defaults)
+ }
+
+ private val configCacheExpiry: Long
+ private var throttleEndTimeMillis: Long = 0
+
+ open val takeoffTimeMs: Long
+ get() = get(SANTA_TAKEOFF) * 1000
+
+ open val arrivalTimeMs: Long
+ get() = get(SANTA_ARRIVAL) * 1000
+
+ init {
+ // Set cache expiration to 0s when debugging to allow easy testing, otherwise
+ // use the default value
+ configCacheExpiry = if (CONFIG_SETTINGS.isDeveloperModeEnabled) {
+ 0
+ } else {
+ DEFAULT_CACHE_EXPIRY_S
+ }
+ }
+
+ @SuppressLint("VisibleForTests")
+ @VisibleForTesting
+ open operator fun get(param: ConfigParam): T {
+ return param.getValue(this)
+ }
+
+ /**
+ * Sync the config values with Firebase Remote Config asynchronously.
+ *
+ * @param paramChangedCallback the callback when any of [ConfigParam]s are changed.
+ */
+ open fun syncConfigAsync(paramChangedCallback: ParamChangedCallback?) {
+ val currentTime = System.currentTimeMillis()
+ if (currentTime > throttleEndTimeMillis) {
+ val getConfigTask = firebaseRemoteConfig.fetch(configCacheExpiry)
+
+ getConfigTask.addOnCompleteListener { task ->
+ onTaskCompleted(task, paramChangedCallback)
+ }
+ } else {
+ val msRemaining = throttleEndTimeMillis - currentTime
+ SantaLog.d(TAG, "Not trying config, throttled for " + msRemaining + "ms")
+ }
+ }
+
+ fun syncConfig() {
+ val currentTime = System.currentTimeMillis()
+ if (currentTime > throttleEndTimeMillis) {
+ val task = firebaseRemoteConfig.fetch(configCacheExpiry)
+ Tasks.await(task, 60, TimeUnit.SECONDS)
+ } else {
+ val msRemaining = throttleEndTimeMillis - currentTime
+ SantaLog.d(TAG, "Not trying config, throttled for " + msRemaining + "ms")
+ }
+ }
+
+ private fun onTaskCompleted(
+ getConfigTask: Task,
+ paramChangedCallback: ParamChangedCallback?
+ ) {
+ if (getConfigTask.isSuccessful) {
+ SantaLog.d(TAG, "fetchConfig:SUCCESS")
+
+ val oldParams = Bundle()
+ for (param in ALL_LONG_PARAMS) {
+ oldParams.putLong(param.key, param.getValue(this))
+ }
+ for (param in ALL_STRING_PARAMS) {
+ oldParams.putString(param.key, param.getValue(this))
+ }
+ for (param in ALL_BOOLEAN_PARAMS) {
+ oldParams.putBoolean(param.key, param.getValue(this))
+ }
+ val oldWebSceneState = webSceneState()
+
+ // Activate config and notify clients of any changes
+ firebaseRemoteConfig.activateFetched()
+ val changedKeys = getChangedKeys(oldParams, oldWebSceneState)
+ if (changedKeys.isNotEmpty() && paramChangedCallback != null) {
+ paramChangedCallback.onChanged(changedKeys)
+ }
+ } else {
+ val e = getConfigTask.exception
+ if (e is FirebaseRemoteConfigFetchThrottledException) {
+ // Store throttle end time
+ val ex = e as FirebaseRemoteConfigFetchThrottledException?
+ throttleEndTimeMillis = ex!!.throttleEndTimeMillis
+ SantaLog.w(TAG, "fetchConfig:THROTTLED until $throttleEndTimeMillis")
+ } else {
+ SantaLog.w(TAG, "fetchConfig:UNEXPECTED_ERROR", e!!)
+ }
+ }
+ }
+
+ /**
+ * @return a list of String representing key names of the parameters changed from the previous
+ * values. Returns an empty list if nothing changed.
+ */
+ private fun getChangedKeys(oldParams: Bundle, oldWebSceneState: WebSceneState): List {
+ val changedParamsKeys = ArrayList()
+ for (param in ALL_LONG_PARAMS) {
+ if (oldParams.getLong(param.key) != param.getValue(this)) {
+ changedParamsKeys.add(param.key)
+ }
+ }
+ for (param in ALL_STRING_PARAMS) {
+ val oldValue = oldParams.getString(param.key)
+ if (oldValue != null && oldValue != param.getValue(this)) {
+ changedParamsKeys.add(param.key)
+ }
+ }
+ for (param in ALL_BOOLEAN_PARAMS) {
+ if (oldParams.getBoolean(param.key) != param.getValue(this)) {
+ changedParamsKeys.add(param.key)
+ }
+ }
+ val newWebSceneState = webSceneState()
+ if (oldWebSceneState != newWebSceneState) {
+ changedParamsKeys.add(WebConfig.WEBCONFIG)
+ }
+ return changedParamsKeys
+ }
+
+ /** Interface for a callback when any of config values are changed from the previous values. */
+ interface ParamChangedCallback {
+ /**
+ * Called when any of parameters are changed from the previous values.
+ *
+ * @param changedKeys has the list of key names whose values are changed from the previous
+ * values.
+ */
+ fun onChanged(changedKeys: List)
+ }
+
+ companion object {
+ private const val TAG = "Config"
+
+ // Santa kill switch
+ val DISABLE_SANTA = BooleanConfigParam("DisableSanta")
+
+ // Game kill switches
+ val DISABLE_CASTBUTTON = BooleanConfigParam("DisableCastButton")
+ val DISABLE_PHOTO = BooleanConfigParam("DisableDestinationPhoto")
+ val DISABLE_GUMBALLGAME = BooleanConfigParam("DisableGumballGame")
+ val DISABLE_JETPACKGAME = BooleanConfigParam("DisableJetpackGame")
+ val DISABLE_MEMORYGAME = BooleanConfigParam("DisableMemoryGame")
+ val DISABLE_ROCKETGAME = BooleanConfigParam("DisableRocketGame")
+ val DISABLE_DANCERGAME = BooleanConfigParam("DisableDancerGame")
+ val DISABLE_SWIMMINGGAME = BooleanConfigParam("DisableSwimmingGame")
+ val DISABLE_BMXGAME = BooleanConfigParam("DisableBmxGame")
+ val DISABLE_RUNNINGGAME = BooleanConfigParam("DisableRunningGame")
+ val DISABLE_TENNISGAME = BooleanConfigParam("DisableTennisGame")
+ val DISABLE_WATERPOLOGAME = BooleanConfigParam("DisableWaterpoloGame")
+ val DISABLE_CITY_QUIZ = BooleanConfigParam("DisableCityQuiz")
+ val DISABLE_PRESENTQUEST = BooleanConfigParam("DisablePresentQuest")
+ val DISABLE_SANTA_SNAP = BooleanConfigParam("DisableSantaSnap")
+ val DISABLE_PRESENT_THROW = BooleanConfigParam("DisablePresentThrow")
+
+ // YouTube video IDs
+ val VIDEO_1 = StringConfigParam("Video1")
+ val VIDEO_15 = StringConfigParam("Video15")
+ val VIDEO_23 = StringConfigParam("Video23")
+
+ // Unlock times
+ @JvmField val SANTA_TAKEOFF = LongConfigParam("SantaTakeoff")
+ @JvmField val SANTA_ARRIVAL = LongConfigParam("SantaArrival")
+ @JvmField val UNLOCK_GUMBALL = LongConfigParam("UnlockGumball")
+ @JvmField val UNLOCK_MEMORY = LongConfigParam("UnlockMemory")
+ @JvmField val UNLOCK_ROCKET = LongConfigParam("UnlockRocket")
+ @JvmField val UNLOCK_DANCER = LongConfigParam("UnlockDancer")
+ @JvmField val UNLOCK_CITYQUIZ = LongConfigParam("UnlockCityQuiz")
+ @JvmField val UNLOCK_VIDEO_1 = LongConfigParam("UnlockVideo1")
+ @JvmField val UNLOCK_VIDEO_15 = LongConfigParam("UnlockVideo15")
+ @JvmField val UNLOCK_VIDEO_23 = LongConfigParam("UnlockVideo23")
+ @JvmField val UNLOCK_JETPACK = LongConfigParam("UnlockJetpack")
+ @JvmField val UNLOCK_PRESENT_THROW = LongConfigParam("UnlockPresentThrow")
+
+ // Game isFeatured switches
+ val FEATURE_GUMBALLGAME = BooleanConfigParam("FeatureGumballGame")
+ val FEATURE_JETPACKGAME = BooleanConfigParam("FeatureJetpackGame")
+ val FEATURE_MEMORYGAME = BooleanConfigParam("FeatureMemoryGame")
+ val FEATURE_ROCKETGAME = BooleanConfigParam("FeatureRocketGame")
+ val FEATURE_DANCERGAME = BooleanConfigParam("FeatureDancerGame")
+ val FEATURE_SWIMMINGGAME = BooleanConfigParam("FeatureSwimmingGame")
+ val FEATURE_BMXGAME = BooleanConfigParam("FeatureBmxGame")
+ val FEATURE_RUNNINGGAME = BooleanConfigParam("FeatureRunningGame")
+ val FEATURE_TENNISGAME = BooleanConfigParam("FeatureTennisGame")
+ val FEATURE_WATERPOLOGAME = BooleanConfigParam("FeatureWaterpoloGame")
+ val FEATURE_CITY_QUIZ = BooleanConfigParam("FeatureCityQuiz")
+ val FEATURE_PRESENTQUEST = BooleanConfigParam("FeaturePresentQuest")
+ val FEATURE_SANTA_SNAP = BooleanConfigParam("FeatureSantaSnap")
+ val FEATURE_PRESENT_THROW = BooleanConfigParam("FeaturePresentThrow")
+
+ val STICKERS_CONFIG_URL = StringConfigParam("StickersConfigUrl")
+
+ // Time offset
+ val TIME_OFFSET = LongConfigParam("TimeOffset")
+
+ val WEB_SCENES = WebConfig()
+
+ // Array of params related to tracker
+ val ALL_PARAMS_TRACKER = arrayOf(
+ TIME_OFFSET, DISABLE_SANTA, DISABLE_CASTBUTTON, DISABLE_PHOTO
+ )
+
+ // Array of all String params
+ private val ALL_STRING_PARAMS = arrayOf(VIDEO_1, VIDEO_15, VIDEO_23)
+
+ // Array of all Boolean params
+ private val ALL_BOOLEAN_PARAMS = arrayOf(
+ DISABLE_SANTA, DISABLE_CASTBUTTON, DISABLE_PHOTO, DISABLE_GUMBALLGAME,
+ FEATURE_GUMBALLGAME, DISABLE_JETPACKGAME, FEATURE_JETPACKGAME,
+ DISABLE_MEMORYGAME, FEATURE_MEMORYGAME, DISABLE_ROCKETGAME,
+ FEATURE_ROCKETGAME, DISABLE_DANCERGAME, FEATURE_DANCERGAME,
+ DISABLE_SWIMMINGGAME, FEATURE_SWIMMINGGAME, DISABLE_BMXGAME,
+ FEATURE_BMXGAME, DISABLE_RUNNINGGAME, FEATURE_RUNNINGGAME,
+ DISABLE_TENNISGAME, FEATURE_TENNISGAME, DISABLE_WATERPOLOGAME,
+ FEATURE_WATERPOLOGAME, DISABLE_CITY_QUIZ, FEATURE_CITY_QUIZ,
+ DISABLE_PRESENTQUEST, FEATURE_PRESENTQUEST, DISABLE_SANTA_SNAP,
+ FEATURE_SANTA_SNAP, DISABLE_PRESENT_THROW, FEATURE_PRESENT_THROW
+ )
+
+ // Array of all Long params
+ private val ALL_LONG_PARAMS = arrayOf(
+ SANTA_TAKEOFF, SANTA_ARRIVAL, UNLOCK_GUMBALL, UNLOCK_MEMORY, UNLOCK_JETPACK,
+ UNLOCK_ROCKET, UNLOCK_DANCER, UNLOCK_CITYQUIZ, UNLOCK_VIDEO_1,
+ UNLOCK_VIDEO_15, UNLOCK_VIDEO_23, TIME_OFFSET, UNLOCK_PRESENT_THROW
+ )
+
+ private const val DEFAULT_CACHE_EXPIRY_S = (60 * 12).toLong() // 5 requests / h
+
+ private val CONFIG_SETTINGS = FirebaseRemoteConfigSettings.Builder()
+ .setDeveloperModeEnabled(BuildConfig.DEBUG)
+ .build()
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/config/ConfigParam.kt b/common/src/main/java/com/google/android/apps/santatracker/config/ConfigParam.kt
new file mode 100644
index 000000000..2e3bbd797
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/config/ConfigParam.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.config
+
+/** Configuration value, shared between network config (Firebase) and local cache (Shared Prefs). */
+abstract class ConfigParam(val key: String) {
+ abstract fun getValue(config: Config): T
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/config/LongConfigParam.kt b/common/src/main/java/com/google/android/apps/santatracker/config/LongConfigParam.kt
new file mode 100644
index 000000000..b69439d27
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/config/LongConfigParam.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.config
+
+/** Long config param. */
+class LongConfigParam(key: String) : ConfigParam(key) {
+ override fun getValue(config: Config): Long = config.firebaseRemoteConfig.getLong(key)
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/config/StringConfigParam.kt b/common/src/main/java/com/google/android/apps/santatracker/config/StringConfigParam.kt
new file mode 100644
index 000000000..df48b8cbb
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/config/StringConfigParam.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.config
+
+/** String configuration value. */
+class StringConfigParam(key: String) : ConfigParam(key) {
+ override fun getValue(config: Config): String = config.firebaseRemoteConfig.getString(key)
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/config/WebConfig.kt b/common/src/main/java/com/google/android/apps/santatracker/config/WebConfig.kt
new file mode 100644
index 000000000..0e21ef133
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/config/WebConfig.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.config
+
+class WebConfig {
+ companion object {
+ const val WEBCONFIG = "WEBCONFIG"
+ const val AIRPORT = "AIRPORT"
+ const val BOATLOAD = "BOATLOAD"
+ const val CLAUSDRAWS = "CLAUSDRAWS"
+ const val CODEBOOGIE = "CODEBOOGIE"
+ const val CODELAB = "CODELAB"
+ const val ELFSKI = "ELFSKI"
+ const val GUMBALL = "GUMBALL"
+ const val JAMBAND = "JAMBAND"
+ const val PENGUINDASH = "PENGUINDASH"
+ const val PRESENTBOUNCE = "PRESENTBOUNCE"
+ const val PRESENTDROP = "PRESENTDROP"
+ const val RACER = "RACER"
+ const val RUNNER = "RUNNER"
+ const val SANTASEARCH = "SANTASEARCH"
+ const val SANTASELFIE = "SANTASELFIE"
+ const val SEASONOFGIVING = "SEASONOFGIVING"
+ const val SNOWBALL = "SNOWBALL"
+ const val SNOWFLAKE = "SNOWFLAKE"
+ const val SPEEDSKETCH = "SPEEDSKETCH"
+ const val WRAPBATTLE = "WRAPBATTLE"
+ const val ELFMAKER = "ELFMAKER"
+ }
+
+ val SCENE_CONFIG = hashMapOf(
+ AIRPORT to WebConfigScene("WebAirport"),
+ BOATLOAD to WebConfigScene("WebBoatload"),
+ CLAUSDRAWS to WebConfigScene("WebClausdraws"),
+ CODEBOOGIE to WebConfigScene("WebCodeboogie"),
+ CODELAB to WebConfigScene("WebCodelab"),
+ ELFSKI to WebConfigScene("WebElfski"),
+ GUMBALL to WebConfigScene("WebGumball"),
+ JAMBAND to WebConfigScene("WebJamband"),
+ PENGUINDASH to WebConfigScene("WebPenguindash"),
+ PRESENTBOUNCE to WebConfigScene("WebPresentbounce"),
+ PRESENTDROP to WebConfigScene("WebPresentdrop"),
+ RACER to WebConfigScene("WebRacer"),
+ RUNNER to WebConfigScene("WebRunner"),
+ SANTASEARCH to WebConfigScene("WebSantasearch"),
+ SANTASELFIE to WebConfigScene("WebSantaselfie"),
+ SEASONOFGIVING to WebConfigScene("WebSeasonofgiving"),
+ SNOWBALL to WebConfigScene("WebSnowball"),
+ SNOWFLAKE to WebConfigScene("WebSnowflake"),
+ SPEEDSKETCH to WebConfigScene("WebSpeedsketch"),
+ WRAPBATTLE to WebConfigScene("WebWrapbattle"),
+ ELFMAKER to WebConfigScene("WebElfMaker")
+ )
+}
+
+class WebConfigScene(
+ featuredFlagName: String,
+ disabledFlagName: String,
+ landscapeFlagName: String,
+ urlFlagName: String,
+ cardImageUrlFlagName: String? = null
+) {
+ constructor(prefix: String) : this(
+ featuredFlagName = "${prefix}Featured",
+ disabledFlagName = "${prefix}Disabled",
+ landscapeFlagName = "${prefix}Landscape",
+ urlFlagName = "${prefix}Url",
+ cardImageUrlFlagName = "${prefix}CardImageUrl"
+ )
+
+ val configFeatured = BooleanConfigParam(featuredFlagName)
+ val configDisabled = BooleanConfigParam(disabledFlagName)
+ val configLandscape = BooleanConfigParam(landscapeFlagName)
+ val configUrl = StringConfigParam(urlFlagName)
+ val configCardImageUrl = cardImageUrlFlagName?.let { StringConfigParam(it) }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/data/FeatureState.kt b/common/src/main/java/com/google/android/apps/santatracker/data/FeatureState.kt
new file mode 100644
index 000000000..b1e94bbb8
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/data/FeatureState.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.data
+
+import com.google.android.apps.santatracker.config.Config
+
+/** State for non-video non-game feature flags. */
+data class FeatureState(
+ val santaDisabled: Boolean,
+ val castDisabled: Boolean,
+ val photoDisabled: Boolean
+)
+
+fun featureStateFromConfig(config: Config) = FeatureState(
+ Config.DISABLE_SANTA.getValue(config),
+ Config.DISABLE_CASTBUTTON.getValue(config),
+ Config.DISABLE_PHOTO.getValue(config)
+)
+
+fun Config.featureState() = featureStateFromConfig(this)
\ No newline at end of file
diff --git a/common/src/main/java/com/google/android/apps/santatracker/data/GameState.kt b/common/src/main/java/com/google/android/apps/santatracker/data/GameState.kt
new file mode 100644
index 000000000..b1c0f2fd6
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/data/GameState.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.data
+
+import com.google.android.apps.santatracker.config.Config
+
+/** Disabled state of each game. */
+data class GameState(
+ var disableGumballGame: Boolean = false,
+ var disableJetpackGame: Boolean = false,
+ var disableMemoryGame: Boolean = false,
+ var disableRocketGame: Boolean = false,
+ var disableDancerGame: Boolean = false,
+ var disableSwimmingGame: Boolean = false,
+ var disableBmxGame: Boolean = false,
+ var disableRunningGame: Boolean = false,
+ var disableTennisGame: Boolean = false,
+ var disableWaterpoloGame: Boolean = false,
+ var disableCityQuizGame: Boolean = false,
+ var disablePresentQuest: Boolean = false,
+ var disableSantaSnap: Boolean = false,
+ var disablePresentThrow: Boolean = false,
+ var featureGumballGame: Boolean = false,
+ var featureJetpackGame: Boolean = false,
+ var featureMemoryGame: Boolean = false,
+ var featureRocketGame: Boolean = false,
+ var featureDancerGame: Boolean = false,
+ var featureSwimmingGame: Boolean = false,
+ var featureBmxGame: Boolean = false,
+ var featureRunningGame: Boolean = false,
+ var featureTennisGame: Boolean = false,
+ var featureWaterpoloGame: Boolean = false,
+ var featureCityQuizGame: Boolean = false,
+ var featurePresentQuest: Boolean = false,
+ var featureSantaSnap: Boolean = false,
+ var featurePresentThrow: Boolean = false
+)
+
+fun gameStateFromConfig(config: Config) = GameState(
+ disableGumballGame = Config.DISABLE_GUMBALLGAME.getValue(config),
+ disableJetpackGame = Config.DISABLE_JETPACKGAME.getValue(config),
+ disableMemoryGame = Config.DISABLE_MEMORYGAME.getValue(config),
+ disableRocketGame = Config.DISABLE_ROCKETGAME.getValue(config),
+ disableDancerGame = Config.DISABLE_DANCERGAME.getValue(config),
+ disableSwimmingGame = Config.DISABLE_SWIMMINGGAME.getValue(config),
+ disableBmxGame = Config.DISABLE_BMXGAME.getValue(config),
+ disableRunningGame = Config.DISABLE_RUNNINGGAME.getValue(config),
+ disableTennisGame = Config.DISABLE_TENNISGAME.getValue(config),
+ disableWaterpoloGame = Config.DISABLE_WATERPOLOGAME.getValue(config),
+ disableCityQuizGame = Config.DISABLE_CITY_QUIZ.getValue(config),
+ disablePresentQuest = Config.DISABLE_PRESENTQUEST.getValue(config),
+ disableSantaSnap = Config.DISABLE_SANTA_SNAP.getValue(config),
+ disablePresentThrow = Config.DISABLE_PRESENT_THROW.getValue(config),
+ featureGumballGame = Config.FEATURE_GUMBALLGAME.getValue(config),
+ featureJetpackGame = Config.FEATURE_JETPACKGAME.getValue(config),
+ featureMemoryGame = Config.FEATURE_MEMORYGAME.getValue(config),
+ featureRocketGame = Config.FEATURE_ROCKETGAME.getValue(config),
+ featureDancerGame = Config.FEATURE_DANCERGAME.getValue(config),
+ featureSwimmingGame = Config.FEATURE_SWIMMINGGAME.getValue(config),
+ featureBmxGame = Config.FEATURE_BMXGAME.getValue(config),
+ featureRunningGame = Config.FEATURE_RUNNINGGAME.getValue(config),
+ featureTennisGame = Config.FEATURE_TENNISGAME.getValue(config),
+ featureWaterpoloGame = Config.FEATURE_WATERPOLOGAME.getValue(config),
+ featureCityQuizGame = Config.FEATURE_CITY_QUIZ.getValue(config),
+ featurePresentQuest = Config.FEATURE_PRESENTQUEST.getValue(config),
+ featureSantaSnap = Config.FEATURE_SANTA_SNAP.getValue(config),
+ featurePresentThrow = Config.FEATURE_PRESENT_THROW.getValue(config)
+)
+
+fun Config.gameState() = gameStateFromConfig(this)
\ No newline at end of file
diff --git a/common/src/main/java/com/google/android/apps/santatracker/data/SantaPreferences.kt b/common/src/main/java/com/google/android/apps/santatracker/data/SantaPreferences.kt
new file mode 100644
index 000000000..4fc74899c
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/data/SantaPreferences.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.data
+
+import android.annotation.SuppressLint
+import android.content.Context
+
+/** Singleton that manages access to internal data stored as preferences. */
+@SuppressLint("CommitPrefEdits")
+class SantaPreferences(context: Context) {
+ private val settings = context.getSharedPreferences(PREFERENCES_FILENAME, Context.MODE_PRIVATE)
+
+ var offset: Long
+ get() = dateOffset
+ set(value) {
+ // We have to use commit() here so that the value is updated immediately
+ settings.edit().putLong(PREF_OFFSET, value).apply()
+ dateOffset = value
+ }
+
+ var isMuted: Boolean = settings.getBoolean(PREF_MUTED, false)
+ set(value) {
+ settings.edit().putBoolean(PREF_MUTED, value).apply()
+ field = value
+ }
+
+ fun toggleMuted() {
+ isMuted = !isMuted
+ }
+
+ init {
+ dateOffset = settings.getLong(PREF_OFFSET, 0)
+ }
+
+ companion object {
+ // Shared time offset this is used only for the debug build
+ private var dateOffset = 0L
+
+ private const val PREFERENCES_FILENAME = "SantaTracker"
+ private const val PREF_OFFSET = "PREF_OFFSET"
+ private const val PREF_MUTED = "PREF_MUTED"
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/data/VideoState.kt b/common/src/main/java/com/google/android/apps/santatracker/data/VideoState.kt
new file mode 100644
index 000000000..83a6319be
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/data/VideoState.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.data
+
+import com.google.android.apps.santatracker.config.Config
+
+/** Configuration for video URLs. */
+data class VideoState(
+ val video1: String? = null,
+ val video15: String? = null,
+ val video23: String? = null
+)
+
+fun videoStateFromConfig(config: Config) = VideoState(
+ Config.VIDEO_1.getValue(config),
+ Config.VIDEO_15.getValue(config),
+ Config.VIDEO_23.getValue(config)
+)
+
+fun Config.videoState() = videoStateFromConfig(this)
diff --git a/common/src/main/java/com/google/android/apps/santatracker/data/WebSceneState.kt b/common/src/main/java/com/google/android/apps/santatracker/data/WebSceneState.kt
new file mode 100644
index 000000000..6462a95c5
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/data/WebSceneState.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.data
+
+import com.google.android.apps.santatracker.config.Config
+
+data class WebSceneState(val scenes: Map = emptyMap()) {
+ data class WebScene(
+ val featured: Boolean,
+ val disabled: Boolean,
+ val landscape: Boolean,
+ val url: String,
+ val cardImageUrl: String?
+ )
+}
+
+fun webSceneStateFromConfig(config: Config) = WebSceneState(
+ Config.WEB_SCENES.SCENE_CONFIG.mapValues { (_, value) ->
+ WebSceneState.WebScene(
+ value.configFeatured.getValue(config),
+ value.configDisabled.getValue(config),
+ value.configLandscape.getValue(config),
+ value.configUrl.getValue(config),
+ value.configCardImageUrl?.getValue(config)
+ )
+ }
+)
+
+fun Config.webSceneState() = webSceneStateFromConfig(this)
\ No newline at end of file
diff --git a/common/src/main/java/com/google/android/apps/santatracker/games/FeatureLoadStateListener.kt b/common/src/main/java/com/google/android/apps/santatracker/games/FeatureLoadStateListener.kt
new file mode 100644
index 000000000..03db54f92
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/games/FeatureLoadStateListener.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.PendingIntent
+import android.content.IntentSender
+import com.google.android.apps.santatracker.util.SantaLog
+import com.google.android.play.core.splitinstall.SplitInstallManager
+import com.google.android.play.core.splitinstall.SplitInstallSessionState
+import com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener
+import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus.CANCELED
+import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus.DOWNLOADING
+import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus.FAILED
+import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus.INSTALLED
+import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus.INSTALLING
+import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus.PENDING
+import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION
+import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus.UNKNOWN
+
+/**
+ * Listener for loading dynamic feature modules on demand.
+ */
+abstract class FeatureLoadStateListener : SplitInstallStateUpdatedListener {
+
+ private var isRegistered = false
+
+ fun register(manager: SplitInstallManager) {
+ manager.registerListener(this)
+ isRegistered = true
+ }
+
+ fun unregister(manager: SplitInstallManager) {
+ if (isRegistered) {
+ manager.unregisterListener(this)
+ isRegistered = false
+ }
+ }
+
+ override fun onStateUpdate(state: SplitInstallSessionState) {
+ SantaLog.d(TAG, "onStateUpdate. Status: ${state.status()}")
+
+ when (state.status()) {
+ PENDING -> onPending()
+ REQUIRES_USER_CONFIRMATION -> requiresConfirmation(state)
+ DOWNLOADING -> onDownloading(state.bytesDownloaded(), state.totalBytesToDownload())
+ INSTALLING -> onInstalling()
+ INSTALLED -> onInstalled()
+ UNKNOWN or FAILED -> onFailure()
+ CANCELED -> onCanceled()
+ }
+ }
+
+ open fun onPending() = Unit
+
+ private fun requiresConfirmation(state: SplitInstallSessionState) {
+ val resolutionIntent: PendingIntent = state.resolutionIntent() ?: return
+ onRequiresConfirmation(resolutionIntent.intentSender)
+ }
+
+ abstract fun onRequiresConfirmation(intentSender: IntentSender)
+
+ abstract fun onDownloading(bytesDownloaded: Long, totalBytesToDownload: Long)
+
+ abstract fun onInstalling()
+
+ open fun onInstalled() = Unit
+
+ open fun onFailure() = Unit
+
+ open fun onCanceled() = Unit
+
+ companion object {
+ const val TAG = "FeatureLoadStateListener"
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/games/LoadingSceneView.java b/common/src/main/java/com/google/android/apps/santatracker/games/LoadingSceneView.java
new file mode 100644
index 000000000..529801bb4
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/games/LoadingSceneView.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.content.Context;
+import android.content.res.ColorStateList;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import com.google.android.apps.santatracker.common.R;
+
+/** Animated loading screen with progress indicator. */
+public class LoadingSceneView extends LinearLayout {
+
+ public LoadingSceneView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ // Inflate custom layout
+ LayoutInflater inflater = LayoutInflater.from(context);
+ inflater.inflate(R.layout.layout_loading_screen, this, true);
+
+ this.setGravity(Gravity.CENTER_VERTICAL);
+ this.setBackgroundColor(getResources().getColor(R.color.loading_web_background_blue));
+ this.setOrientation(LinearLayout.VERTICAL);
+
+ final ProgressBar progressBar = findViewById(R.id.progressbar);
+ if (Build.VERSION.SDK_INT >= 24) {
+ progressBar.setIndeterminateDrawable(
+ getResources().getDrawable(R.drawable.avd_loading_bar, context.getTheme()));
+ } else {
+ progressBar.setIndeterminateTintList(
+ ColorStateList.valueOf(getResources().getColor(R.color.SantaWhite)));
+ }
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/games/OnDemandActivity.kt b/common/src/main/java/com/google/android/apps/santatracker/games/OnDemandActivity.kt
new file mode 100644
index 000000000..21ae3e126
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/games/OnDemandActivity.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.content.Context
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.play.core.splitcompat.SplitCompat
+
+/**
+ * Base class for activities that are loaded within an onDemand module.
+ */
+abstract class OnDemandActivity : AppCompatActivity() {
+
+ override fun attachBaseContext(newBase: Context?) {
+ super.attachBaseContext(newBase)
+ SplitCompat.install(this)
+ }
+}
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
deleted file mode 100644
index f4a6081ed..000000000
--- a/common/src/main/java/com/google/android/apps/santatracker/games/PlayGamesFragment.java
+++ /dev/null
@@ -1,240 +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.apps.santatracker.games;
-
-import android.app.Activity;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-
-import com.google.android.apps.santatracker.common.BuildConfig;
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.GoogleApiAvailability;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.games.Games;
-
-/**
- * Non-visible fragment to encapsulate Google Play Game Services logic.
- */
-public class PlayGamesFragment extends Fragment implements
- GoogleApiClient.ConnectionCallbacks,
- GoogleApiClient.OnConnectionFailedListener{
-
- private static final String TAG = "PlayGamesFragment";
- private static final String FRAGMENT_TAG = "PlayGamesFragment_Tag";
-
- /** Key to store mIsResolving in SharedPreferences. **/
- private static final String KEY_IS_RESOLVING = "is_resolving";
-
- /** Key to store mShouldResolve in SharedPreferences. **/
- private static final String KEY_SHOULD_RESOLVE = "should_resolve";
-
- /** Request code used for resolving Games sign-in failures. **/
- private static final int RC_GAMES = 9001;
-
- /** Should debug-level log messages be printed? **/
- private boolean mDebugLogEnabled = false;
-
- /** GoogleApiClient used for interacting with Play Game Services. **/
- private GoogleApiClient mGamesApiClient;
-
- /** Is a resolution already in progress? **/
- private boolean mIsResolving = false;
-
- /** Should connection failures be automatically resolved? **/
- private boolean mShouldResolve = false;
-
- /** Listener for sign-in events. **/
- private SignInListener mListener;
-
- /**
- * Get or create an instance of the Fragment attached to an Activity.
- * @param activity FragmentActivity to host the Fragment.
- * @param listener SignInListener to respond to changes in sign-in state.
- * @return instance of PlayGamesFragment.
- */
- public static PlayGamesFragment getInstance(FragmentActivity activity,
- SignInListener listener) {
-
- FragmentManager fm = activity.getSupportFragmentManager();
- FragmentTransaction ft = fm.beginTransaction();
-
- PlayGamesFragment result = null;
-
- Fragment fragment = fm.findFragmentByTag(FRAGMENT_TAG);
- if (fragment == null) {
- result = new PlayGamesFragment();
- ft.add(result, FRAGMENT_TAG).disallowAddToBackStack().commit();
- } else {
- result = (PlayGamesFragment) fragment;
- }
-
- result.setListener(listener);
- return result;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Restore state of in-progress sign-in in the case of rotation or other
- // Activity recreation.
- if (savedInstanceState != null) {
- mIsResolving = savedInstanceState.getBoolean(KEY_IS_RESOLVING, false);
- mShouldResolve = savedInstanceState.getBoolean(KEY_SHOULD_RESOLVE, false);
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- mGamesApiClient.connect();
- }
-
- @Override
- public void onStop() {
- super.onStop();
- mGamesApiClient.disconnect();
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- // Only log debug messages when enabled
- mDebugLogEnabled = BuildConfig.DEBUG;
-
- // Api client for interacting with Google Play Games
- mGamesApiClient = new GoogleApiClient.Builder(getActivity())
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .addApi(Games.API, Games.GamesOptions.builder().build())
- .addScope(Games.SCOPE_GAMES)
- .build();
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == RC_GAMES) {
- debugLog("onActivityResult:RC_GAMES:" + resultCode + ":" + data);
-
- // If the error resolution was not successful we should not resolve further.
- if (resultCode != Activity.RESULT_OK) {
- mShouldResolve = false;
- }
-
- mIsResolving = false;
- mGamesApiClient.connect();
- }
- }
-
- @Override
- public void onConnected(Bundle bundle) {
- debugLog("onConnected:" + bundle);
- mShouldResolve = false;
- mListener.onSignInSucceeded();
- }
-
- @Override
- public void onConnectionSuspended(int i) {
- debugLog("onConnectionSuspended:" + i);
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- debugLog("onConnectionFailed:" + connectionResult);
- if (!mIsResolving && mShouldResolve) {
- if (connectionResult.hasResolution()) {
- try {
- connectionResult.startResolutionForResult(getActivity(), RC_GAMES);
- mIsResolving = true;
- } catch (IntentSender.SendIntentException e) {
- debugLog("onConnectionFailed:SendIntentException:" + e.getMessage());
- mIsResolving = false;
- mGamesApiClient.connect();
- }
- } else {
- // Could not resolve the connection result, show the user an
- // error dialog.
- showErrorDialog(connectionResult);
- }
- } else {
- // Show the signed-out UI
- mListener.onSignInFailed();
- }
- }
-
- /**
- * Show error dialog for Google Play Services errors that cannot be resolved.
- * @param connectionResult the connection result from onConnectionFailed.
- */
- private void showErrorDialog(ConnectionResult connectionResult) {
- GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
- int resultCode = apiAvailability.isGooglePlayServicesAvailable(getActivity());
-
- if (resultCode != ConnectionResult.SUCCESS) {
- if (apiAvailability.isUserResolvableError(resultCode)) {
- apiAvailability.getErrorDialog(getActivity(), resultCode, RC_GAMES,
- new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- mShouldResolve = false;
- mListener.onSignInFailed();
- }
- }).show();
- } else {
- String errorString = apiAvailability.getErrorString(resultCode);
- debugLog("Google Play Services Error:" + connectionResult + ":" + errorString);;
-
- mShouldResolve = false;
- mListener.onSignInFailed();
- }
- }
- }
-
- public boolean isSignedIn() {
- return (mGamesApiClient != null && mGamesApiClient.isConnected());
- }
-
- public void beginUserInitiatedSignIn() {
- mShouldResolve = true;
- mGamesApiClient.connect();
- }
-
- public GoogleApiClient getGamesApiClient() {
- return mGamesApiClient;
- }
-
- private void debugLog(String message) {
- if (!mDebugLogEnabled) {
- return;
- }
-
- Log.d(TAG, message);
- }
-
- private void setListener(SignInListener listener) {
- mListener = listener;
- }
-
-}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/games/PlayGamesFragment.kt b/common/src/main/java/com/google/android/apps/santatracker/games/PlayGamesFragment.kt
new file mode 100644
index 000000000..a9e0c8eed
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/games/PlayGamesFragment.kt
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.Activity
+import android.content.Intent
+import android.content.IntentSender
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import com.google.android.apps.santatracker.common.BuildConfig
+import com.google.android.apps.santatracker.util.SantaLog
+import com.google.android.gms.common.ConnectionResult
+import com.google.android.gms.common.GoogleApiAvailability
+import com.google.android.gms.common.api.GoogleApiClient
+import com.google.android.gms.games.Games
+
+/** Non-visible fragment to encapsulate Google Play Game Services logic. */
+class PlayGamesFragment : Fragment(), GoogleApiClient.ConnectionCallbacks,
+ GoogleApiClient.OnConnectionFailedListener {
+
+ /** Should debug-level log messages be printed? */
+ private var debugLogEnabled = false
+
+ /** GoogleApiClient used for interacting with Play Game Services. */
+ var gamesApiClient: GoogleApiClient? = null
+
+ /** Is a resolution already in progress? */
+ private var isResolving = false
+
+ /** Should connection failures be automatically resolved? */
+ private var shouldResolve = false
+
+ /** Listener for sign-in events. */
+ private var listener: SignInListener? = null
+
+ val isSignedIn: Boolean
+ get() = gamesApiClient?.isConnected == true
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // Restore state of in-progress sign-in in the case of rotation or other
+ // Activity recreation.
+ if (savedInstanceState != null) {
+ isResolving = savedInstanceState.getBoolean(KEY_IS_RESOLVING, false)
+ shouldResolve = savedInstanceState.getBoolean(KEY_SHOULD_RESOLVE, false)
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ gamesApiClient?.connect()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ gamesApiClient?.disconnect()
+ }
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+
+ // Only log debug messages when enabled
+ debugLogEnabled = BuildConfig.DEBUG
+
+ val activity = activity ?: return
+ // Api client for interacting with Google Play Games
+ gamesApiClient = GoogleApiClient.Builder(activity)
+ .addConnectionCallbacks(this)
+ .addOnConnectionFailedListener(this)
+ .addApi(Games.API, Games.GamesOptions.builder().build())
+ .addScope(Games.SCOPE_GAMES)
+ .build()
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (requestCode == RC_GAMES) {
+ debugLog("onActivityResult:RC_GAMES:$resultCode:$data")
+
+ // If the error resolution was not successful we should not resolve further.
+ if (resultCode != Activity.RESULT_OK) {
+ shouldResolve = false
+ }
+
+ isResolving = false
+ gamesApiClient?.connect()
+ }
+ }
+
+ override fun onConnected(bundle: Bundle?) {
+ debugLog("onConnected $bundle")
+ shouldResolve = false
+ listener?.onSignInSucceeded()
+ }
+
+ override fun onConnectionSuspended(i: Int) {
+ debugLog("onConnectionSuspended:$i")
+ }
+
+ override fun onConnectionFailed(connectionResult: ConnectionResult) {
+ debugLog("onConnectionFailed:$connectionResult")
+ if (!isResolving && shouldResolve) {
+ if (connectionResult.hasResolution()) {
+ try {
+ connectionResult.startResolutionForResult(activity, RC_GAMES)
+ isResolving = true
+ } catch (e: IntentSender.SendIntentException) {
+ debugLog("onConnectionFailed:SendIntentException:" + e.message)
+ isResolving = false
+ gamesApiClient?.connect()
+ }
+ } else {
+ // Could not resolve the connection result, show the user an
+ // error dialog.
+ showErrorDialog(connectionResult)
+ }
+ } else {
+ // Show the signed-out UI
+ listener?.onSignInFailed()
+ }
+ }
+
+ /**
+ * Show error dialog for Google Play Services errors that cannot be resolved.
+ *
+ * @param connectionResult the connection result from onConnectionFailed.
+ */
+ private fun showErrorDialog(connectionResult: ConnectionResult) {
+ val apiAvailability = GoogleApiAvailability.getInstance()
+ val resultCode = apiAvailability.isGooglePlayServicesAvailable(activity)
+
+ if (resultCode != ConnectionResult.SUCCESS) {
+ if (apiAvailability.isUserResolvableError(resultCode)) {
+ apiAvailability
+ .getErrorDialog(
+ activity,
+ resultCode,
+ RC_GAMES
+ ) {
+ shouldResolve = false
+ listener?.onSignInFailed()
+ }
+ .show()
+ } else {
+ val errorString = apiAvailability.getErrorString(resultCode)
+ debugLog("Google Play Services Error:$connectionResult:$errorString")
+
+ shouldResolve = false
+ listener?.onSignInFailed()
+ }
+ }
+ }
+
+ fun beginUserInitiatedSignIn() {
+ shouldResolve = true
+ gamesApiClient?.connect()
+ }
+
+ private fun debugLog(message: String) {
+ if (!debugLogEnabled) {
+ return
+ }
+
+ SantaLog.d(TAG, message)
+ }
+
+ private fun setListener(listener: SignInListener) {
+ this.listener = listener
+ }
+
+ companion object {
+
+ private const val TAG = "PlayGamesFragment"
+ private const val FRAGMENT_TAG = "PlayGamesFragment_Tag"
+
+ /** Key to store isResolving in SharedPreferences. */
+ private const val KEY_IS_RESOLVING = "is_resolving"
+
+ /** Key to store shouldResolve in SharedPreferences. */
+ private const val KEY_SHOULD_RESOLVE = "should_resolve"
+
+ /** Request code used for resolving Games sign-in failures. */
+ private const val RC_GAMES = 9001
+
+ /**
+ * Get or create an instance of the Fragment attached to an Activity.
+ *
+ * @param activity FragmentActivity to host the Fragment.
+ * @param listener SignInListener to respond to changes in sign-in state.
+ * @return instance of PlayGamesFragment.
+ */
+ @JvmStatic
+ fun getInstance(
+ activity: androidx.fragment.app.FragmentActivity,
+ listener: SignInListener
+ ): PlayGamesFragment? {
+
+ val fm = activity.supportFragmentManager
+ val ft = fm.beginTransaction()
+
+ val result: PlayGamesFragment?
+ val fragment = fm.findFragmentByTag(FRAGMENT_TAG)
+ if (fragment == null) {
+ result = PlayGamesFragment()
+ ft.add(result, FRAGMENT_TAG).disallowAddToBackStack().commit()
+ } else {
+ result = fragment as PlayGamesFragment?
+ }
+
+ result?.setListener(listener)
+ return result
+ }
+ }
+}
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
deleted file mode 100644
index 66093ede0..000000000
--- a/common/src/main/java/com/google/android/apps/santatracker/games/SignInListener.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.apps.santatracker.games;
-
-/**
- * Interface for Activities that observe sign-in state, normally used with {@link GameActivity}.
- */
-public interface SignInListener {
-
- /**
- * Called when sign-in fails. As a result, a "Sign-In" button can be shown to the user.
- * Not all calls to this method indicate an error, sign-in is expected to fail when the
- * user has never signed in before.
- */
- void onSignInFailed();
-
- /**
- * Called when sign-in succeeds and the application can begin to take action on behalf of
- * the user.
- */
- void onSignInSucceeded();
-
-}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/games/SignInListener.kt b/common/src/main/java/com/google/android/apps/santatracker/games/SignInListener.kt
new file mode 100644
index 000000000..0a78a159f
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/games/SignInListener.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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
+
+/** Interface for Activities that observe sign-in state, normally used with [GameActivity]. */
+interface SignInListener {
+
+ /**
+ * Called when sign-in fails. As a result, a "Sign-In" button can be shown to the user. Not all
+ * calls to this method indicate an error, sign-in is expected to fail when the user has never
+ * signed in before.
+ */
+ fun onSignInFailed()
+
+ /**
+ * Called when sign-in succeeds and the application can begin to take action on behalf of the
+ * user.
+ */
+ fun onSignInSucceeded()
+}
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
deleted file mode 100644
index 7703edda3..000000000
--- a/common/src/main/java/com/google/android/apps/santatracker/invites/AppInvitesFragment.java
+++ /dev/null
@@ -1,171 +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.apps.santatracker.invites;
-
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-
-import com.google.android.apps.santatracker.common.R;
-import com.google.android.apps.santatracker.util.MeasurementManager;
-import com.google.android.gms.appinvite.AppInvite;
-import com.google.android.gms.appinvite.AppInviteInvitation;
-import com.google.android.gms.appinvite.AppInviteInvitationResult;
-import com.google.android.gms.appinvite.AppInviteReferral;
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.common.api.ResultCallback;
-import com.google.firebase.analytics.FirebaseAnalytics;
-
-public class AppInvitesFragment extends Fragment implements
- GoogleApiClient.OnConnectionFailedListener {
-
- private static final String TAG = "AppInvitesFragment";
- private static final String FRAGMENT_TAG = "AppInvitesFragment";
- 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/");
-
- private GoogleApiClient mGoogleApiClient;
- private FirebaseAnalytics mMeasurement;
-
- public interface GetInvitationCallback {
- void onInvitation(String invitationId, String deepLink);
- }
-
- public static AppInvitesFragment getInstance(FragmentActivity activity) {
-
- FragmentManager fm = activity.getSupportFragmentManager();
- FragmentTransaction ft = fm.beginTransaction();
-
- AppInvitesFragment result = null;
-
- Fragment fragment = fm.findFragmentByTag(FRAGMENT_TAG);
- if (fragment == null) {
- result = new AppInvitesFragment();
- ft.add(result, FRAGMENT_TAG).disallowAddToBackStack().commit();
- } else {
- result = (AppInvitesFragment) fragment;
- }
-
- return result;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- // Initialize app measurement.
- mMeasurement = FirebaseAnalytics.getInstance(getActivity());
-
- // Api client for AppInvites.
- mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
- .addOnConnectionFailedListener(this)
- .enableAutoManage(getActivity(), AUTOMANAGE_ID, this)
- .addApi(AppInvite.API)
- .build();
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- if (requestCode == RC_INVITE) {
- String[] ids = AppInviteInvitation.getInvitationIds(resultCode, data);
- Log.d(TAG, "onActivityResult:" + ids);
- }
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- Log.w(TAG, "onConnectionFailed:" + connectionResult);
- }
-
- /**
- * Send an invite with a deep link into a game.
- * @param gameName a human-readable name for the game, to be displayed in the invitation UI.
- * @param gameId an identifier for the game to be appended to
- * http://google.com/santatracker/android/. The game should be a registered
- * handler for this URL in the Android Manifest.
- * @param score the inviting user's game score, which will be pre-populated in the
- * invitation message.
- */
- public void sendGameInvite(String gameName, String gameId, int score) {
- Uri uri = BASE_URI.buildUpon()
- .appendPath(gameId)
- .appendQueryParameter("score", Integer.toString(score))
- .build();
-
- sendInvite(getString(R.string.invite_message_game_fmt, score, gameName), uri);
- MeasurementManager.recordInvitationSent(mMeasurement, "game", uri.toString());
-
- }
-
- public void sendGenericInvite() {
- Uri uri = BASE_URI;
- sendInvite(getString(R.string.invite_message_generic), uri);
- MeasurementManager.recordInvitationSent(mMeasurement, "generic", uri.toString());
- }
-
- private 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.
- int maxLength = AppInviteInvitation.IntentBuilder.MAX_MESSAGE_LENGTH;
- if (message.length() > maxLength) {
- String suffix = "...";
- String prefix = message.substring(0, maxLength - suffix.length());
-
- message = prefix + suffix;
- }
-
- Intent inviteIntent = new AppInviteInvitation.IntentBuilder(getString(R.string.invite_title))
- .setMessage(message)
- .setDeepLink(uri)
- .build();
-
- startActivityForResult(inviteIntent, RC_INVITE);
- }
-
- public void getInvite(final GetInvitationCallback callback, boolean launchDeepLink) {
- AppInvite.AppInviteApi.getInvitation(mGoogleApiClient, getActivity(), launchDeepLink)
- .setResultCallback(new ResultCallback() {
- @Override
- public void onResult(AppInviteInvitationResult appInviteInvitationResult) {
- Log.d(TAG, "getInvite:" + appInviteInvitationResult.getStatus());
-
- if (callback != null && appInviteInvitationResult.getStatus().isSuccess()) {
- // Report the callback.
- Intent intent = appInviteInvitationResult.getInvitationIntent();
- String invitiationId = AppInviteReferral.getInvitationId(intent);
- String deepLink = AppInviteReferral.getDeepLink(intent);
- callback.onInvitation(invitiationId, deepLink);
-
- // Record invitation receipt event.
- MeasurementManager.recordInvitationReceived(mMeasurement, deepLink);
- }
-
- }
- });
- }
-}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/invites/AppInvitesFragment.kt b/common/src/main/java/com/google/android/apps/santatracker/invites/AppInvitesFragment.kt
new file mode 100644
index 000000000..dc2df98b7
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/invites/AppInvitesFragment.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.invites
+
+import android.content.ActivityNotFoundException
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
+import com.google.android.apps.santatracker.common.R
+import com.google.android.apps.santatracker.util.MeasurementManager
+import com.google.android.apps.santatracker.util.SantaLog
+import com.google.android.gms.appinvite.AppInvite
+import com.google.android.gms.appinvite.AppInviteInvitation
+import com.google.android.gms.appinvite.AppInviteReferral
+import com.google.android.gms.common.ConnectionResult
+import com.google.android.gms.common.api.GoogleApiClient
+import com.google.firebase.analytics.FirebaseAnalytics
+
+class AppInvitesFragment : Fragment(), GoogleApiClient.OnConnectionFailedListener {
+
+ private lateinit var googleApiClient: GoogleApiClient
+ private lateinit var firebaseAnalytics: FirebaseAnalytics
+
+ interface GetInvitationCallback {
+ fun onInvitation(invitationId: String, deepLink: String)
+ }
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+
+ val activity = activity ?: return
+
+ // Initialize app measurement.
+ firebaseAnalytics = FirebaseAnalytics.getInstance(activity)
+
+ // Api client for AppInvites.
+ googleApiClient = GoogleApiClient.Builder(activity)
+ .addOnConnectionFailedListener(this)
+ .enableAutoManage(activity, AUTOMANAGE_ID, this)
+ .addApi(AppInvite.API)
+ .build()
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+
+ if (requestCode == RC_INVITE && data != null) {
+ val ids = AppInviteInvitation.getInvitationIds(resultCode, data)
+ SantaLog.d(TAG, "onActivityResult:$ids")
+ }
+ }
+
+ override fun onConnectionFailed(connectionResult: ConnectionResult) {
+ SantaLog.w(TAG, "onConnectionFailed:$connectionResult")
+ }
+
+ /**
+ * Send an invite with a deep link into a game.
+ *
+ * @param gameName a human-readable name for the game, to be displayed in the invitation UI.
+ * @param gameId an identifier for the game to be appended to
+ * http://google.com/santatracker/android/. The game should be a registered handler for this
+ * URL in the Android Manifest.
+ * @param score the inviting user's game score, which will be pre-populated in the invitation
+ * message.
+ */
+ fun sendGameInvite(gameName: String, gameId: String, score: Int) {
+ val uri = BASE_URI.buildUpon()
+ .appendPath(gameId)
+ .appendQueryParameter("score", Integer.toString(score))
+ .build()
+
+ sendInvite(getString(R.string.invite_message_game_fmt, score, gameName), uri)
+ MeasurementManager.recordInvitationSent(firebaseAnalytics, "game", uri.toString())
+ }
+
+ fun sendGenericInvite() {
+ val uri = BASE_URI
+ sendInvite(getString(R.string.invite_message_generic), uri)
+ MeasurementManager.recordInvitationSent(firebaseAnalytics, "generic", uri.toString())
+ }
+
+ private fun sendInvite(message: String, uri: Uri) {
+ var message = message
+ // 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.
+ val maxLength = AppInviteInvitation.IntentBuilder.MAX_MESSAGE_LENGTH
+ if (message.length > maxLength) {
+ val suffix = "..."
+ val prefix = message.substring(0, maxLength - suffix.length)
+
+ message = prefix + suffix
+ }
+
+ val inviteIntent = AppInviteInvitation.IntentBuilder(getString(R.string.invite_title))
+ .setMessage(message)
+ .setDeepLink(uri)
+ .build()
+
+ startActivityForResult(inviteIntent, RC_INVITE)
+ }
+
+ fun getInvite(callback: GetInvitationCallback?, launchDeepLink: Boolean) {
+ // 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.
+ val activity = activity
+ AppInvite.AppInviteApi.getInvitation(googleApiClient, null, false)
+ .setResultCallback { appInviteInvitationResult ->
+ SantaLog.d(TAG, "getInvite:" + appInviteInvitationResult.status)
+
+ if (callback != null && appInviteInvitationResult.status.isSuccess) {
+ // Report the callback.
+ val intent = appInviteInvitationResult.invitationIntent
+ val invitiationId = AppInviteReferral.getInvitationId(intent)
+ val deepLink = AppInviteReferral.getDeepLink(intent)
+ callback.onInvitation(invitiationId, deepLink)
+
+ // Record invitation receipt event.
+ MeasurementManager.recordInvitationReceived(
+ firebaseAnalytics, deepLink)
+
+ // Launch the deep link (see above note on why we don't do this
+ // automatically)
+ activity?.let {
+ if (launchDeepLink) {
+ try {
+ it.startActivity(intent)
+ } catch (e: ActivityNotFoundException) {
+ SantaLog.w(TAG, "No handler for deep link", e)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+
+ private const val TAG = "AppInvitesFragment"
+ private const val FRAGMENT_TAG = "AppInvitesFragment"
+ private const val AUTOMANAGE_ID = 107
+ private const val RC_INVITE = 9007
+
+ val BASE_URI: Uri = Uri.parse("https://google.com/santatracker/android/")
+
+ @JvmStatic
+ fun getInstance(activity: FragmentActivity): AppInvitesFragment? {
+
+ val fm = activity.supportFragmentManager
+ val ft = fm.beginTransaction()
+
+ var result: AppInvitesFragment?
+ val fragment = fm.findFragmentByTag(FRAGMENT_TAG)
+ if (fragment == null) {
+ result = AppInvitesFragment()
+ ft.add(result, FRAGMENT_TAG).disallowAddToBackStack().commit()
+ } else {
+ result = fragment as AppInvitesFragment?
+ }
+ return result
+ }
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/AccessibilityUtil.kt b/common/src/main/java/com/google/android/apps/santatracker/util/AccessibilityUtil.kt
new file mode 100644
index 000000000..3c9e3be9a
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/util/AccessibilityUtil.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.view.View
+import android.view.accessibility.AccessibilityEvent
+import android.view.accessibility.AccessibilityManager
+import androidx.core.view.accessibility.AccessibilityEventCompat
+
+/** Utility methods for accessibility support. */
+object AccessibilityUtil {
+
+ /** Return true if the accessibility service or touch exploration are enabled. */
+ @JvmStatic
+ fun isTouchAccessiblityEnabled(context: Context): Boolean {
+ val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
+ val isAccessibilityEnabled = am.isEnabled
+ val isTouchExplorationEnabled = am.isTouchExplorationEnabled
+ return isAccessibilityEnabled || isTouchExplorationEnabled
+ }
+
+ /**
+ * Announce text through the AccessibilityManager for a view.
+ *
+ * @param text
+ * @param view
+ * @param manager
+ */
+ @JvmStatic
+ fun announceText(text: String, view: View, manager: AccessibilityManager) {
+ // Only announce text if the accessibility service is enabled
+ if (!manager.isEnabled) {
+ return
+ }
+
+ val event = AccessibilityEvent.obtain(
+ AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED)
+ event.text.add(text)
+ event.isEnabled = true
+ // Tie the event to the view
+ event.className = view.javaClass.name
+ event.packageName = view.context.packageName
+ event.setSource(view)
+
+ // Send the announcement
+ manager.sendAccessibilityEvent(event)
+ }
+}
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
deleted file mode 100644
index d2198dbbc..000000000
--- a/common/src/main/java/com/google/android/apps/santatracker/util/AnalyticsManager.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 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.apps.santatracker.util;
-
-import android.content.Context;
-import android.util.Log;
-
-import com.google.android.gms.analytics.GoogleAnalytics;
-import com.google.android.gms.analytics.HitBuilders;
-import com.google.android.gms.analytics.Tracker;
-import com.google.android.apps.santatracker.common.R;
-
-/**
- * Handles communication with Google Analytics.
- * Based on implementation in iosched: com.google.samples.apps.iosched.util.AnalyticsManager
- */
-public class AnalyticsManager {
-
- private static Context sAppContext = null;
- private static Tracker mTracker;
-
- private final static String TAG = "AnalyticsManager";
-
- public static synchronized void setTracker(Tracker tracker) {
- mTracker = tracker;
- }
-
- private static boolean canSend() {
- return mTracker != null;
- }
-
- /**
- * Sends a screen view with the string resource loaded as its label.
- */
- public static void sendScreenView(int resourceId) {
- sendScreenView(getString(resourceId));
- }
-
- private static String getString(int id){
- if(sAppContext != null) {
- return sAppContext.getString(id);
- }
- return null;
- }
- /**
- * Sends a screen vie for a screen label.
- */
- public static void sendScreenView(String screenName) {
- if (canSend()) {
- mTracker.setScreenName(screenName);
- mTracker.send(new HitBuilders.AppViewBuilder().build());
- Log.d(TAG, "Screen View recorded: " + screenName);
- } else {
- Log.d(TAG, "Screen View NOT recorded (analytics disabled or not ready).");
- }
- }
-
- /**
- * Sends an event to the tracker with string resources loaded as parameters.
- */
- public static void sendEvent(int category, int action, int label, long value) {
- sendEvent(getString(category), getString(action),
- getString(label), value);
- }
-
- /**
- * Sends an event to the tracker with string resources loaded as parameters.
- */
- public static void sendEvent(int category, int action) {
- sendEvent(getString(category), getString(action));
- }
-
- /**
- * Sends an event to the tracker with string resources loaded as parameters.
- */
- public static void sendEvent(int category, int action, String label) {
- sendEvent(getString(category), getString(action), label);
- }
-
- public static void sendEvent(String category, String action) {
- if (canSend()) {
- mTracker.send(new HitBuilders.EventBuilder(category,action).build());
-
- Log.d(TAG, "Event recorded:");
- Log.d(TAG, "\tCategory: " + category);
- Log.d(TAG, "\tAction: " + action);
- } else {
- Log.d(TAG, "Analytics event ignored (analytics disabled or not ready).");
- }
- }
-
- public static void sendEvent(String category, String action, String label, long value) {
- if (canSend()) {
- mTracker.send(new HitBuilders.EventBuilder()
- .setCategory(category)
- .setAction(action)
- .setLabel(label)
- .setValue(value)
- .build());
-
- Log.d(TAG, "Event recorded:");
- Log.d(TAG, "\tCategory: " + category);
- Log.d(TAG, "\tAction: " + action);
- Log.d(TAG, "\tLabel: " + label);
- Log.d(TAG, "\tValue: " + value);
- } else {
- Log.d(TAG, "Analytics event ignored (analytics disabled or not ready).");
- }
- }
-
- /**
- * Sends an event to the tracker with string resources loaded as parameters.
- */
- public static void sendEvent(int category, int action, int label) {
- sendEvent(getString(category), getString(action),
- getString(label));
- }
-
- public static void sendEvent(String category, String action, String label) {
- sendEvent(category, action, label, 0);
- }
-
- public Tracker getTracker() {
- return mTracker;
- }
-
- public static synchronized void initializeAnalyticsTracker(Context context) {
- sAppContext = context;
- if (mTracker == null) {
- GoogleAnalytics analytics = GoogleAnalytics.getInstance(context);
- mTracker = analytics.newTracker(R.xml.config_analytics_tracker);
- Log.d(TAG, "Analytics tracker initialised.");
- }
- }
-}
\ No newline at end of file
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
deleted file mode 100644
index aa4ba29ca..000000000
--- a/common/src/main/java/com/google/android/apps/santatracker/util/ImmersiveModeHelper.java
+++ /dev/null
@@ -1,64 +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.apps.santatracker.util;
-
-import android.annotation.TargetApi;
-import android.os.Build;
-import android.util.Log;
-import android.view.View;
-import android.view.Window;
-
-public class ImmersiveModeHelper {
-
- private static final String TAG = ImmersiveModeHelper.class
- .getSimpleName();
-
- @TargetApi(Build.VERSION_CODES.KITKAT)
- public static void installSystemUiVisibilityChangeListener(final Window w) {
- View view = w.getDecorView();
- view.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
- @Override
- public void onSystemUiVisibilityChange(int visibility) {
- Log.d(TAG, "setOnSystemUiVisibilityChangeListener: visibility=" + visibility);
- setImmersiveSticky(w);
- }
- });
- }
-
- @TargetApi(Build.VERSION_CODES.KITKAT)
- public static void setImmersiveSticky(Window w) {
- w.getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_FULLSCREEN |
- View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
-
- }
-
- @TargetApi(Build.VERSION_CODES.KITKAT)
- public static void setImmersiveStickyWithActionBar(Window w) {
- w.getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_FULLSCREEN |
- View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
-
- }
-}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/ImmersiveModeHelper.kt b/common/src/main/java/com/google/android/apps/santatracker/util/ImmersiveModeHelper.kt
new file mode 100644
index 000000000..3c9f1bb4a
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/util/ImmersiveModeHelper.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.annotation.TargetApi
+import android.os.Build
+import android.view.View
+import android.view.Window
+
+object ImmersiveModeHelper {
+
+ private val TAG = ImmersiveModeHelper::class.java.simpleName
+
+ @TargetApi(Build.VERSION_CODES.KITKAT)
+ @JvmStatic
+ fun installSystemUiVisibilityChangeListener(w: Window) {
+ val view = w.decorView
+ view.setOnSystemUiVisibilityChangeListener { visibility ->
+ SantaLog.d(
+ TAG,
+ "setOnSystemUiVisibilityChangeListener: visibility=$visibility")
+ setImmersiveSticky(w)
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.KITKAT)
+ @JvmStatic
+ fun setImmersiveSticky(w: Window) {
+ w.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ or View.SYSTEM_UI_FLAG_FULLSCREEN
+ or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
+ }
+
+ @TargetApi(Build.VERSION_CODES.KITKAT)
+ @JvmStatic
+ fun setImmersiveStickyWithActionBar(w: Window) {
+ w.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ or View.SYSTEM_UI_FLAG_FULLSCREEN
+ or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/MapHelper.kt b/common/src/main/java/com/google/android/apps/santatracker/util/MapHelper.kt
new file mode 100644
index 000000000..9bffbee68
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/util/MapHelper.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 com.google.android.gms.maps.SupportMapFragment
+
+object MapHelper {
+
+ private val TAG = MapHelper::class.java.simpleName
+
+ /**
+ * 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.
+ */
+ @JvmStatic
+ fun getMapPadding(supportMapFragment: SupportMapFragment): Int {
+ val height = supportMapFragment.view!!.height
+ val width = supportMapFragment.view!!.width
+ val factor = 0.3
+ val padding = if (height < width) height * factor else width * factor
+ SantaLog.d(TAG, "padding used: $padding")
+ return padding.toInt()
+ }
+}
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
deleted file mode 100644
index 2e37a3928..000000000
--- a/common/src/main/java/com/google/android/apps/santatracker/util/MeasurementManager.java
+++ /dev/null
@@ -1,121 +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.apps.santatracker.util;
-
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.Log;
-
-import com.google.firebase.analytics.FirebaseAnalytics;
-
-/** Handles communication with Firebase Analytics. */
-public class MeasurementManager {
-
- private static final String TAG = "MeasurementManager";
-
- private static final String GAME_TITLE = "game_title";
- private static final String TYPE_SCREEN = "type_screen";
-
- public static void recordCustomEvent(FirebaseAnalytics measurement,
- @NonNull String name,
- @NonNull String action,
- @Nullable String label) {
- Log.d(TAG, "recordCustomEvent:" + name + ":" + action + ":" + label);
-
- Bundle params = new Bundle();
- params.putString("action", action);
- if (label != null) {
- params.putString("label", label);
- }
- measurement.logEvent(name, params);
- }
-
- public static void recordCustomEvent(FirebaseAnalytics measurement,
- @NonNull String name,
- @NonNull String action) {
- Log.d(TAG, "recordCustomEvent:" + name + ":" + action);
-
- recordCustomEvent(measurement, name, action, null);
- }
-
- public static void recordScreenView(FirebaseAnalytics measurement,
- @NonNull String id) {
- Log.d(TAG, "recordScreenView:" + id);
-
- Bundle params = new Bundle();
- params.putString(FirebaseAnalytics.Param.CONTENT_TYPE, TYPE_SCREEN);
- params.putString(FirebaseAnalytics.Param.ITEM_ID, id);
- measurement.logEvent(FirebaseAnalytics.Event.SELECT_CONTENT, params);
- }
-
- public static void recordInvitationReceived(FirebaseAnalytics measurement,
- @NonNull String deepLink) {
- Log.d(TAG, "recordInvitationReceived:" + deepLink);
-
- Bundle params = new Bundle();
- params.putString("deepLink", deepLink);
- measurement.logEvent(FirebaseAnalytics.Event.APP_OPEN, params);
- }
-
- public static void recordInvitationSent(FirebaseAnalytics measurement,
- @NonNull String type,
- @NonNull String deepLink) {
- Log.d(TAG, "recordInvitationSent:" + type + ":" + deepLink);
-
- Bundle params = new Bundle();
- params.putString(FirebaseAnalytics.Param.CONTENT_TYPE, type);
- params.putSerializable(FirebaseAnalytics.Param.ITEM_ID, deepLink);
- measurement.logEvent(FirebaseAnalytics.Event.SHARE, params);
- }
-
- public static void recordLogin(FirebaseAnalytics measurement) {
- Log.d(TAG, "recordLogin");
- measurement.logEvent(FirebaseAnalytics.Event.LOGIN, null);
- }
-
- public static void recordAchievement(FirebaseAnalytics measurement,
- @NonNull String achId,
- @Nullable String gameTitle) {
- Log.d(TAG, "recordAchievement:" + achId + ":" + gameTitle);
-
- Bundle params = new Bundle();
- params.putString(FirebaseAnalytics.Param.ACHIEVEMENT_ID, achId);
- if (gameTitle != null) {
- params.putString(GAME_TITLE, gameTitle);
- }
- measurement.logEvent(FirebaseAnalytics.Event.UNLOCK_ACHIEVEMENT, params);
- }
-
- public static void recordGameScore(FirebaseAnalytics measurement,
- @NonNull Long score,
- @Nullable Long level,
- @Nullable String gameTitle) {
- Log.d(TAG, "recordGameEnd:" + gameTitle + ":" + score + ":" + level);
-
- Bundle params = new Bundle();
- params.putLong(FirebaseAnalytics.Param.SCORE, score);
- if (level != null) {
- params.putLong(FirebaseAnalytics.Param.LEVEL, level);
- }
- if (gameTitle != null) {
- params.putString(GAME_TITLE, gameTitle);
- }
- measurement.logEvent(FirebaseAnalytics.Event.POST_SCORE, params);
- }
-
-}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/MeasurementManager.kt b/common/src/main/java/com/google/android/apps/santatracker/util/MeasurementManager.kt
new file mode 100644
index 000000000..157eb0540
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/util/MeasurementManager.kt
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import com.google.android.apps.santatracker.common.BuildConfig
+import com.google.firebase.analytics.FirebaseAnalytics
+import java.util.Locale
+
+/** Handles communication with Firebase Analytics. */
+object MeasurementManager {
+
+ private val TAG = "MeasurementManager"
+
+ private val GAME_TITLE = "game_title"
+ private val TYPE_SCREEN = "type_screen"
+
+ /** User properties */
+ private val BUILD_DEBUG = "BUILD_DEBUG"
+
+ private val BUILD_VERSION_NAME = "BUILD_VERSION_NAME"
+ private val DEVICE_BOARD = "DEVICE_BOARD"
+ private val DEVICE_BRAND = "DEVICE_BRAND"
+ private val DEVICE_LOCALE = "DEVICE_LOCALE"
+ private val API_LEVEL = "API_LEVEL"
+
+ @JvmStatic
+ fun recordDeviceProperties(context: Context) {
+ val analytics = FirebaseAnalytics.getInstance(context.applicationContext)
+
+ // Set some user properties based on the device, this can be used for Analytics or
+ // for Remote Config
+ analytics.setUserProperty(BUILD_DEBUG, BuildConfig.DEBUG.toString())
+ analytics.setUserProperty(DEVICE_BOARD, Build.BOARD)
+ analytics.setUserProperty(DEVICE_BRAND, Build.BRAND)
+ analytics.setUserProperty(DEVICE_LOCALE, Locale.getDefault().language)
+ analytics.setUserProperty(API_LEVEL, Build.VERSION.SDK_INT.toString())
+
+ try {
+ // Set version name, if we can get it
+ val pm = context.packageManager
+ val info = pm.getPackageInfo(context.packageName, 0)
+ analytics.setUserProperty(BUILD_VERSION_NAME, info.versionName)
+ } catch (e: PackageManager.NameNotFoundException) {
+ SantaLog.w(TAG, "Could not get package info", e)
+ }
+ }
+
+ @JvmOverloads
+ @JvmStatic
+ fun recordCustomEvent(
+ measurement: FirebaseAnalytics,
+ name: String,
+ action: String,
+ label: String? = null,
+ value: Long = Integer.MIN_VALUE.toLong()
+ ) {
+ SantaLog.d(TAG, "recordCustomEvent:$name:$action:$label")
+
+ val params = Bundle()
+ params.putString("action", action)
+ if (label != null) {
+ params.putString("label", label)
+ }
+ if (value != Integer.MIN_VALUE.toLong()) {
+ params.putString("value", java.lang.Long.toString(value))
+ }
+ measurement.logEvent(name, params)
+ }
+
+ @JvmStatic
+ fun recordScreenView(measurement: FirebaseAnalytics, id: String) {
+ SantaLog.d(TAG, "recordScreenView:$id")
+
+ val params = Bundle()
+ params.putString(FirebaseAnalytics.Param.CONTENT_TYPE, TYPE_SCREEN)
+ params.putString(FirebaseAnalytics.Param.ITEM_ID, id)
+ measurement.logEvent(FirebaseAnalytics.Event.SELECT_CONTENT, params)
+ }
+
+ @JvmStatic
+ fun recordInvitationReceived(
+ measurement: FirebaseAnalytics,
+ deepLink: String
+ ) {
+ SantaLog.d(TAG, "recordInvitationReceived:$deepLink")
+
+ val params = Bundle()
+ params.putString("deepLink", deepLink)
+ measurement.logEvent(FirebaseAnalytics.Event.APP_OPEN, params)
+ }
+
+ @JvmStatic
+ fun recordInvitationSent(
+ measurement: FirebaseAnalytics,
+ type: String,
+ deepLink: String
+ ) {
+ SantaLog.d(TAG, "recordInvitationSent:$type:$deepLink")
+
+ val params = Bundle()
+ params.putString(FirebaseAnalytics.Param.CONTENT_TYPE, type)
+ params.putSerializable(FirebaseAnalytics.Param.ITEM_ID, deepLink)
+ measurement.logEvent(FirebaseAnalytics.Event.SHARE, params)
+ }
+
+ @JvmStatic
+ fun recordLogin(measurement: FirebaseAnalytics) {
+ SantaLog.d(TAG, "recordLogin")
+ measurement.logEvent(FirebaseAnalytics.Event.LOGIN, null)
+ }
+
+ @JvmStatic
+ fun recordAchievement(
+ measurement: FirebaseAnalytics,
+ achId: String,
+ gameTitle: String?
+ ) {
+ SantaLog.d(TAG, "recordAchievement:$achId:$gameTitle")
+
+ val params = Bundle()
+ params.putString(FirebaseAnalytics.Param.ACHIEVEMENT_ID, achId)
+ if (gameTitle != null) {
+ params.putString(GAME_TITLE, gameTitle)
+ }
+ measurement.logEvent(FirebaseAnalytics.Event.UNLOCK_ACHIEVEMENT, params)
+ }
+
+ @JvmStatic
+ fun recordGameScore(
+ measurement: FirebaseAnalytics,
+ score: Long,
+ level: Long?,
+ gameTitle: String?
+ ) {
+ SantaLog.d(TAG, "recordGameEnd:$gameTitle:$score:$level")
+
+ val params = Bundle()
+ params.putLong(FirebaseAnalytics.Param.SCORE, score)
+ if (level != null) {
+ params.putLong(FirebaseAnalytics.Param.LEVEL, level)
+ }
+ if (gameTitle != null) {
+ params.putString(GAME_TITLE, gameTitle)
+ }
+ measurement.logEvent(FirebaseAnalytics.Event.POST_SCORE, params)
+ }
+
+ @JvmStatic
+ fun recordVillageSantaClick(measurement: FirebaseAnalytics) {
+ SantaLog.d(TAG, "recordVillageSantaClick")
+ measurement.logEvent("village_santa_clicked", Bundle())
+ }
+
+ @JvmStatic
+ fun recordSwimmingEnd(
+ measurement: FirebaseAnalytics,
+ numStars: Int,
+ score: Int,
+ end_reason: String?
+ ) {
+ SantaLog.d(TAG, "recordSwimmingEnd:$numStars:$score:$end_reason")
+
+ val params = Bundle()
+ params.putInt("num_stars", numStars)
+ params.putInt("score", score)
+ if (end_reason != null) {
+ params.putString("end_reason", end_reason)
+ }
+
+ // Log custom swimming event
+ measurement.logEvent("swimming_game_end", params)
+
+ // Log generic game score event
+ recordGameScore(measurement, score.toLong(), null, "swimming")
+ }
+
+ @JvmStatic
+ fun recordRunningEnd(measurement: FirebaseAnalytics, numStars: Int, score: Int) {
+ SantaLog.d(TAG, "recordRunningEnd:$numStars:$score")
+
+ val params = 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, score.toLong(), null, "running")
+ }
+
+ @JvmStatic
+ fun recordPresentDropped(analytics: FirebaseAnalytics, isLarge: Boolean) {
+ SantaLog.d(TAG, "recordPresentDropped:$isLarge")
+
+ val params = Bundle()
+ if (isLarge) {
+ params.putString("size", "large")
+ } else {
+ params.putString("size", "small")
+ }
+
+ analytics.logEvent("pq_present_dropped", params)
+ }
+
+ @JvmStatic
+ fun recordPresentsCollected(analytics: FirebaseAnalytics, numPresents: Int) {
+ SantaLog.d(TAG, "recordPresentsCollected:$numPresents")
+
+ val params = Bundle()
+ params.putInt("num_presents", numPresents)
+
+ analytics.logEvent("pq_presents_collected", params)
+ }
+
+ @JvmStatic
+ fun recordPresentsReturned(analytics: FirebaseAnalytics, numPresents: Int) {
+ SantaLog.d(TAG, "recordPresentsReturned:$numPresents")
+
+ val params = Bundle()
+ params.putInt("num_presents", numPresents)
+
+ analytics.logEvent("pq_presents_returned", params)
+ }
+
+ @JvmStatic
+ fun recordPresentQuestLevel(analytics: FirebaseAnalytics, level: Int) {
+ SantaLog.d(TAG, "recordPresentQuestLevel:$level")
+
+ val params = Bundle()
+ params.putInt("level", level)
+
+ // Log custom event
+ analytics.logEvent("pq_level_unlocked", params)
+
+ // Log standard LEVEL_UP event
+ val params2 = Bundle()
+ params2.putLong(FirebaseAnalytics.Param.LEVEL, level.toLong())
+ analytics.logEvent(FirebaseAnalytics.Event.LEVEL_UP, params2)
+ }
+
+ @JvmStatic
+ fun recordWorkshopMoved(analytics: FirebaseAnalytics) {
+ SantaLog.d(TAG, "recordWorkshopMoved")
+
+ analytics.logEvent("pq_workshop_moved", Bundle())
+ }
+
+ @JvmStatic
+ fun recordHundredMetersWalked(analytics: FirebaseAnalytics, distance: Int) {
+ SantaLog.d(TAG, "recordHundredMetersWalked")
+
+ val bundle = Bundle()
+ bundle.putInt("distance", distance)
+ analytics.logEvent("pq_hundred_meters_walked", bundle)
+ }
+
+ @JvmStatic
+ fun recordCorrectCitySelected(
+ analytics: FirebaseAnalytics,
+ cityId: String,
+ numIncorrectAttempts: Int
+ ) {
+ SantaLog.d(TAG, "recordCorrectCitySelected:$cityId:$numIncorrectAttempts")
+
+ val params = Bundle()
+ params.putString("city_id", cityId)
+ params.putInt("incorrect_attempts", numIncorrectAttempts)
+
+ analytics.logEvent("cq_select_correct", params)
+ }
+
+ @JvmStatic
+ fun recordIncorrectCitySelected(
+ analytics: FirebaseAnalytics,
+ cityId: String
+ ) {
+ SantaLog.d(TAG, "recordIncorrectCitySelected:$cityId")
+
+ val params = 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.kt b/common/src/main/java/com/google/android/apps/santatracker/util/NetworkHelper.kt
new file mode 100644
index 000000000..33dc507ca
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/util/NetworkHelper.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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
+
+/** Utility class to check network state. */
+object NetworkHelper {
+
+ @JvmStatic
+ fun hasNetwork(context: Context): Boolean {
+ val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+
+ val activeNetwork = cm.activeNetworkInfo
+ return activeNetwork != null && activeNetwork.isConnectedOrConnecting
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/PlayServicesUtil.kt b/common/src/main/java/com/google/android/apps/santatracker/util/PlayServicesUtil.kt
new file mode 100644
index 000000000..049973ef4
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/util/PlayServicesUtil.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 com.google.android.gms.common.ConnectionResult
+import com.google.android.gms.common.GoogleApiAvailability
+
+object PlayServicesUtil {
+
+ @JvmStatic
+ fun hasPlayServices(context: Context): Boolean {
+ return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(
+ context) == ConnectionResult.SUCCESS
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/SantaLog.kt b/common/src/main/java/com/google/android/apps/santatracker/util/SantaLog.kt
new file mode 100644
index 000000000..dfc836c05
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/util/SantaLog.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.apps.santatracker.common.BuildConfig
+
+object SantaLog {
+ private val LOG_ENABLED = BuildConfig.BUILD_TYPE != "release"
+
+ @JvmStatic
+ fun v(tag: String, msg: String) {
+ if (LOG_ENABLED) {
+ Log.v(tag, msg)
+ }
+ }
+
+ @JvmStatic
+ fun w(tag: String, msg: String) {
+ if (LOG_ENABLED) {
+ Log.w(tag, msg)
+ }
+ }
+
+ @JvmStatic
+ fun w(tag: String, msg: String, t: Throwable?) {
+ if (LOG_ENABLED) {
+ Log.w(tag, msg, t)
+ }
+ }
+
+ @JvmStatic
+ fun e(tag: String, msg: String) {
+ Log.e(tag, msg)
+ }
+
+ @JvmStatic
+ fun e(tag: String, msg: String, t: Throwable?) {
+ Log.e(tag, msg, t)
+ }
+
+ @JvmStatic
+ fun d(tag: String, msg: String) {
+ if (LOG_ENABLED) {
+ Log.d(tag, msg)
+ }
+ }
+
+ @JvmStatic
+ fun i(tag: String, msg: String) {
+ if (LOG_ENABLED) {
+ Log.i(tag, msg)
+ }
+ }
+
+ @JvmStatic
+ fun d(tag: String, s: String, t: Throwable?) {
+ if (LOG_ENABLED) {
+ Log.d(tag, s, t)
+ }
+ }
+}
diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/SoundPoolExtensions.kt b/common/src/main/java/com/google/android/apps/santatracker/util/SoundPoolExtensions.kt
new file mode 100644
index 000000000..db379cb43
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/util/SoundPoolExtensions.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.media.SoundPool
+import com.google.android.apps.santatracker.AudioConstants
+
+/**
+ * Extension function to play a sound using some sane defaults
+ */
+fun SoundPool.play(
+ soundId: Int,
+ volume: Float = AudioConstants.DEFAULT_SOUND_EFFECT_VOLUME,
+ priority: Int = 0,
+ loop: Int = 0,
+ rate: Float = 1f
+) = play(soundId, volume, volume, priority, loop, rate)
+
+object SoundPoolUtils {
+ /**
+ * Util function to play a sound using some sane defaults. This is just for use from Java
+ */
+ @JvmOverloads
+ @JvmStatic
+ fun playSoundEffect(
+ soundPool: SoundPool,
+ soundId: Int,
+ volume: Float = AudioConstants.DEFAULT_SOUND_EFFECT_VOLUME,
+ priority: Int = 0,
+ loop: Int = 0,
+ rate: Float = 1f
+ ) = soundPool.play(soundId, volume, volume, priority, loop, rate)
+}
\ No newline at end of file
diff --git a/common/src/main/java/com/google/android/apps/santatracker/util/VectorUtil.kt b/common/src/main/java/com/google/android/apps/santatracker/util/VectorUtil.kt
new file mode 100644
index 000000000..20573a85b
--- /dev/null
+++ b/common/src/main/java/com/google/android/apps/santatracker/util/VectorUtil.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.graphics.Bitmap
+import android.graphics.Canvas
+import androidx.annotation.DrawableRes
+import androidx.core.content.res.ResourcesCompat
+import com.google.android.gms.maps.model.BitmapDescriptor
+import com.google.android.gms.maps.model.BitmapDescriptorFactory
+
+object VectorUtil {
+
+ @JvmStatic
+ fun vectorToBitmap(context: Context, @DrawableRes id: Int): BitmapDescriptor {
+ val vectorDrawable = ResourcesCompat.getDrawable(context.resources, id, null)
+ val bitmap = Bitmap.createBitmap(
+ vectorDrawable!!.intrinsicWidth,
+ vectorDrawable.intrinsicHeight,
+ Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(bitmap)
+ vectorDrawable.setBounds(0, 0, canvas.width, canvas.height)
+ vectorDrawable.draw(canvas)
+ return BitmapDescriptorFactory.fromBitmap(bitmap)
+ }
+}
diff --git a/common/src/main/res/drawable-hdpi/btn_play_yellow.webp b/common/src/main/res/drawable-hdpi/btn_play_yellow.webp
new file mode 100644
index 000000000..c77852539
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/btn_play_yellow.webp differ
diff --git a/common/src/main/res/drawable-hdpi/common_btn_pause.webp b/common/src/main/res/drawable-hdpi/common_btn_pause.webp
new file mode 100644
index 000000000..3d011cc53
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_pause.webp differ
diff --git a/common/src/main/res/drawable-hdpi/common_btn_play.webp b/common/src/main/res/drawable-hdpi/common_btn_play.webp
new file mode 100644
index 000000000..c77852539
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_play.webp differ
diff --git a/common/src/main/res/drawable-hdpi/common_btn_share.webp b/common/src/main/res/drawable-hdpi/common_btn_share.webp
new file mode 100644
index 000000000..ff2e3060e
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_share.webp differ
diff --git a/common/src/main/res/drawable-hdpi/common_btn_speaker_off.webp b/common/src/main/res/drawable-hdpi/common_btn_speaker_off.webp
new file mode 100644
index 000000000..f10129cc0
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_speaker_off.webp differ
diff --git a/common/src/main/res/drawable-hdpi/common_btn_speaker_on.webp b/common/src/main/res/drawable-hdpi/common_btn_speaker_on.webp
new file mode 100644
index 000000000..62fff3232
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/common_btn_speaker_on.webp differ
diff --git a/common/src/main/res/drawable-hdpi/games_share.png b/common/src/main/res/drawable-hdpi/games_share.png
deleted file mode 100644
index 1c693a867..000000000
Binary files a/common/src/main/res/drawable-hdpi/games_share.png and /dev/null differ
diff --git a/common/src/main/res/drawable-hdpi/games_share.webp b/common/src/main/res/drawable-hdpi/games_share.webp
new file mode 100644
index 000000000..b4fa7ace4
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/games_share.webp 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
deleted file mode 100644
index d96b26981..000000000
Binary files a/common/src/main/res/drawable-hdpi/games_share_pressed.png and /dev/null differ
diff --git a/common/src/main/res/drawable-hdpi/games_share_pressed.webp b/common/src/main/res/drawable-hdpi/games_share_pressed.webp
new file mode 100644
index 000000000..a2b6dbaf8
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/games_share_pressed.webp differ
diff --git a/common/src/main/res/drawable-hdpi/ic_launcher_foreground.webp b/common/src/main/res/drawable-hdpi/ic_launcher_foreground.webp
new file mode 100644
index 000000000..bee4e0bc6
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/ic_launcher_foreground.webp differ
diff --git a/common/src/main/res/drawable-hdpi/ornament.webp b/common/src/main/res/drawable-hdpi/ornament.webp
new file mode 100644
index 000000000..a1300747e
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/ornament.webp 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.webp b/common/src/main/res/drawable-hdpi/winner.webp
new file mode 100644
index 000000000..f1d810b30
Binary files /dev/null and b/common/src/main/res/drawable-hdpi/winner.webp differ
diff --git a/common/src/main/res/drawable-mdpi/btn_play_yellow.webp b/common/src/main/res/drawable-mdpi/btn_play_yellow.webp
new file mode 100644
index 000000000..ef12cf793
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/btn_play_yellow.webp differ
diff --git a/common/src/main/res/drawable-mdpi/common_btn_pause.webp b/common/src/main/res/drawable-mdpi/common_btn_pause.webp
new file mode 100644
index 000000000..d3694d683
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_pause.webp differ
diff --git a/common/src/main/res/drawable-mdpi/common_btn_play.webp b/common/src/main/res/drawable-mdpi/common_btn_play.webp
new file mode 100644
index 000000000..ef12cf793
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_play.webp differ
diff --git a/common/src/main/res/drawable-mdpi/common_btn_share.webp b/common/src/main/res/drawable-mdpi/common_btn_share.webp
new file mode 100644
index 000000000..e6031956a
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_share.webp differ
diff --git a/common/src/main/res/drawable-mdpi/common_btn_speaker_off.webp b/common/src/main/res/drawable-mdpi/common_btn_speaker_off.webp
new file mode 100644
index 000000000..c8fb6759a
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_speaker_off.webp differ
diff --git a/common/src/main/res/drawable-mdpi/common_btn_speaker_on.webp b/common/src/main/res/drawable-mdpi/common_btn_speaker_on.webp
new file mode 100644
index 000000000..25d3204c5
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/common_btn_speaker_on.webp differ
diff --git a/common/src/main/res/drawable-mdpi/games_share.png b/common/src/main/res/drawable-mdpi/games_share.png
deleted file mode 100644
index f6b58b926..000000000
Binary files a/common/src/main/res/drawable-mdpi/games_share.png and /dev/null differ
diff --git a/common/src/main/res/drawable-mdpi/games_share.webp b/common/src/main/res/drawable-mdpi/games_share.webp
new file mode 100644
index 000000000..64bc8f72b
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/games_share.webp 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
deleted file mode 100644
index 218c73df6..000000000
Binary files a/common/src/main/res/drawable-mdpi/games_share_pressed.png and /dev/null differ
diff --git a/common/src/main/res/drawable-mdpi/games_share_pressed.webp b/common/src/main/res/drawable-mdpi/games_share_pressed.webp
new file mode 100644
index 000000000..489b705ea
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/games_share_pressed.webp differ
diff --git a/common/src/main/res/drawable-mdpi/ic_launcher_foreground.webp b/common/src/main/res/drawable-mdpi/ic_launcher_foreground.webp
new file mode 100644
index 000000000..8abf03380
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/ic_launcher_foreground.webp differ
diff --git a/common/src/main/res/drawable-mdpi/ornament.webp b/common/src/main/res/drawable-mdpi/ornament.webp
new file mode 100644
index 000000000..7df186e7d
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/ornament.webp 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..dce0648fd 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.webp b/common/src/main/res/drawable-mdpi/winner.webp
new file mode 100644
index 000000000..afea42402
Binary files /dev/null and b/common/src/main/res/drawable-mdpi/winner.webp differ
diff --git a/common/src/main/res/drawable-nodpi/icon_ribbon_upsidedown_short.webp b/common/src/main/res/drawable-nodpi/icon_ribbon_upsidedown_short.webp
new file mode 100644
index 000000000..b62370349
Binary files /dev/null and b/common/src/main/res/drawable-nodpi/icon_ribbon_upsidedown_short.webp differ
diff --git a/common/src/main/res/drawable-nodpi/jetpack_background_day.webp b/common/src/main/res/drawable-nodpi/jetpack_background_day.webp
new file mode 100644
index 000000000..145664600
Binary files /dev/null and b/common/src/main/res/drawable-nodpi/jetpack_background_day.webp differ
diff --git a/common/src/main/res/drawable-nodpi/jetpack_background_evening.webp b/common/src/main/res/drawable-nodpi/jetpack_background_evening.webp
new file mode 100644
index 000000000..316f9fe69
Binary files /dev/null and b/common/src/main/res/drawable-nodpi/jetpack_background_evening.webp differ
diff --git a/common/src/main/res/drawable-nodpi/purple_rectangle_button.webp b/common/src/main/res/drawable-nodpi/purple_rectangle_button.webp
new file mode 100644
index 000000000..b6ae8684d
Binary files /dev/null and b/common/src/main/res/drawable-nodpi/purple_rectangle_button.webp 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
deleted file mode 100644
index bf333cc96..000000000
Binary files a/common/src/main/res/drawable-sw600dp-hdpi/games_share.png and /dev/null differ
diff --git a/common/src/main/res/drawable-sw600dp-hdpi/games_share.webp b/common/src/main/res/drawable-sw600dp-hdpi/games_share.webp
new file mode 100644
index 000000000..8c3a0a29f
Binary files /dev/null and b/common/src/main/res/drawable-sw600dp-hdpi/games_share.webp 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
deleted file mode 100644
index 76942ac3e..000000000
Binary files a/common/src/main/res/drawable-sw600dp-mdpi/games_share.png and /dev/null differ
diff --git a/common/src/main/res/drawable-sw600dp-mdpi/games_share.webp b/common/src/main/res/drawable-sw600dp-mdpi/games_share.webp
new file mode 100644
index 000000000..f8abdab40
Binary files /dev/null and b/common/src/main/res/drawable-sw600dp-mdpi/games_share.webp 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
deleted file mode 100644
index 76942ac3e..000000000
Binary files a/common/src/main/res/drawable-sw600dp-tvdpi/games_share.png and /dev/null differ
diff --git a/common/src/main/res/drawable-sw600dp-tvdpi/games_share.webp b/common/src/main/res/drawable-sw600dp-tvdpi/games_share.webp
new file mode 100644
index 000000000..f8abdab40
Binary files /dev/null and b/common/src/main/res/drawable-sw600dp-tvdpi/games_share.webp differ
diff --git a/common/src/main/res/drawable-xhdpi/btn_play_yellow.webp b/common/src/main/res/drawable-xhdpi/btn_play_yellow.webp
new file mode 100644
index 000000000..85f638de7
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/btn_play_yellow.webp differ
diff --git a/common/src/main/res/drawable-xhdpi/common_btn_pause.webp b/common/src/main/res/drawable-xhdpi/common_btn_pause.webp
new file mode 100644
index 000000000..9bd5ab5fe
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_pause.webp differ
diff --git a/common/src/main/res/drawable-xhdpi/common_btn_play.webp b/common/src/main/res/drawable-xhdpi/common_btn_play.webp
new file mode 100644
index 000000000..85f638de7
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_play.webp differ
diff --git a/common/src/main/res/drawable-xhdpi/common_btn_share.webp b/common/src/main/res/drawable-xhdpi/common_btn_share.webp
new file mode 100644
index 000000000..3e74912b0
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_share.webp differ
diff --git a/common/src/main/res/drawable-xhdpi/common_btn_speaker_off.webp b/common/src/main/res/drawable-xhdpi/common_btn_speaker_off.webp
new file mode 100644
index 000000000..934ea0f5a
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_speaker_off.webp differ
diff --git a/common/src/main/res/drawable-xhdpi/common_btn_speaker_on.webp b/common/src/main/res/drawable-xhdpi/common_btn_speaker_on.webp
new file mode 100644
index 000000000..55325bb08
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/common_btn_speaker_on.webp differ
diff --git a/common/src/main/res/drawable-xhdpi/games_share.png b/common/src/main/res/drawable-xhdpi/games_share.png
deleted file mode 100644
index 76942ac3e..000000000
Binary files a/common/src/main/res/drawable-xhdpi/games_share.png and /dev/null differ
diff --git a/common/src/main/res/drawable-xhdpi/games_share.webp b/common/src/main/res/drawable-xhdpi/games_share.webp
new file mode 100644
index 000000000..ae69a9dc7
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/games_share.webp 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
deleted file mode 100644
index bd2353d7c..000000000
Binary files a/common/src/main/res/drawable-xhdpi/games_share_pressed.png and /dev/null differ
diff --git a/common/src/main/res/drawable-xhdpi/games_share_pressed.webp b/common/src/main/res/drawable-xhdpi/games_share_pressed.webp
new file mode 100644
index 000000000..fa41e2e74
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/games_share_pressed.webp differ
diff --git a/common/src/main/res/drawable-xhdpi/ic_launcher_foreground.webp b/common/src/main/res/drawable-xhdpi/ic_launcher_foreground.webp
new file mode 100644
index 000000000..b34f4c381
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/ic_launcher_foreground.webp differ
diff --git a/common/src/main/res/drawable-xhdpi/ornament.webp b/common/src/main/res/drawable-xhdpi/ornament.webp
new file mode 100644
index 000000000..1dc54105d
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/ornament.webp 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.webp b/common/src/main/res/drawable-xhdpi/winner.webp
new file mode 100644
index 000000000..549646ee0
Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/winner.webp differ
diff --git a/common/src/main/res/drawable-xxhdpi/btn_play_yellow.webp b/common/src/main/res/drawable-xxhdpi/btn_play_yellow.webp
new file mode 100644
index 000000000..4f4ea8121
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/btn_play_yellow.webp differ
diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_pause.webp b/common/src/main/res/drawable-xxhdpi/common_btn_pause.webp
new file mode 100644
index 000000000..5b268d76f
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_pause.webp differ
diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_play.webp b/common/src/main/res/drawable-xxhdpi/common_btn_play.webp
new file mode 100644
index 000000000..4f4ea8121
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_play.webp differ
diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_share.webp b/common/src/main/res/drawable-xxhdpi/common_btn_share.webp
new file mode 100644
index 000000000..32e3c528d
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_share.webp differ
diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_speaker_off.webp b/common/src/main/res/drawable-xxhdpi/common_btn_speaker_off.webp
new file mode 100644
index 000000000..a445bf546
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_speaker_off.webp differ
diff --git a/common/src/main/res/drawable-xxhdpi/common_btn_speaker_on.webp b/common/src/main/res/drawable-xxhdpi/common_btn_speaker_on.webp
new file mode 100644
index 000000000..871117ad9
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/common_btn_speaker_on.webp differ
diff --git a/common/src/main/res/drawable-xxhdpi/games_share.png b/common/src/main/res/drawable-xxhdpi/games_share.png
deleted file mode 100644
index bf333cc96..000000000
Binary files a/common/src/main/res/drawable-xxhdpi/games_share.png and /dev/null differ
diff --git a/common/src/main/res/drawable-xxhdpi/games_share.webp b/common/src/main/res/drawable-xxhdpi/games_share.webp
new file mode 100644
index 000000000..8c3a0a29f
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/games_share.webp 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
deleted file mode 100644
index 363a2eb99..000000000
Binary files a/common/src/main/res/drawable-xxhdpi/games_share_pressed.png and /dev/null differ
diff --git a/common/src/main/res/drawable-xxhdpi/games_share_pressed.webp b/common/src/main/res/drawable-xxhdpi/games_share_pressed.webp
new file mode 100644
index 000000000..ba3fda338
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/games_share_pressed.webp differ
diff --git a/common/src/main/res/drawable-xxhdpi/ic_launcher_foreground.webp b/common/src/main/res/drawable-xxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 000000000..1147db515
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/common/src/main/res/drawable-xxhdpi/ornament.webp b/common/src/main/res/drawable-xxhdpi/ornament.webp
new file mode 100644
index 000000000..84e0c21d1
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/ornament.webp 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.webp b/common/src/main/res/drawable-xxhdpi/winner.webp
new file mode 100644
index 000000000..a1e9da6d7
Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/winner.webp differ
diff --git a/common/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.webp b/common/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 000000000..423ccbbaa
Binary files /dev/null and b/common/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.webp 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..9c332f917 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/avd_loading_bar.xml b/common/src/main/res/drawable/avd_loading_bar.xml
new file mode 100644
index 000000000..020e2cc61
--- /dev/null
+++ b/common/src/main/res/drawable/avd_loading_bar.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
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..1eb700d9a
--- /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/bg_copyright.xml b/common/src/main/res/drawable/bg_copyright.xml
new file mode 100644
index 000000000..18f2cd311
--- /dev/null
+++ b/common/src/main/res/drawable/bg_copyright.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/common/src/main/res/drawable/bg_top.xml b/common/src/main/res/drawable/bg_top.xml
new file mode 100644
index 000000000..041fd2344
--- /dev/null
+++ b/common/src/main/res/drawable/bg_top.xml
@@ -0,0 +1,24 @@
+
+
+
+ -
+
+
+ -
+
+
+
diff --git a/common/src/main/res/drawable/btn_pause_foreground.xml b/common/src/main/res/drawable/btn_pause_foreground.xml
new file mode 100644
index 000000000..21aab74dd
--- /dev/null
+++ b/common/src/main/res/drawable/btn_pause_foreground.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/common/src/main/res/drawable/btn_play_foreground.xml b/common/src/main/res/drawable/btn_play_foreground.xml
new file mode 100644
index 000000000..938f25a0e
--- /dev/null
+++ b/common/src/main/res/drawable/btn_play_foreground.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/common/src/main/res/drawable/btn_speaker_mute.xml b/common/src/main/res/drawable/btn_speaker_mute.xml
new file mode 100644
index 000000000..d00b39b85
--- /dev/null
+++ b/common/src/main/res/drawable/btn_speaker_mute.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
diff --git a/common/src/main/res/drawable/btn_speaker_on_foreground.xml b/common/src/main/res/drawable/btn_speaker_on_foreground.xml
new file mode 100644
index 000000000..ce922bea6
--- /dev/null
+++ b/common/src/main/res/drawable/btn_speaker_on_foreground.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
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..f15b3872e
--- /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/ic_launcher_background.xml b/common/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 000000000..c6ec666cd
--- /dev/null
+++ b/common/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/common/src/main/res/drawable/ic_launcher_foreground_inset.xml b/common/src/main/res/drawable/ic_launcher_foreground_inset.xml
new file mode 100644
index 000000000..6480cd03e
--- /dev/null
+++ b/common/src/main/res/drawable/ic_launcher_foreground_inset.xml
@@ -0,0 +1,22 @@
+
+
+
diff --git a/common/src/main/res/drawable/ic_pause_black_24dp.xml b/common/src/main/res/drawable/ic_pause_black_24dp.xml
new file mode 100644
index 000000000..92764cbce
--- /dev/null
+++ b/common/src/main/res/drawable/ic_pause_black_24dp.xml
@@ -0,0 +1,25 @@
+
+
+
+
diff --git a/common/src/main/res/drawable/loading_bar.xml b/common/src/main/res/drawable/loading_bar.xml
new file mode 100644
index 000000000..6f108c962
--- /dev/null
+++ b/common/src/main/res/drawable/loading_bar.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/common/src/main/res/drawable/score_background.xml b/common/src/main/res/drawable/score_background.xml
index 3b65eb5c9..cf6119f34 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..f57e12584 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/font/lobster.xml b/common/src/main/res/font/lobster.xml
new file mode 100644
index 000000000..db2f2ef54
--- /dev/null
+++ b/common/src/main/res/font/lobster.xml
@@ -0,0 +1,21 @@
+
+
+
diff --git a/common/src/main/res/layout/layout_loading_screen.xml b/common/src/main/res/layout/layout_loading_screen.xml
new file mode 100644
index 000000000..f5ddff6ee
--- /dev/null
+++ b/common/src/main/res/layout/layout_loading_screen.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
diff --git a/common/src/main/res/mipmap-anydpi-v26/ic_launcher_santa.xml b/common/src/main/res/mipmap-anydpi-v26/ic_launcher_santa.xml
new file mode 100644
index 000000000..18c2c3ef7
--- /dev/null
+++ b/common/src/main/res/mipmap-anydpi-v26/ic_launcher_santa.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/common/src/main/res/mipmap-hdpi/ic_launcher_santa.webp b/common/src/main/res/mipmap-hdpi/ic_launcher_santa.webp
new file mode 100644
index 000000000..1dfb88423
Binary files /dev/null and b/common/src/main/res/mipmap-hdpi/ic_launcher_santa.webp differ
diff --git a/common/src/main/res/mipmap-mdpi/ic_launcher_santa.webp b/common/src/main/res/mipmap-mdpi/ic_launcher_santa.webp
new file mode 100644
index 000000000..b409ffe6e
Binary files /dev/null and b/common/src/main/res/mipmap-mdpi/ic_launcher_santa.webp differ
diff --git a/common/src/main/res/mipmap-xhdpi/ic_launcher_santa.webp b/common/src/main/res/mipmap-xhdpi/ic_launcher_santa.webp
new file mode 100644
index 000000000..1ca89b68a
Binary files /dev/null and b/common/src/main/res/mipmap-xhdpi/ic_launcher_santa.webp differ
diff --git a/common/src/main/res/mipmap-xxhdpi/ic_launcher_santa.webp b/common/src/main/res/mipmap-xxhdpi/ic_launcher_santa.webp
new file mode 100644
index 000000000..ae94054f7
Binary files /dev/null and b/common/src/main/res/mipmap-xxhdpi/ic_launcher_santa.webp differ
diff --git a/common/src/main/res/mipmap-xxxhdpi/ic_launcher_santa.webp b/common/src/main/res/mipmap-xxxhdpi/ic_launcher_santa.webp
new file mode 100644
index 000000000..cb4578f71
Binary files /dev/null and b/common/src/main/res/mipmap-xxxhdpi/ic_launcher_santa.webp differ
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..b0a18dc4f
--- /dev/null
+++ b/common/src/main/res/values-af/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Speletjie verby
+ Laai tans skerm
+ Hervat
+ Herspeel
+ Tuis
+ Deel
+ Kon nie %1$s aflaai nie. Werk jou netwerkverbinding?
+
diff --git a/common/src/main/res/values-af/strings_appname.xml b/common/src/main/res/values-af/strings_appname.xml
new file mode 100644
index 000000000..24834203e
--- /dev/null
+++ b/common/src/main/res/values-af/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Waar is Kersvader
+
diff --git a/common/src/main/res/values-af/strings_doodles.xml b/common/src/main/res/values-af/strings_doodles.xml
new file mode 100644
index 000000000..c7d249b83
--- /dev/null
+++ b/common/src/main/res/values-af/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Sneeubal-hardloop
+ Pikkewynswem
+ Geskenkgooi
+ Beste: %1$s
+ Demp
+ Ontdemp
+ Maak toe
+ Laat wag
+ BESTE TELLING: <b>%1$s</b>
+ %1$.1f s.
+ %1$d m
+
diff --git a/common/src/main/res/values-af/strings_gamenames.xml b/common/src/main/res/values-af/strings_gamenames.xml
index e687c26e8..2ec794ba4 100644
--- a/common/src/main/res/values-af/strings_gamenames.xml
+++ b/common/src/main/res/values-af/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Geheue
- Elf-stralerpak
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Sneeubal-speletjie
- Snowdown
+ Gumball
+ Geheue
+ Elf-stralerpak
+ Vuurpylslee
+ Dasher-danser
+ Stadvasvra
+ Geskenksoektog
+ Kersvader-kiekie
+ Presentgooi
+ Elf-stralerpak
+ Noordpool-lughawe
+ Geskenkkettie
+ Kersvader-tekeninge
+ Kode-Boogie
+ Kodelaboratorium
+ Gumball-kantel
+ Elf-jamgroep
+ Pikkewynjaagtog
+ Geskenkhop
+ Aflaai van geskenke
+ Rudolph die jaer
+ Rendier-hardloper
+ Kersvader-soektog
+ Kersvader-selfie
+ Seisoen van geskenke
+ Elf-ski
+ Sneeubalstorm
+ Kodeer \'n sneeuvlokkie
+ Spoedskets
+ Toedraaistryd
+ Elf-maker
+ Terug werk toe
+ Kantoorpoets
+ Saamryklub
diff --git a/common/src/main/res/values-af/strings_invite.xml b/common/src/main/res/values-af/strings_invite.xml
index b0a98bf11..8c6daa72e 100644
--- a/common/src/main/res/values-af/strings_invite.xml
+++ b/common/src/main/res/values-af/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Nooi jou vriende om Kersvader met Google te volg
- Probeer Santa Tracker en kyk hoe Kersvader om die wêreld vlieg!
- Ek het %1$d aangeteken deur die %2$s-speletjie met die elwe in Santa Tracker te speel. Kan jy dit klop?
+ Nooi jou vriende om Kersvader met Google te volg
+ Probeer Santa Tracker en kyk hoe Kersvader om die wêreld vlieg!
+ Ek het %1$d aangeteken deur die %2$s-speletjie met die elwe in Santa Tracker te speel. Kan jy dit klop?
diff --git a/common/src/main/res/values-af/strings_jetpack.xml b/common/src/main/res/values-af/strings_jetpack.xml
index 12ee9cfe6..52319bc2f 100644
--- a/common/src/main/res/values-af/strings_jetpack.xml
+++ b/common/src/main/res/values-af/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Meld aan om prestasies te ontsluit en jou telling te plaas!
- Speel weer
- Telling
+ Meld aan om prestasies te ontsluit en jou telling te plaas!
+ Speel weer
+ Gaan terug na kaart
+ TELLING
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..02d4555ea
--- /dev/null
+++ b/common/src/main/res/values-ar-rXB/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Loading screen
+ Resume
+ Replay
+ Home
+ Share
+ An error occurred while downloading %1$s. Is your network connection working?
+
diff --git a/common/src/main/res/values-ar-rXB/strings_appname.xml b/common/src/main/res/values-ar-rXB/strings_appname.xml
new file mode 100644
index 000000000..9e3acc77d
--- /dev/null
+++ b/common/src/main/res/values-ar-rXB/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Santa Tracker
+
diff --git a/common/src/main/res/values-ar-rXB/strings_doodles.xml b/common/src/main/res/values-ar-rXB/strings_doodles.xml
new file mode 100644
index 000000000..4bbbd55c6
--- /dev/null
+++ b/common/src/main/res/values-ar-rXB/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snowball Run
+ Penguin Swim
+ Present Throw
+ Best: %1$s
+ Mute
+ Unmute
+ Close
+ Pause
+ BEST SCORE: <b>%1$s</b>
+ %1$.1fs
+ %1$dm
+
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..612a70efb 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ City Quiz
+ Present Quest
+ Santa Snap
+ Present Toss
+ Elf Jetpack
+ North Pole Airport
+ Gift Slingshot
+ Claus Draws
+ Code Boogie
+ Code Lab
+ Gumball Tilt
+ Elf Jamband
+ Penguin Dash
+ Present Bounce
+ Present Drop
+ Rudolph Racer
+ Reindeer Runner
+ Santa Search
+ Santa Selfie
+ Season of Giving
+ Elf Ski
+ Snowball Storm
+ Code a Snowflake
+ Speed Sketch
+ Wrap Battle
+ Elf Maker
+ Back to Work
+ Office Prank
+ Carpool
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..45c8cb58c 100644
--- a/common/src/main/res/values-ar-rXB/strings_invite.xml
+++ b/common/src/main/res/values-ar-rXB/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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?
+ 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-ar-rXB/strings_jetpack.xml b/common/src/main/res/values-ar-rXB/strings_jetpack.xml
index 66fe7a59f..aedf5c445 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,23 @@
+
+
- 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
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..c7278d244
--- /dev/null
+++ b/common/src/main/res/values-bg/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Назад към картата
+ Назад към селцето
+ Тази версия на приложението „Къде е Дядо Коледа“ не е актуална. Моля, посетете Google Play Магазин, за да актуализирате до най-новата версия.
+ Край на играта
+ Екранът се зарежда
+ Възобновяване
+ Повторно пускане
+ Начална страница
+ Споделяне
+ При изтеглянето на %1$s възникна грешка. Имате ли връзка с интернет?
+
diff --git a/common/src/main/res/values-bg/strings_appname.xml b/common/src/main/res/values-bg/strings_appname.xml
new file mode 100644
index 000000000..77829cbf9
--- /dev/null
+++ b/common/src/main/res/values-bg/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Къде е Дядо Коледа
+
diff --git a/common/src/main/res/values-bg/strings_doodles.xml b/common/src/main/res/values-bg/strings_doodles.xml
new file mode 100644
index 000000000..daafc7357
--- /dev/null
+++ b/common/src/main/res/values-bg/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Замерване със снежни топки
+ Плуващият пингвин
+ Хвърляне на подаръци
+ Най-добър резултат: %1$s
+ Без звук
+ Включване на звука
+ Затваряне
+ Поставяне на пауза
+ НАЙ-ДОБЪР РЕЗУЛТАТ: <b>%1$s</b>
+ %1$.1f сек
+ %1$d м
+
diff --git a/common/src/main/res/values-bg/strings_gamenames.xml b/common/src/main/res/values-bg/strings_gamenames.xml
index 8a7504c21..912d0e844 100644
--- a/common/src/main/res/values-bg/strings_gamenames.xml
+++ b/common/src/main/res/values-bg/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Гъмбол
- Мемори
- Реактивно джудже
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Игра „Snowball“
- Snowdown
+ Гъмбол
+ Мемори
+ Реактивно джудже
+ Rocket Sleigh
+ Dasher Dancer
+ Географска викторина
+ Търсене на подаръци
+ Коледни селфита
+ Хвърляне на подаръци
+ Реактивно джудже
+ Летище на Северния полюс
+ Стреляне с подаръци
+ Рисунки с коледно настроение
+ Танц за кодиране
+ Лаборатория за кодиране
+ Балансиране на топчета от дъвка
+ Джуджешка музика
+ Бързият пингвин
+ Подскачащи подаръци
+ Пускане на подаръци
+ Надпревара с Рудолф
+ Препускане с елен
+ Търсене на Дядо Коледа
+ Селфи на Дядо Коледа
+ Сезонът на щедростта
+ Джуджета на ски
+ Бой със снежни топки
+ Кодиране на снежинка
+ Рисуване върху заскрежено стъкло
+ Опаковане на подаръци
+ Създаване на джудже
+ Отново на работа
+ Офис шега
+ Споделено пътуване
diff --git a/common/src/main/res/values-bg/strings_invite.xml b/common/src/main/res/values-bg/strings_invite.xml
index 9c86eb1f8..8e8439f6e 100644
--- a/common/src/main/res/values-bg/strings_invite.xml
+++ b/common/src/main/res/values-bg/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Поканете приятелите си да следят Дядо Коледа с Google
- Изпробвайте „Къде е Дядо Коледа“ и гледайте как белобрадият старец лети по цял свят!
- Постигнах %1$d точки в играта %2$s с джуджетата в приложението на Google „Къде е Дядо Коледа“. Можете ли да надминете резултата ми?
+ Поканете приятелите си да следят Дядо Коледа с Google
+ Изпробвайте „Къде е Дядо Коледа“ и гледайте как белобрадият старец лети по цял свят!
+ Постигнах %1$d точки в играта %2$s с джуджетата в приложението на 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..c2833219e 100644
--- a/common/src/main/res/values-bg/strings_jetpack.xml
+++ b/common/src/main/res/values-bg/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Влезте в профила си, за да отключвате постижения и да публикувате резултата си!
- Нова игра
- Резултат
+ Влезте в профила си, за да отключвате постижения и да публикувате резултата си!
+ Нова игра
+ Назад към картата
+ РЕЗУЛТАТ
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..439d5b331
--- /dev/null
+++ b/common/src/main/res/values-ca/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Torna al mapa
+ Torna al llogaret
+ Aquesta versió de Segueix el Pare Noel està obsoleta. Ves a Play Store per actualitzar l\'aplicació a la versió més recent.
+ Fi de la partida
+ S\'està carregant la pantalla
+ Reprèn
+ Torna a jugar
+ Inici
+ Comparteix
+ S\'ha produït un error en baixar %1$s. Comprova que la connexió a la xarxa funcioni.
+
diff --git a/common/src/main/res/values-ca/strings_appname.xml b/common/src/main/res/values-ca/strings_appname.xml
new file mode 100644
index 000000000..bf6abca15
--- /dev/null
+++ b/common/src/main/res/values-ca/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Segueix el Pare Noel
+
diff --git a/common/src/main/res/values-ca/strings_doodles.xml b/common/src/main/res/values-ca/strings_doodles.xml
new file mode 100644
index 000000000..9533de6f3
--- /dev/null
+++ b/common/src/main/res/values-ca/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Fuig de la bola de neu
+ Pingüí nedador
+ Llançament de regals
+ Millor puntuació: %1$s
+ Silencia
+ Deixa de silenciar
+ Tanca
+ Posa en pausa
+ MILLOR PUNTUACIÓ: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-ca/strings_gamenames.xml b/common/src/main/res/values-ca/strings_gamenames.xml
index 72e11737a..2e785a6a4 100644
--- a/common/src/main/res/values-ca/strings_gamenames.xml
+++ b/common/src/main/res/values-ca/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- El joc Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Joc de les ciutats
+ Recerca de regals
+ Fotos nadalenques
+ Llançament de regals
+ Elf amb motxilla propulsora
+ Aeroport del Pol Nord
+ Joc de tirar regals
+ Dibuixos de Nadal
+ El ball del codi
+ Laboratori de programació
+ Joc de guiar els caramels
+ La banda dels elfs
+ Carrera de pingüins
+ Joc de rebotar regals
+ Joc de repartir regals
+ La cursa de trineus de Rudolf
+ Ren a la carrera
+ On és el Pare Noel?
+ La selfie del Pare Noel
+ Temps de regals
+ Els elfs van a esquiar
+ Tempesta de boles de neu
+ Crea un floc de neu amb codi
+ Esbós ràpid
+ Batalla d\'embolicar regals
+ Creador d\'elfs
+ Tornada a la feina
+ Broma a l\'oficina
+ Cotxe compartit
diff --git a/common/src/main/res/values-ca/strings_invite.xml b/common/src/main/res/values-ca/strings_invite.xml
index 181621836..5343db9e5 100644
--- a/common/src/main/res/values-ca/strings_invite.xml
+++ b/common/src/main/res/values-ca/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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.
- He aconseguit %1$d punts jugant amb els elfs al joc %2$s a Segueix el Pare Noel de Google. Aviam si em guanyes!
+ Convida els teus amics a seguir el Pare Noel amb Google
+ Prova l\'aplicació Segueix el Pare Noel i mira com vola per tot el món.
+ He aconseguit %1$d punts jugant a %2$s amb els elfs a Segueix el Pare Noel de Google. Aviam si em guanyes!
diff --git a/common/src/main/res/values-ca/strings_jetpack.xml b/common/src/main/res/values-ca/strings_jetpack.xml
index b026509f8..e4a2b99b2 100644
--- a/common/src/main/res/values-ca/strings_jetpack.xml
+++ b/common/src/main/res/values-ca/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Inicieu la sessió per desbloquejar assoliments i publicar la vostra puntuació
- Torna a jugar
- Puntuació
+ Inicia la sessió per desbloquejar assoliments i publicar la teva puntuació
+ Torna a jugar
+ Torna al mapa
+ PUNTUACIÓ
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..045da8932
--- /dev/null
+++ b/common/src/main/res/values-da/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Spillet er slut
+ Indlæsningsskærm
+ Genoptag
+ Spil videre
+ Gå til start
+ Del
+ Der opstod en fejl under download af %1$s. Er din netværksforbindelse i orden?
+
diff --git a/common/src/main/res/values-da/strings_appname.xml b/common/src/main/res/values-da/strings_appname.xml
new file mode 100644
index 000000000..8ce902d60
--- /dev/null
+++ b/common/src/main/res/values-da/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Følg julemanden
+
diff --git a/common/src/main/res/values-da/strings_doodles.xml b/common/src/main/res/values-da/strings_doodles.xml
new file mode 100644
index 000000000..13c1b4977
--- /dev/null
+++ b/common/src/main/res/values-da/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Løb fra snebolden
+ Pingvin på svømmetur
+ Gavekast
+ Højeste: %1$s
+ Slå lyden fra
+ Slå lyden til
+ Luk
+ Sæt på pause
+ HØJESTE SCORE: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-da/strings_gamenames.xml b/common/src/main/res/values-da/strings_gamenames.xml
index 3fb1976ad..5f2f68deb 100644
--- a/common/src/main/res/values-da/strings_gamenames.xml
+++ b/common/src/main/res/values-da/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snekuglespil
- Raketslædespil
- Julemandens rensdyr
- Sneboldspil
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Raketslædespil
+ Julemandens rensdyr
+ Kortquiz
+ Gavejagten
+ Julemands-snap
+ Gavekast
+ Nissejetpack
+ Nordpolens lufthavn
+ Slangebøsse med gaver
+ Julekruseduller
+ Kodeboogie
+ Kodelaboratorium
+ Rullende tyggegummikugler
+ Nissejamband
+ Pingvin med fart på
+ Gaveregn
+ Smid gaven
+ Racer-Rudolf
+ Få fat i gaverne med Rudolf
+ Find julemanden
+ Julemandsselfie
+ Årstiden for gaver
+ Nisseskiløb
+ Sneboldkrig
+ Lav et snefnug med kode
+ Hurtigtegner
+ Gaveindpakningens mester
+ Lav en nisse
+ Tilbage på arbejdet
+ Spøg på kontoret
+ Samkørsel
diff --git a/common/src/main/res/values-da/strings_invite.xml b/common/src/main/res/values-da/strings_invite.xml
index b8c78e7d9..847a3ec15 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!
- 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?
+ Inviter dine venner til at følge julemanden med Google
+ 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..eab21d974 100644
--- a/common/src/main/res/values-da/strings_jetpack.xml
+++ b/common/src/main/res/values-da/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Log ind for at låse op for resultater og indsende dine point.
- Spil igen
- Pointtal
+ Log ind for at låse op for resultater og indsende dine point.
+ Spil igen
+ Tilbage til kortet
+ POINT
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..2bdc33741
--- /dev/null
+++ b/common/src/main/res/values-de-rAT/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Ladebildschirm
+ Fortsetzen
+ Wiederholen
+ Weiter
+ Teilen
+ Beim Download von %1$s ist ein Fehler aufgetreten. Funktioniert deine Netzwerkverbindung?
+
diff --git a/common/src/main/res/values-de-rAT/strings_appname.xml b/common/src/main/res/values-de-rAT/strings_appname.xml
new file mode 100644
index 000000000..f1644cdd9
--- /dev/null
+++ b/common/src/main/res/values-de-rAT/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Auf den Spuren des Weihnachtsmanns
+
diff --git a/common/src/main/res/values-de-rAT/strings_doodles.xml b/common/src/main/res/values-de-rAT/strings_doodles.xml
new file mode 100644
index 000000000..dd80597cd
--- /dev/null
+++ b/common/src/main/res/values-de-rAT/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Schneeballrennen
+ Pinguinschwimmen
+ Geschenkewerfen
+ Bestes Ergebnis: %1$s
+ Stummschalten
+ Stummschaltung aufheben
+ Schließen
+ Pausieren
+ BESTES ERGEBNIS: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..ce82ae70f 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball Game
- Snowdown
+ Lolli-Flipper
+ Memory
+ Elf Jetpack
+ Raketen Flug
+ Weihnachts-Disco
+ Städte-Quiz
+ Geschenke-Schnitzeljagd
+ Weihnachtsmann-Selfie
+ Geschenkewerfen
+ Wichtel-Jetpack
+ Flughafen Nordpol
+ Geschenkeschleuder
+ Zeichnen mit dem Weihnachtsmann
+ Code-Boogie
+ Code-Lab
+ Lolli-Flipper
+ Wichtel-Wunschkonzert
+ Pinguin gib Acht
+ Geschenkeautomat
+ Bescherung
+ Rudolfs Rennen
+ Rasendes Rentier
+ Such den Weihnachtsmann
+ Weihnachtsmann-Selfie
+ Zeit des Gebens
+ Wichtel auf der Piste
+ Schneeballsturm
+ Schneeflockencode
+ Frostmaler
+ Verpackungskünstler
+ Wichtelkiste
+ Wieder bei der Arbeit
+ Bürostreich
+ Fahrgemeinschaften
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..61d3a7fa8 100644
--- a/common/src/main/res/values-de-rAT/strings_invite.xml
+++ b/common/src/main/res/values-de-rAT/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 \"Auf den Spuren des Weihnachtsmanns\" von Google das Spiel %2$s mit den Wichteln gespielt und %1$d Punkte erreicht. Schaffst du das auch?
+ 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 \"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-rAT/strings_jetpack.xml b/common/src/main/res/values-de-rAT/strings_jetpack.xml
index 94ecb86e2..d710d6d00 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,23 @@
+
+
- Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten!
- Neues Spiel
- Punktzahl
+ Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten!
+ Neues Spiel
+ Zurück zur Karte
+ PUNKTE
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..2bdc33741
--- /dev/null
+++ b/common/src/main/res/values-de-rCH/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Ladebildschirm
+ Fortsetzen
+ Wiederholen
+ Weiter
+ Teilen
+ Beim Download von %1$s ist ein Fehler aufgetreten. Funktioniert deine Netzwerkverbindung?
+
diff --git a/common/src/main/res/values-de-rCH/strings_appname.xml b/common/src/main/res/values-de-rCH/strings_appname.xml
new file mode 100644
index 000000000..f1644cdd9
--- /dev/null
+++ b/common/src/main/res/values-de-rCH/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Auf den Spuren des Weihnachtsmanns
+
diff --git a/common/src/main/res/values-de-rCH/strings_doodles.xml b/common/src/main/res/values-de-rCH/strings_doodles.xml
new file mode 100644
index 000000000..20290c3a9
--- /dev/null
+++ b/common/src/main/res/values-de-rCH/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Schneeballrennen
+ Pinguinschwimmen
+ Geschenkewerfen
+ Bestes Ergebnis: %1$s
+ Stummschalten
+ Stummschaltung aufheben
+ Schliessen
+ Pausieren
+ BESTES ERGEBNIS: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..ce82ae70f 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball Game
- Snowdown
+ Lolli-Flipper
+ Memory
+ Elf Jetpack
+ Raketen Flug
+ Weihnachts-Disco
+ Städte-Quiz
+ Geschenke-Schnitzeljagd
+ Weihnachtsmann-Selfie
+ Geschenkewerfen
+ Wichtel-Jetpack
+ Flughafen Nordpol
+ Geschenkeschleuder
+ Zeichnen mit dem Weihnachtsmann
+ Code-Boogie
+ Code-Lab
+ Lolli-Flipper
+ Wichtel-Wunschkonzert
+ Pinguin gib Acht
+ Geschenkeautomat
+ Bescherung
+ Rudolfs Rennen
+ Rasendes Rentier
+ Such den Weihnachtsmann
+ Weihnachtsmann-Selfie
+ Zeit des Gebens
+ Wichtel auf der Piste
+ Schneeballsturm
+ Schneeflockencode
+ Frostmaler
+ Verpackungskünstler
+ Wichtelkiste
+ Wieder bei der Arbeit
+ Bürostreich
+ Fahrgemeinschaften
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..61d3a7fa8 100644
--- a/common/src/main/res/values-de-rCH/strings_invite.xml
+++ b/common/src/main/res/values-de-rCH/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 \"Auf den Spuren des Weihnachtsmanns\" von Google das Spiel %2$s mit den Wichteln gespielt und %1$d Punkte erreicht. Schaffst du das auch?
+ 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 \"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-rCH/strings_jetpack.xml b/common/src/main/res/values-de-rCH/strings_jetpack.xml
index 94ecb86e2..d710d6d00 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,23 @@
+
+
- Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten!
- Neues Spiel
- Punktzahl
+ Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten!
+ Neues Spiel
+ Zurück zur Karte
+ PUNKTE
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..2bdc33741
--- /dev/null
+++ b/common/src/main/res/values-de/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Ladebildschirm
+ Fortsetzen
+ Wiederholen
+ Weiter
+ Teilen
+ Beim Download von %1$s ist ein Fehler aufgetreten. Funktioniert deine Netzwerkverbindung?
+
diff --git a/common/src/main/res/values-de/strings_appname.xml b/common/src/main/res/values-de/strings_appname.xml
new file mode 100644
index 000000000..f1644cdd9
--- /dev/null
+++ b/common/src/main/res/values-de/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Auf den Spuren des Weihnachtsmanns
+
diff --git a/common/src/main/res/values-de/strings_doodles.xml b/common/src/main/res/values-de/strings_doodles.xml
new file mode 100644
index 000000000..dd80597cd
--- /dev/null
+++ b/common/src/main/res/values-de/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Schneeballrennen
+ Pinguinschwimmen
+ Geschenkewerfen
+ Bestes Ergebnis: %1$s
+ Stummschalten
+ Stummschaltung aufheben
+ Schließen
+ Pausieren
+ BESTES ERGEBNIS: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-de/strings_gamenames.xml b/common/src/main/res/values-de/strings_gamenames.xml
index bc79191c0..ce82ae70f 100644
--- a/common/src/main/res/values-de/strings_gamenames.xml
+++ b/common/src/main/res/values-de/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball Game
- Snowdown
+ Lolli-Flipper
+ Memory
+ Elf Jetpack
+ Raketen Flug
+ Weihnachts-Disco
+ Städte-Quiz
+ Geschenke-Schnitzeljagd
+ Weihnachtsmann-Selfie
+ Geschenkewerfen
+ Wichtel-Jetpack
+ Flughafen Nordpol
+ Geschenkeschleuder
+ Zeichnen mit dem Weihnachtsmann
+ Code-Boogie
+ Code-Lab
+ Lolli-Flipper
+ Wichtel-Wunschkonzert
+ Pinguin gib Acht
+ Geschenkeautomat
+ Bescherung
+ Rudolfs Rennen
+ Rasendes Rentier
+ Such den Weihnachtsmann
+ Weihnachtsmann-Selfie
+ Zeit des Gebens
+ Wichtel auf der Piste
+ Schneeballsturm
+ Schneeflockencode
+ Frostmaler
+ Verpackungskünstler
+ Wichtelkiste
+ Wieder bei der Arbeit
+ Bürostreich
+ Fahrgemeinschaften
diff --git a/common/src/main/res/values-de/strings_invite.xml b/common/src/main/res/values-de/strings_invite.xml
index 600b50fbd..61d3a7fa8 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
+ 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 \"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..d710d6d00 100644
--- a/common/src/main/res/values-de/strings_jetpack.xml
+++ b/common/src/main/res/values-de/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten!
- Neues Spiel
- Punktzahl
+ Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten!
+ Neues Spiel
+ Zurück zur Karte
+ PUNKTE
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..2079fb480
--- /dev/null
+++ b/common/src/main/res/values-en-rGB/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Loading screen
+ Resume
+ Replay
+ Home
+ Share
+ An error occurred while downloading %1$s. Is your network connection working?
+
diff --git a/common/src/main/res/values-en-rGB/strings_appname.xml b/common/src/main/res/values-en-rGB/strings_appname.xml
new file mode 100644
index 000000000..77d556f56
--- /dev/null
+++ b/common/src/main/res/values-en-rGB/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Santa Tracker
+
diff --git a/common/src/main/res/values-en-rGB/strings_doodles.xml b/common/src/main/res/values-en-rGB/strings_doodles.xml
new file mode 100644
index 000000000..a896b117e
--- /dev/null
+++ b/common/src/main/res/values-en-rGB/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snowball Run
+ Penguin Swim
+ Present Throw
+ Best: %1$s
+ Mute
+ Unmute
+ Close
+ Pause
+ BEST SCORE: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..a21938901 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ City Quiz
+ Present Quest
+ Santa Snap
+ Present Toss
+ Elf Jetpack
+ North Pole Airport
+ Gift Slingshot
+ Claus Draws
+ Code Boogie
+ Code Lab
+ Gumball Tilt
+ Elf Jam Band
+ Penguin Dash
+ Present Bounce
+ Present Drop
+ Rudolph Racer
+ Reindeer Runner
+ Santa Search
+ Santa Selfie
+ Season of Giving
+ Elf Ski
+ Snowball Storm
+ Code a Snowflake
+ Speed Sketch
+ Wrap Battle
+ Elf Maker
+ Back to Work
+ Office Prank
+ Carpool
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..2ea2e73f7 100644
--- a/common/src/main/res/values-en-rGB/strings_invite.xml
+++ b/common/src/main/res/values-en-rGB/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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?
+ 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-en-rGB/strings_jetpack.xml b/common/src/main/res/values-en-rGB/strings_jetpack.xml
index 428344416..494e8d531 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,23 @@
+
+
- 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
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..2079fb480
--- /dev/null
+++ b/common/src/main/res/values-en-rIE/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Loading screen
+ Resume
+ Replay
+ Home
+ Share
+ An error occurred while downloading %1$s. Is your network connection working?
+
diff --git a/common/src/main/res/values-en-rIE/strings_appname.xml b/common/src/main/res/values-en-rIE/strings_appname.xml
new file mode 100644
index 000000000..77d556f56
--- /dev/null
+++ b/common/src/main/res/values-en-rIE/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Santa Tracker
+
diff --git a/common/src/main/res/values-en-rIE/strings_doodles.xml b/common/src/main/res/values-en-rIE/strings_doodles.xml
new file mode 100644
index 000000000..a896b117e
--- /dev/null
+++ b/common/src/main/res/values-en-rIE/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snowball Run
+ Penguin Swim
+ Present Throw
+ Best: %1$s
+ Mute
+ Unmute
+ Close
+ Pause
+ BEST SCORE: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..a21938901 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ City Quiz
+ Present Quest
+ Santa Snap
+ Present Toss
+ Elf Jetpack
+ North Pole Airport
+ Gift Slingshot
+ Claus Draws
+ Code Boogie
+ Code Lab
+ Gumball Tilt
+ Elf Jam Band
+ Penguin Dash
+ Present Bounce
+ Present Drop
+ Rudolph Racer
+ Reindeer Runner
+ Santa Search
+ Santa Selfie
+ Season of Giving
+ Elf Ski
+ Snowball Storm
+ Code a Snowflake
+ Speed Sketch
+ Wrap Battle
+ Elf Maker
+ Back to Work
+ Office Prank
+ Carpool
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..2ea2e73f7 100644
--- a/common/src/main/res/values-en-rIE/strings_invite.xml
+++ b/common/src/main/res/values-en-rIE/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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?
+ 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-en-rIE/strings_jetpack.xml b/common/src/main/res/values-en-rIE/strings_jetpack.xml
index 428344416..494e8d531 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,23 @@
+
+
- 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
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..2079fb480
--- /dev/null
+++ b/common/src/main/res/values-en-rIN/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Loading screen
+ Resume
+ Replay
+ Home
+ Share
+ An error occurred while downloading %1$s. Is your network connection working?
+
diff --git a/common/src/main/res/values-en-rIN/strings_appname.xml b/common/src/main/res/values-en-rIN/strings_appname.xml
new file mode 100644
index 000000000..77d556f56
--- /dev/null
+++ b/common/src/main/res/values-en-rIN/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Santa Tracker
+
diff --git a/common/src/main/res/values-en-rIN/strings_doodles.xml b/common/src/main/res/values-en-rIN/strings_doodles.xml
new file mode 100644
index 000000000..a896b117e
--- /dev/null
+++ b/common/src/main/res/values-en-rIN/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snowball Run
+ Penguin Swim
+ Present Throw
+ Best: %1$s
+ Mute
+ Unmute
+ Close
+ Pause
+ BEST SCORE: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..a21938901 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ City Quiz
+ Present Quest
+ Santa Snap
+ Present Toss
+ Elf Jetpack
+ North Pole Airport
+ Gift Slingshot
+ Claus Draws
+ Code Boogie
+ Code Lab
+ Gumball Tilt
+ Elf Jam Band
+ Penguin Dash
+ Present Bounce
+ Present Drop
+ Rudolph Racer
+ Reindeer Runner
+ Santa Search
+ Santa Selfie
+ Season of Giving
+ Elf Ski
+ Snowball Storm
+ Code a Snowflake
+ Speed Sketch
+ Wrap Battle
+ Elf Maker
+ Back to Work
+ Office Prank
+ Carpool
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..2ea2e73f7 100644
--- a/common/src/main/res/values-en-rIN/strings_invite.xml
+++ b/common/src/main/res/values-en-rIN/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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?
+ 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-en-rIN/strings_jetpack.xml b/common/src/main/res/values-en-rIN/strings_jetpack.xml
index 428344416..494e8d531 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,23 @@
+
+
- 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
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..2079fb480
--- /dev/null
+++ b/common/src/main/res/values-en-rSG/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Loading screen
+ Resume
+ Replay
+ Home
+ Share
+ An error occurred while downloading %1$s. Is your network connection working?
+
diff --git a/common/src/main/res/values-en-rSG/strings_appname.xml b/common/src/main/res/values-en-rSG/strings_appname.xml
new file mode 100644
index 000000000..77d556f56
--- /dev/null
+++ b/common/src/main/res/values-en-rSG/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Santa Tracker
+
diff --git a/common/src/main/res/values-en-rSG/strings_doodles.xml b/common/src/main/res/values-en-rSG/strings_doodles.xml
new file mode 100644
index 000000000..a896b117e
--- /dev/null
+++ b/common/src/main/res/values-en-rSG/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snowball Run
+ Penguin Swim
+ Present Throw
+ Best: %1$s
+ Mute
+ Unmute
+ Close
+ Pause
+ BEST SCORE: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..a21938901 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ City Quiz
+ Present Quest
+ Santa Snap
+ Present Toss
+ Elf Jetpack
+ North Pole Airport
+ Gift Slingshot
+ Claus Draws
+ Code Boogie
+ Code Lab
+ Gumball Tilt
+ Elf Jam Band
+ Penguin Dash
+ Present Bounce
+ Present Drop
+ Rudolph Racer
+ Reindeer Runner
+ Santa Search
+ Santa Selfie
+ Season of Giving
+ Elf Ski
+ Snowball Storm
+ Code a Snowflake
+ Speed Sketch
+ Wrap Battle
+ Elf Maker
+ Back to Work
+ Office Prank
+ Carpool
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..2ea2e73f7 100644
--- a/common/src/main/res/values-en-rSG/strings_invite.xml
+++ b/common/src/main/res/values-en-rSG/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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?
+ 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-en-rSG/strings_jetpack.xml b/common/src/main/res/values-en-rSG/strings_jetpack.xml
index 428344416..494e8d531 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,23 @@
+
+
- 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
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..8ed82537c
--- /dev/null
+++ b/common/src/main/res/values-en-rXA/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ [Бåçķ ţö 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]
+ [Ĝåmé Övéŕ one two]
+ [Ļöåðîñĝ šçŕééñ one two]
+ [Ŕéšûmé one]
+ [Ŕéþļåý one]
+ [Ĥömé one]
+ [Šĥåŕé one]
+ [Åñ éŕŕöŕ öççûŕŕéð ŵĥîļé ðöŵñļöåðîñĝ ᐅ%1$sᐊ. Κ ýöûŕ ñéţŵöŕķ çöññéçţîöñ ŵöŕķîñĝ¿ one two three four five six seven eight nine ten eleven twelve thirteen fourteen]
+
diff --git a/common/src/main/res/values-en-rXA/strings_appname.xml b/common/src/main/res/values-en-rXA/strings_appname.xml
new file mode 100644
index 000000000..48c384061
--- /dev/null
+++ b/common/src/main/res/values-en-rXA/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ [Šåñţå Ţŕåçķéŕ one two]
+
diff --git a/common/src/main/res/values-en-rXA/strings_doodles.xml b/common/src/main/res/values-en-rXA/strings_doodles.xml
new file mode 100644
index 000000000..0cd6de23e
--- /dev/null
+++ b/common/src/main/res/values-en-rXA/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ [Šñöŵбåļļ Ŕûñ one two]
+ [Þéñĝûîñ Šŵîm one two]
+ [Þŕéšéñţ Ţĥŕöŵ one two]
+ [Бéšţ: ᐅ%1$sᐊ one two three]
+ [Mûţé one]
+ [Ûñmûţé one]
+ [Çļöšé one]
+ [Þåûšé one]
+ [БÉŠŢ ŠÇÖŔÉ: <b>ᐅ%1$sᐊ</b> one two three four]
+ [ᐅ%1$.1fᐊš one]
+ [ᐅ%1$dᐊm one]
+
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..aad0c0e00 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,53 @@
+
+
- [Ĝû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]
+ [Çîţý Qûîž one two]
+ [Þŕéšéñţ Qûéšţ one two]
+ [Šåñţå Šñåþ one two]
+ [Þŕéšéñţ Ţöšš one two]
+ [Éļƒ Ĵéţþåçķ one two]
+ [Ñöŕţĥ Þöļé Åîŕþöŕţ one two three]
+ [Ĝîƒţ Šļîñĝšĥöţ one two]
+ [Çļåûš Ðŕåŵš one two]
+ [Çöðé Бööĝîé one two]
+ [Çöðé Ļåб one]
+ [Ĝûmбåļļ Ţîļţ one two]
+ [Éļƒ Ĵåmбåñð one two]
+ [Þéñĝûîñ Ðåšĥ one two]
+ [Þŕéšéñţ Бöûñçé one two]
+ [Þŕéšéñţ Ðŕöþ one two]
+ [Ŕûðöļþĥ Ŕåçéŕ one two]
+ [Ŕéîñðééŕ Ŕûññéŕ one two]
+ [Šåñţå Šéåŕçĥ one two]
+ [Šåñţå Šéļƒîé one two]
+ [Šéåšöñ öƒ Ĝîvîñĝ one two]
+ [Éļƒ Šķî one]
+ [Šñöŵбåļļ Šţöŕm one two]
+ [Çöðé å Šñöŵƒļåķé one two]
+ [Šþééð Šķéţçĥ one two]
+ [Ŵŕåþ Бåţţļé one two]
+ [Éļƒ Måķéŕ one two]
+ [Бåçķ ţö Ŵöŕķ one two]
+ [Öƒƒîçé Þŕåñķ one two]
+ [Çåŕþööļ one]
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..5ac06a926 100644
--- a/common/src/main/res/values-en-rXA/strings_invite.xml
+++ b/common/src/main/res/values-en-rXA/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- [Îñvîţé ýöûŕ ƒŕîéñðš ţö ţŕåçķ Šåñţå ŵîţĥ Ĝööĝļé one two three four five six seven eight nine ten]
- [Ţŕý Šåñţå Ţŕåçķéŕ åñð ŵåţçĥ Šåñţå ƒļý åŕöûñð ţĥé ŵöŕļð¡ one two three four five six seven eight nine ten eleven]
- [Î šçöŕéð ᐅ%1$dᐊ þļåýîñĝ ţĥé ᐅ%2$sᐊ ĝåmé ŵîţĥ ţĥé éļvéš îñ Ĝööĝļé\'š Šåñţå Ţŕåçķéŕ, çåñ ýöû бéåţ ţĥåţ¿ one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen]
+ [Îñvîţé ýöûŕ ƒŕîéñðš ţö ţŕåçķ Šåñţå ŵîţĥ Ĝööĝļé one two three four five six seven eight nine ten]
+ [Ţŕý Šåñţå Ţŕåçķéŕ åñð ŵåţçĥ Šåñţå ƒļý åŕöûñð ţĥé ŵöŕļð¡ one two three four five six seven eight nine ten eleven]
+ [Î šçöŕéð ᐅ%1$dᐊ þļåýîñĝ ţĥé ᐅ%2$sᐊ ĝåmé ŵîţĥ ţĥé éļvéš îñ Ĝööĝļé\'š Šåñţå Ţŕåçķéŕ, çåñ ýöû бéåţ ţĥåţ¿ one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen]
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..7fa8cff9e 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,23 @@
+
+
- [Šîĝñ îñ ţö ûñļöçķ åçĥîévéméñţš åñð þöšţ ýöûŕ šçöŕé¡ one two three four five six seven eight nine ten eleven]
- [Þļåý Åĝåîñ one two]
- [Šçöŕé one]
+ [Šîĝñ îñ ţö ûñļöçķ åçĥîévéméñţš åñð þöšţ ýöûŕ šçöŕé¡ one two three four five six seven eight nine ten eleven]
+ [Þļåý Åĝåîñ one two]
+ [Ŕéţûŕñ ţö Måþ one two]
+ [ŠÇÖŔÉ one]
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..86f3a435a
--- /dev/null
+++ b/common/src/main/res/values-en-rXC/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Loading screen
+ Resume
+ Replay
+ Home
+ Share
+ An error occurred while downloading %1$s. Is your network connection working?
+
diff --git a/common/src/main/res/values-en-rXC/strings_appname.xml b/common/src/main/res/values-en-rXC/strings_appname.xml
new file mode 100644
index 000000000..c0fac02cd
--- /dev/null
+++ b/common/src/main/res/values-en-rXC/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Santa Tracker
+
diff --git a/common/src/main/res/values-en-rXC/strings_doodles.xml b/common/src/main/res/values-en-rXC/strings_doodles.xml
new file mode 100644
index 000000000..da75865e0
--- /dev/null
+++ b/common/src/main/res/values-en-rXC/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snowball Run
+ Penguin Swim
+ Present Throw
+ Best: %1$s
+ Mute
+ Unmute
+ Close
+ Pause
+ BEST SCORE: <b>%1$s</b>
+ %1$.1fs
+ %1$dm
+
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..ef97d56ef 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ City Quiz
+ Present Quest
+ Santa Snap
+ Present Toss
+ Elf Jetpack
+ North Pole Airport
+ Gift Slingshot
+ Claus Draws
+ Code Boogie
+ Code Lab
+ Gumball Tilt
+ Elf Jamband
+ Penguin Dash
+ Present Bounce
+ Present Drop
+ Rudolph Racer
+ Reindeer Runner
+ Santa Search
+ Santa Selfie
+ Season of Giving
+ Elf Ski
+ Snowball Storm
+ Code a Snowflake
+ Speed Sketch
+ Wrap Battle
+ Elf Maker
+ Back to Work
+ Office Prank
+ Carpool
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..eab69030a 100644
--- a/common/src/main/res/values-en-rXC/strings_invite.xml
+++ b/common/src/main/res/values-en-rXC/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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?
+ 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-en-rXC/strings_jetpack.xml b/common/src/main/res/values-en-rXC/strings_jetpack.xml
index 8ea177340..002cf140a 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,23 @@
+
+
- 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
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..2079fb480
--- /dev/null
+++ b/common/src/main/res/values-en-rZA/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Loading screen
+ Resume
+ Replay
+ Home
+ Share
+ An error occurred while downloading %1$s. Is your network connection working?
+
diff --git a/common/src/main/res/values-en-rZA/strings_appname.xml b/common/src/main/res/values-en-rZA/strings_appname.xml
new file mode 100644
index 000000000..77d556f56
--- /dev/null
+++ b/common/src/main/res/values-en-rZA/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Santa Tracker
+
diff --git a/common/src/main/res/values-en-rZA/strings_doodles.xml b/common/src/main/res/values-en-rZA/strings_doodles.xml
new file mode 100644
index 000000000..a896b117e
--- /dev/null
+++ b/common/src/main/res/values-en-rZA/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snowball Run
+ Penguin Swim
+ Present Throw
+ Best: %1$s
+ Mute
+ Unmute
+ Close
+ Pause
+ BEST SCORE: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..a21938901 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ City Quiz
+ Present Quest
+ Santa Snap
+ Present Toss
+ Elf Jetpack
+ North Pole Airport
+ Gift Slingshot
+ Claus Draws
+ Code Boogie
+ Code Lab
+ Gumball Tilt
+ Elf Jam Band
+ Penguin Dash
+ Present Bounce
+ Present Drop
+ Rudolph Racer
+ Reindeer Runner
+ Santa Search
+ Santa Selfie
+ Season of Giving
+ Elf Ski
+ Snowball Storm
+ Code a Snowflake
+ Speed Sketch
+ Wrap Battle
+ Elf Maker
+ Back to Work
+ Office Prank
+ Carpool
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..2ea2e73f7 100644
--- a/common/src/main/res/values-en-rZA/strings_invite.xml
+++ b/common/src/main/res/values-en-rZA/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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?
+ 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-en-rZA/strings_jetpack.xml b/common/src/main/res/values-en-rZA/strings_jetpack.xml
index 428344416..494e8d531 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,23 @@
+
+
- 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
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rAR/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rAR/strings_appname.xml b/common/src/main/res/values-es-rAR/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rAR/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rAR/strings_doodles.xml b/common/src/main/res/values-es-rAR/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rAR/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rBO/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rBO/strings_appname.xml b/common/src/main/res/values-es-rBO/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rBO/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rBO/strings_doodles.xml b/common/src/main/res/values-es-rBO/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rBO/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rCL/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rCL/strings_appname.xml b/common/src/main/res/values-es-rCL/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rCL/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rCL/strings_doodles.xml b/common/src/main/res/values-es-rCL/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rCL/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rCO/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rCO/strings_appname.xml b/common/src/main/res/values-es-rCO/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rCO/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rCO/strings_doodles.xml b/common/src/main/res/values-es-rCO/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rCO/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rCR/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rCR/strings_appname.xml b/common/src/main/res/values-es-rCR/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rCR/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rCR/strings_doodles.xml b/common/src/main/res/values-es-rCR/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rCR/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rDO/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rDO/strings_appname.xml b/common/src/main/res/values-es-rDO/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rDO/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rDO/strings_doodles.xml b/common/src/main/res/values-es-rDO/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rDO/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rEC/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rEC/strings_appname.xml b/common/src/main/res/values-es-rEC/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rEC/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rEC/strings_doodles.xml b/common/src/main/res/values-es-rEC/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rEC/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
diff --git a/common/src/main/res/values-es-rES/strings_appname.xml b/common/src/main/res/values-es-rES/strings_appname.xml
new file mode 100644
index 000000000..b633229e8
--- /dev/null
+++ b/common/src/main/res/values-es-rES/strings_appname.xml
@@ -0,0 +1,18 @@
+
+
+ Sigue a Santa
+
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..fc0b751df
--- 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,22 @@
-
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
+
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
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..0038b07ed 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,19 @@
-
- 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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rGT/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rGT/strings_appname.xml b/common/src/main/res/values-es-rGT/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rGT/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rGT/strings_doodles.xml b/common/src/main/res/values-es-rGT/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rGT/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rHN/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rHN/strings_appname.xml b/common/src/main/res/values-es-rHN/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rHN/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rHN/strings_doodles.xml b/common/src/main/res/values-es-rHN/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rHN/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rMX/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rMX/strings_appname.xml b/common/src/main/res/values-es-rMX/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rMX/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rMX/strings_doodles.xml b/common/src/main/res/values-es-rMX/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rMX/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rNI/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rNI/strings_appname.xml b/common/src/main/res/values-es-rNI/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rNI/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rNI/strings_doodles.xml b/common/src/main/res/values-es-rNI/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rNI/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rPA/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rPA/strings_appname.xml b/common/src/main/res/values-es-rPA/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rPA/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rPA/strings_doodles.xml b/common/src/main/res/values-es-rPA/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rPA/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rPE/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rPE/strings_appname.xml b/common/src/main/res/values-es-rPE/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rPE/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rPE/strings_doodles.xml b/common/src/main/res/values-es-rPE/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rPE/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rPR/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rPR/strings_appname.xml b/common/src/main/res/values-es-rPR/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rPR/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rPR/strings_doodles.xml b/common/src/main/res/values-es-rPR/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rPR/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rPY/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rPY/strings_appname.xml b/common/src/main/res/values-es-rPY/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rPY/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rPY/strings_doodles.xml b/common/src/main/res/values-es-rPY/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rPY/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rSV/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rSV/strings_appname.xml b/common/src/main/res/values-es-rSV/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rSV/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rSV/strings_doodles.xml b/common/src/main/res/values-es-rSV/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rSV/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rUS/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rUS/strings_appname.xml b/common/src/main/res/values-es-rUS/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rUS/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rUS/strings_doodles.xml b/common/src/main/res/values-es-rUS/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rUS/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rUY/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rUY/strings_appname.xml b/common/src/main/res/values-es-rUY/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rUY/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rUY/strings_doodles.xml b/common/src/main/res/values-es-rUY/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rUY/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..06b435697
--- /dev/null
+++ b/common/src/main/res/values-es-rVE/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin del juego
+ Pantalla de carga
+ Reanudar
+ Volver a jugar
+ Inicio
+ Compartir
+ No se pudo descargar %1$s. ¿Funciona bien tu conexión de red?
+
diff --git a/common/src/main/res/values-es-rVE/strings_appname.xml b/common/src/main/res/values-es-rVE/strings_appname.xml
new file mode 100644
index 000000000..8670a7f83
--- /dev/null
+++ b/common/src/main/res/values-es-rVE/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Santa
+
diff --git a/common/src/main/res/values-es-rVE/strings_doodles.xml b/common/src/main/res/values-es-rVE/strings_doodles.xml
new file mode 100644
index 000000000..f8e572e76
--- /dev/null
+++ b/common/src/main/res/values-es-rVE/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Carrera de bolas de nieve
+ Nada con los pingüinos
+ Lanzamiento de regalos
+ Mejor puntuación: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..56a6d49f1 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Cuestionario sobre ciudades
+ Busca regalos
+ Instantáneas navideñas
+ Lanzamiento de regalos
+ Duendes con propulsores
+ Aeropuerto del Polo Norte
+ Honda de regalos
+ Dibujos navideños con Santa
+ Baile de código
+ Laboratorio de códigos
+ Guía las Gumballs
+ Banda de duendes
+ Carrera de pingüinos
+ Rebotes de regalos
+ Entrega de regalos
+ Trineo de carreras de Rudolph
+ Reno corredor
+ Búsqueda de Santa
+ Selfies de Santa
+ Época de dar
+ Duendes en esquí
+ Tormenta de bolas de nieve
+ Codifica un copo de nieve
+ Dibujos rápidos
+ Revuelta de envoltorios
+ Crea tu duende
+ De vuelta al trabajo
+ Broma de oficina
+ Viaje compartido
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..4bf8b6a3e 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.
- Mi puntuación es de %1$d en el juego %2$s con los duendes en Sigue a Santa de Google. ¿Puedes vencerme?
+ Invita a tus amigos a seguir a Santa con Google
+ 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..3b5ee47ae 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,23 @@
+
+
- ¡Accede para desbloquear logros y publicar tu puntuación!
- Volver a jugar
- Puntuación
+ ¡Accede para desbloquear logros y publicar tu puntuación!
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..3cf5f3ae7
--- /dev/null
+++ b/common/src/main/res/values-es/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fin de la partida
+ Cargando pantalla
+ Reanudar
+ Reiniciar partida
+ Inicio
+ Compartir
+ No se ha podido descargar %1$s. Comprueba que tu conexión de red funciona correctamente.
+
diff --git a/common/src/main/res/values-es/strings_appname.xml b/common/src/main/res/values-es/strings_appname.xml
new file mode 100644
index 000000000..aa4d813d6
--- /dev/null
+++ b/common/src/main/res/values-es/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sigue a Papá Noel
+
diff --git a/common/src/main/res/values-es/strings_doodles.xml b/common/src/main/res/values-es/strings_doodles.xml
new file mode 100644
index 000000000..65966501f
--- /dev/null
+++ b/common/src/main/res/values-es/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Persecución en la nieve
+ ¡Al agua, pingüinos!
+ Lanzamiento de regalos
+ Mejor: %1$s
+ Silenciar
+ Dejar de silenciar
+ Cerrar
+ Pausar
+ MEJOR PUNTUACIÓN: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-es/strings_gamenames.xml b/common/src/main/res/values-es/strings_gamenames.xml
index 02d7c389b..a2fdb5066 100644
--- a/common/src/main/res/values-es/strings_gamenames.xml
+++ b/common/src/main/res/values-es/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Guía la bola
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Juego de las ciudades
+ Atrapa el regalo
+ Fotos navideñas
+ Lanzamiento de regalos
+ Elfo propulsado
+ Aeropuerto del Polo Norte
+ Tirachinas de regalos
+ Diseños navideños
+ Baile de código
+ Laboratorio de programación
+ Guía las piruletas
+ Jam session élfica
+ Pingüino atraparregalos
+ ¡Que no se caiga el regalo!
+ Entrega los regalos
+ Carrera de obstáculos de Rudolph
+ Reno a la carrera
+ ¿Dónde está Papá Noel?
+ El selfie de Papá Noel
+ Tiempo de regalos
+ Esquí élfico
+ Pelea de bolas de nieve
+ Crea un copo de nieve con código
+ Retratos contrarreloj
+ Festival del envoltorio
+ Crea un elfo
+ A trabajar
+ Bromas en la oficina
+ Coche compartido
diff --git a/common/src/main/res/values-es/strings_invite.xml b/common/src/main/res/values-es/strings_invite.xml
index b7565d9ec..6064ae188 100644
--- a/common/src/main/res/values-es/strings_invite.xml
+++ b/common/src/main/res/values-es/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Invita a tus amigos a seguir a Papá Noel con Google
- ¡Prueba Sigue a Papá Noel y acompáñalo virtualmente por todo el mundo!
- He conseguido %1$d puntos jugando a %2$s con los elfos en Seguir a Papá Noel de Google. ¡A ver si me ganas!
+ Invita a tus amigos a seguir a Papá Noel con Google
+ ¡Prueba Sigue a Papá Noel y acompáñalo virtualmente por todo el mundo!
+ He conseguido %1$d puntos jugando a %2$s con los elfos en Seguir a Papá Noel de Google. ¡A ver si me ganas!
diff --git a/common/src/main/res/values-es/strings_jetpack.xml b/common/src/main/res/values-es/strings_jetpack.xml
index 5328045ee..ace3096a9 100644
--- a/common/src/main/res/values-es/strings_jetpack.xml
+++ b/common/src/main/res/values-es/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Inicia sesión para desbloquear logros y publicar tu puntuación.
- Volver a jugar
- Puntuación
+ Inicia sesión para desbloquear logros y publicar tu puntuación.
+ Volver a jugar
+ Volver al mapa
+ PUNTUACIÓN
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..f10f9ab6c
--- /dev/null
+++ b/common/src/main/res/values-et/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Tagasi kaardirežiimi
+ Tagasi külla
+ See Santa Trackeri versioon on aegunud. Uusima versiooni leiate Google Play poest.
+ Mäng läbi
+ Laadimiskuva
+ Jätka
+ Mängi uuesti
+ Avakuva
+ Jaga
+ Mängu %1$s allalaadimisel ilmnes viga. Kas võrguühendus on olemas?
+
diff --git a/common/src/main/res/values-et/strings_appname.xml b/common/src/main/res/values-et/strings_appname.xml
new file mode 100644
index 000000000..2739312fb
--- /dev/null
+++ b/common/src/main/res/values-et/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Jõuluvana teekonna jälgimine
+
diff --git a/common/src/main/res/values-et/strings_doodles.xml b/common/src/main/res/values-et/strings_doodles.xml
new file mode 100644
index 000000000..292309431
--- /dev/null
+++ b/common/src/main/res/values-et/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Lumepallijooks
+ Pingviiniujumine
+ Kingiheide
+ Parim: %1$s
+ Vaigista
+ Tühista vaigistus
+ Sulge
+ Peata
+ PARIM TULEMUS: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-et/strings_gamenames.xml b/common/src/main/res/values-et/strings_gamenames.xml
index 89f4e4405..c8bd2048f 100644
--- a/common/src/main/res/values-et/strings_gamenames.xml
+++ b/common/src/main/res/values-et/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Nätsupall
- Mälu
- Haldja rakettranits
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball\'i mäng
- Snowdown
+ Nätsupall
+ Mälu
+ Haldja rakettranits
+ Rakett-kelk
+ Tantsiv põhjapõder
+ Linnaviktoriin
+ Kingiseiklus
+ Jõuluvanatuur
+ Kingiheide
+ Päkapiku rakettranits
+ Põhjapooluse lennujaam
+ Kingikatapult
+ Jõuluvana jutupliiats
+ Tants ja trall
+ Koodilabor
+ Nätsukommid
+ Päkapikubänd
+ Pingviinijooks
+ Põrkavad kingid
+ Kingitustesadu
+ Rudolfi võidusõit
+ Põhjapõdrajooks
+ Leia jõuluvana
+ Jõuluvana selfie
+ Pühadelahkus
+ Päkapikuslaalom
+ Lumesõda
+ Lumehelbe kodeerimine
+ Arva ära
+ Kiirpakkija
+ Päkapikudisainija
+ Tagasi tööle
+ Vingerpuss kontoris
+ Sõidame koos
diff --git a/common/src/main/res/values-et/strings_invite.xml b/common/src/main/res/values-et/strings_invite.xml
index 215ed9f4a..750faaaa5 100644
--- a/common/src/main/res/values-et/strings_invite.xml
+++ b/common/src/main/res/values-et/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Kutsuge sõbrad Google\'iga jõuluvana jälgima
- Proovige rakendust Santa Tracker ja vaadake, kuidas jõuluvana ümber maailma lendab!
- Sain Google\'i jõuluvana jälgimise rakenduses päkapikkudega mängu %2$s mängides %1$d punkti. Arvad, et oled osavam?
+ Kutsuge sõbrad Google\'iga jõuluvana jälgima
+ Proovige rakendust Santa Tracker ja vaadake, kuidas jõuluvana ümber maailma lendab!
+ Sain Google\'i jõuluvana jälgimise rakenduses päkapikkudega mängu %2$s mängides %1$d punkti. Arvad, et oled osavam?
diff --git a/common/src/main/res/values-et/strings_jetpack.xml b/common/src/main/res/values-et/strings_jetpack.xml
index ba21b662f..048479d00 100644
--- a/common/src/main/res/values-et/strings_jetpack.xml
+++ b/common/src/main/res/values-et/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Registreeruge, et saavutusi püüda ja oma skoore postitada!
- Mängi uuesti
- Skoor
+ Registreeruge, et saavutusi püüda ja oma skoore postitada!
+ Mängi uuesti
+ Tagasi kaardi juurde
+ TULEMUS
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..491d1fef1
--- /dev/null
+++ b/common/src/main/res/values-fi/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Takaisin karttaan
+ Takaisin kylään
+ Tämä Joulupukin jäljittimen versio on vanhentunut. Päivitä uusimpaan versioon Play Kaupassa.
+ Peli loppui
+ Ladataan kuvaa
+ Jatka
+ Pelaa uudelleen
+ Etusivu
+ Jaa
+ Virhe ladattaessa peliä %1$s. Toimiiko nettiyhteys?
+
diff --git a/common/src/main/res/values-fi/strings_appname.xml b/common/src/main/res/values-fi/strings_appname.xml
new file mode 100644
index 000000000..0187ef453
--- /dev/null
+++ b/common/src/main/res/values-fi/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Joulupukin jäljitin
+
diff --git a/common/src/main/res/values-fi/strings_doodles.xml b/common/src/main/res/values-fi/strings_doodles.xml
new file mode 100644
index 000000000..1439c891f
--- /dev/null
+++ b/common/src/main/res/values-fi/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Lumipallojuoksu
+ Pingviiniuinti
+ Lahjanheitto
+ Paras: %1$s
+ Mykistä
+ Poista mykistys
+ Sulje
+ Keskeytä
+ PARAS TULOS: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-fi/strings_gamenames.xml b/common/src/main/res/values-fi/strings_gamenames.xml
index 38358085d..dd278f5d5 100644
--- a/common/src/main/res/values-fi/strings_gamenames.xml
+++ b/common/src/main/res/values-fi/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Muistipeli
- Tontturakettireppu
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball-peli
- Snowdown
+ Gumball
+ Muistipeli
+ Tontturakettireppu
+ Rocket Sleigh
+ Dasher Dancer
+ Kaupunkivisa
+ Lahjaseikkailu
+ Pukin pikakuvat
+ Lahjanheitto
+ Tonttu-jetpack
+ Korvatunturin lentokenttä
+ Lahjalinko
+ Pukin piirustuspaja
+ Kooditanssi
+ Koodauslabra
+ Purkkapallo
+ Tonttujen bilebändi
+ Pingviinikilpa
+ Pomppivat paketit
+ Lahjapudotus
+ Petterin kilpa-ajo
+ Porojuoksu
+ Pukkihaku
+ Pukin selfie
+ Antamisen aika
+ Tonttuslalom
+ Lumisota
+ Koodaa lumihiutale
+ Pikapiirros
+ Paketointikilpa
+ Tontuntekijä
+ Työt kutsuvat
+ Toimistojekku
+ Kimppakyyti
diff --git a/common/src/main/res/values-fi/strings_invite.xml b/common/src/main/res/values-fi/strings_invite.xml
index d3a2abe95..7e09d869a 100644
--- a/common/src/main/res/values-fi/strings_invite.xml
+++ b/common/src/main/res/values-fi/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Kutsu ystäväsi seuraamaan pukin matkaa Googlen kanssa
- Kokeile Santa Trackeria ja seuraa pukin matkaa maailman ympäri.
- Sain pelissä %2$s tuloksen %1$d, kun pelasin tonttujen kanssa Googlen Joulupukin jäljitintä. Pystytkö parempaan?
+ Kutsu ystäväsi seuraamaan pukin matkaa Googlen kanssa
+ Kokeile Santa Trackeria ja seuraa pukin matkaa maailman ympäri.
+ Sain pelissä %2$s tuloksen %1$d, kun pelasin tonttujen kanssa Googlen Joulupukin jäljitintä. Pystytkö parempaan?
diff --git a/common/src/main/res/values-fi/strings_jetpack.xml b/common/src/main/res/values-fi/strings_jetpack.xml
index a77b95cd5..a12be6acc 100644
--- a/common/src/main/res/values-fi/strings_jetpack.xml
+++ b/common/src/main/res/values-fi/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Kirjaudu sisään, niin voit avata saavutuksia ja julkaista tuloksesi.
- Pelaa uudelleen
- Pisteet
+ Kirjaudu sisään, niin voit avata saavutuksia ja julkaista tuloksesi.
+ Pelaa uudelleen
+ Takaisin karttaan
+ PISTEET
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..852634cc8
--- /dev/null
+++ b/common/src/main/res/values-fil/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Bumalik sa mapa
+ Bumalik sa village
+ Luma na ang bersyong ito ng Santa Tracker. Pakibisita ang Play Store upang makapag-update sa pinakabagong bersyon.
+ Tapos na ang Laro
+ Nilo-load ang screen
+ Magpatuloy
+ I-replay
+ Home
+ bahagi
+ Nagka-error habang dina-download ang %1$s. Gumagana ba ang koneksyon ng iyong network?
+
diff --git a/common/src/main/res/values-fil/strings_appname.xml b/common/src/main/res/values-fil/strings_appname.xml
new file mode 100644
index 000000000..77d556f56
--- /dev/null
+++ b/common/src/main/res/values-fil/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Santa Tracker
+
diff --git a/common/src/main/res/values-fil/strings_doodles.xml b/common/src/main/res/values-fil/strings_doodles.xml
new file mode 100644
index 000000000..ceb2b9f97
--- /dev/null
+++ b/common/src/main/res/values-fil/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snowball Run
+ Penguin Swim
+ Present Throw
+ Pinakamataas: %1$s
+ I-mute
+ I-unmute
+ Isara
+ I-pause
+ PINAKAMATAAS NA SCORE: <b>%1$s</b>
+ %1$.1fs
+ %1$dm
+
diff --git a/common/src/main/res/values-fil/strings_gamenames.xml b/common/src/main/res/values-fil/strings_gamenames.xml
index 53e834857..bee518e97 100644
--- a/common/src/main/res/values-fil/strings_gamenames.xml
+++ b/common/src/main/res/values-fil/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Larong Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ City Quiz
+ Present Quest
+ Santa Snap
+ Present Toss
+ Elf Jetpack
+ North Pole Airport
+ Gift Slingshot
+ Claus Draws
+ Code Boogie
+ Code Lab
+ Gumball Tilt
+ Elf Jamband
+ Penguin Dash
+ Present Bounce
+ Present Drop
+ Rudolph Racer
+ Reindeer Runner
+ Santa Search
+ Santa Selfie
+ Panahon ng Bigayan
+ Elf Ski
+ Snowball Storm
+ Code a Snowflake
+ Speed Sketch
+ Wrap Battle
+ Elf Maker
+ Back to Work
+ Office Prank
+ Carpool
diff --git a/common/src/main/res/values-fil/strings_invite.xml b/common/src/main/res/values-fil/strings_invite.xml
index ad736646d..f8920ce63 100644
--- a/common/src/main/res/values-fil/strings_invite.xml
+++ b/common/src/main/res/values-fil/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Imbitahan ang iyong mga kaibigan na subaybayan si Santa sa Google
- Subukan ang Santa Tracker at panoorin ang paglipad ni Santa sa buong mundo!
- Nakapuntos ako ng %1$d sa paglalaro ng %2$s game na may elves sa Santa Tracker ng Google, kaya mo bang talunin iyon?
+ Imbitahan ang iyong mga kaibigan na subaybayan si Santa sa Google
+ Subukan ang Santa Tracker at panoorin ang paglipad ni Santa sa buong mundo!
+ Nakapuntos ako ng %1$d sa paglalaro ng %2$s game na may elves sa Santa Tracker ng Google, kaya mo bang talunin iyon?
diff --git a/common/src/main/res/values-fil/strings_jetpack.xml b/common/src/main/res/values-fil/strings_jetpack.xml
index 0723cba66..e5690d3c0 100644
--- a/common/src/main/res/values-fil/strings_jetpack.xml
+++ b/common/src/main/res/values-fil/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Mag-sign in upang mai-unlock ang mga achievement at mai-post ang iyong score!
- Maglaro Muli
- Score
+ Mag-sign in upang mai-unlock ang mga achievement at mai-post ang iyong score!
+ Maglaro Muli
+ Bumalik sa Mapa
+ SCORE
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..e59893efc
--- /dev/null
+++ b/common/src/main/res/values-fr-rCA/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Partie terminée!
+ Écran de chargement
+ Reprendre
+ Jouer de nouveau
+ Accueil
+ Partager
+ Une erreur s\'est produite durant le téléchargement de %1$s. Ta connexion réseau fonctionne-t-elle?
+
diff --git a/common/src/main/res/values-fr-rCA/strings_appname.xml b/common/src/main/res/values-fr-rCA/strings_appname.xml
new file mode 100644
index 000000000..3fa5d1302
--- /dev/null
+++ b/common/src/main/res/values-fr-rCA/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sur les traces du père Noël
+
diff --git a/common/src/main/res/values-fr-rCA/strings_doodles.xml b/common/src/main/res/values-fr-rCA/strings_doodles.xml
new file mode 100644
index 000000000..04442e21f
--- /dev/null
+++ b/common/src/main/res/values-fr-rCA/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Évitement de la boule de neige
+ Nage du pingouin
+ Lancer de cadeaux
+ Meilleur score : %1$s
+ Couper le son
+ Réactiver le son
+ Fermer
+ Interrompre
+ MEILLEUR SCORE : <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..8bc4e6f39 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Jeu Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Quiz urbain
+ Quête de cadeaux
+ Des photos avec le père Noël
+ Lancer de cadeaux
+ Le lutin réacté
+ Aéroport du pôle Nord
+ Lance-cadeaux
+ Dessin de Noël
+ Boogie du code
+ Labo de code
+ Boule de gomme en mouvement
+ Le jam des lutins
+ La ruée du pingouin
+ Rebond de cadeaux
+ Lâcher de cadeaux
+ La course avec Rudolphe
+ La course du renne
+ À la recherche du père Noël
+ Autoportrait du père Noël
+ La saison pour offrir
+ Le ski des lutins
+ Tempête de boules de neige
+ Coder un flocon de neige
+ Croquis rapide
+ La bataille de l\'emballage
+ Créateur de lutin
+ De retour au travail
+ Plaisanterie au bureau
+ Covoiturage
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..ec50d6f53 100644
--- a/common/src/main/res/values-fr-rCA/strings_invite.xml
+++ b/common/src/main/res/values-fr-rCA/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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!
- J\'ai obtenu un score de %1$d en jouant à %2$s avec les lutins dans Sur les traces du père Noël de Google, peux-tu faire mieux?
+ 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!
+ J\'ai obtenu un score de %1$d en jouant à %2$s avec les lutins dans Sur les traces du père Noël de Google, peux-tu faire mieux?
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..496925cb2 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,23 @@
+
+
- Connectez-vous pour débloquer vos réussites et afficher votre score!
- Jouer de nouveau
- Score
+ Connectez-vous pour débloquer vos réussites et afficher votre score!
+ Jouer de nouveau
+ Revenir à la carte
+ POINTAGE
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..164b3ff7a
--- /dev/null
+++ b/common/src/main/res/values-fr-rCH/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Jeu terminé
+ Écran de chargement
+ Reprendre
+ Réessayer
+ Accueil
+ Partager
+ Une erreur s\'est produite lors du téléchargement %1$s. Votre connexion réseau fonctionne-t-elle correctement ?
+
diff --git a/common/src/main/res/values-fr-rCH/strings_appname.xml b/common/src/main/res/values-fr-rCH/strings_appname.xml
new file mode 100644
index 000000000..b9a8fb866
--- /dev/null
+++ b/common/src/main/res/values-fr-rCH/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sur la piste du père Noël
+
diff --git a/common/src/main/res/values-fr-rCH/strings_doodles.xml b/common/src/main/res/values-fr-rCH/strings_doodles.xml
new file mode 100644
index 000000000..a46c86107
--- /dev/null
+++ b/common/src/main/res/values-fr-rCH/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ La course-poursuite enneigée
+ La nage du pingouin
+ Lancer de cadeaux
+ Meilleur score : %1$s
+ Couper le son
+ Réactiver le son
+ Fermer
+ Mettre en pause
+ MEILLEUR SCORE : <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..7b01a0ae8 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Jeu Snowball
- Snowdown
+ Le flipper bonbons
+ Memory
+ Elf Jetpack
+ Le traîneau-fusée
+ La disco de Noël
+ Le quiz des villes
+ La quête des cadeaux
+ Selfie d\'elfe
+ Lancer de cadeaux
+ Fusée du lutin
+ L\'aéroport du pôle Nord
+ Le lance-cadeaux
+ Dessine avec le père Noël
+ La danse du code
+ L\'atelier de programmation
+ Boules de chewing-gum en balade
+ Le groupe des lutins
+ La promenade du pingouin
+ Le cadeau rebondissant
+ Le lâcher de cadeaux
+ La course de Rudolphe
+ La course du renne
+ Où est le père Noël
+ Le selfie du père Noël
+ La saison des fêtes
+ La descente en skis de l\'elfe
+ Tempête de boules de neige
+ Code un flocon de neige
+ Esquisse rapide
+ Concours d\'emballage de cadeaux
+ Créateur de lutin
+ La reprise du travail
+ La farce au bureau
+ Le covoiturage
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..e11a4441a 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 !
- 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 ?
+ Invitez vos amis à suivre le père Noël avec Google
+ 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..72a8f454d 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,23 @@
+
+
- Connectez-vous pour débloquer vos exploits et publier vos scores !
- Rejouer
- Résultats
+ Connectez-vous pour débloquer vos exploits et publier vos scores !
+ Rejouer
+ Revenir à la carte
+ SCORE
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..164b3ff7a
--- /dev/null
+++ b/common/src/main/res/values-fr/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Jeu terminé
+ Écran de chargement
+ Reprendre
+ Réessayer
+ Accueil
+ Partager
+ Une erreur s\'est produite lors du téléchargement %1$s. Votre connexion réseau fonctionne-t-elle correctement ?
+
diff --git a/common/src/main/res/values-fr/strings_appname.xml b/common/src/main/res/values-fr/strings_appname.xml
new file mode 100644
index 000000000..b9a8fb866
--- /dev/null
+++ b/common/src/main/res/values-fr/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sur la piste du père Noël
+
diff --git a/common/src/main/res/values-fr/strings_doodles.xml b/common/src/main/res/values-fr/strings_doodles.xml
new file mode 100644
index 000000000..a46c86107
--- /dev/null
+++ b/common/src/main/res/values-fr/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ La course-poursuite enneigée
+ La nage du pingouin
+ Lancer de cadeaux
+ Meilleur score : %1$s
+ Couper le son
+ Réactiver le son
+ Fermer
+ Mettre en pause
+ MEILLEUR SCORE : <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-fr/strings_gamenames.xml b/common/src/main/res/values-fr/strings_gamenames.xml
index 97d7d7ef0..7b01a0ae8 100644
--- a/common/src/main/res/values-fr/strings_gamenames.xml
+++ b/common/src/main/res/values-fr/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Jeu Snowball
- Snowdown
+ Le flipper bonbons
+ Memory
+ Elf Jetpack
+ Le traîneau-fusée
+ La disco de Noël
+ Le quiz des villes
+ La quête des cadeaux
+ Selfie d\'elfe
+ Lancer de cadeaux
+ Fusée du lutin
+ L\'aéroport du pôle Nord
+ Le lance-cadeaux
+ Dessine avec le père Noël
+ La danse du code
+ L\'atelier de programmation
+ Boules de chewing-gum en balade
+ Le groupe des lutins
+ La promenade du pingouin
+ Le cadeau rebondissant
+ Le lâcher de cadeaux
+ La course de Rudolphe
+ La course du renne
+ Où est le père Noël
+ Le selfie du père Noël
+ La saison des fêtes
+ La descente en skis de l\'elfe
+ Tempête de boules de neige
+ Code un flocon de neige
+ Esquisse rapide
+ Concours d\'emballage de cadeaux
+ Créateur de lutin
+ La reprise du travail
+ La farce au bureau
+ Le covoiturage
diff --git a/common/src/main/res/values-fr/strings_invite.xml b/common/src/main/res/values-fr/strings_invite.xml
index 684b63131..e11a4441a 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 !
- 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 ?
+ Invitez vos amis à suivre le père Noël avec Google
+ 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..72a8f454d 100644
--- a/common/src/main/res/values-fr/strings_jetpack.xml
+++ b/common/src/main/res/values-fr/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Connectez-vous pour débloquer vos exploits et publier vos scores !
- Rejouer
- Résultats
+ Connectez-vous pour débloquer vos exploits et publier vos scores !
+ Rejouer
+ Revenir à la carte
+ SCORE
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..2bdc33741
--- /dev/null
+++ b/common/src/main/res/values-gsw/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game Over
+ Ladebildschirm
+ Fortsetzen
+ Wiederholen
+ Weiter
+ Teilen
+ Beim Download von %1$s ist ein Fehler aufgetreten. Funktioniert deine Netzwerkverbindung?
+
diff --git a/common/src/main/res/values-gsw/strings_appname.xml b/common/src/main/res/values-gsw/strings_appname.xml
new file mode 100644
index 000000000..f1644cdd9
--- /dev/null
+++ b/common/src/main/res/values-gsw/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Auf den Spuren des Weihnachtsmanns
+
diff --git a/common/src/main/res/values-gsw/strings_doodles.xml b/common/src/main/res/values-gsw/strings_doodles.xml
new file mode 100644
index 000000000..dd80597cd
--- /dev/null
+++ b/common/src/main/res/values-gsw/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Schneeballrennen
+ Pinguinschwimmen
+ Geschenkewerfen
+ Bestes Ergebnis: %1$s
+ Stummschalten
+ Stummschaltung aufheben
+ Schließen
+ Pausieren
+ BESTES ERGEBNIS: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-gsw/strings_gamenames.xml b/common/src/main/res/values-gsw/strings_gamenames.xml
index bc79191c0..ce82ae70f 100644
--- a/common/src/main/res/values-gsw/strings_gamenames.xml
+++ b/common/src/main/res/values-gsw/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball Game
- Snowdown
+ Lolli-Flipper
+ Memory
+ Elf Jetpack
+ Raketen Flug
+ Weihnachts-Disco
+ Städte-Quiz
+ Geschenke-Schnitzeljagd
+ Weihnachtsmann-Selfie
+ Geschenkewerfen
+ Wichtel-Jetpack
+ Flughafen Nordpol
+ Geschenkeschleuder
+ Zeichnen mit dem Weihnachtsmann
+ Code-Boogie
+ Code-Lab
+ Lolli-Flipper
+ Wichtel-Wunschkonzert
+ Pinguin gib Acht
+ Geschenkeautomat
+ Bescherung
+ Rudolfs Rennen
+ Rasendes Rentier
+ Such den Weihnachtsmann
+ Weihnachtsmann-Selfie
+ Zeit des Gebens
+ Wichtel auf der Piste
+ Schneeballsturm
+ Schneeflockencode
+ Frostmaler
+ Verpackungskünstler
+ Wichtelkiste
+ Wieder bei der Arbeit
+ Bürostreich
+ Fahrgemeinschaften
diff --git a/common/src/main/res/values-gsw/strings_invite.xml b/common/src/main/res/values-gsw/strings_invite.xml
index 931606d08..61d3a7fa8 100644
--- a/common/src/main/res/values-gsw/strings_invite.xml
+++ b/common/src/main/res/values-gsw/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 \"Auf den Spuren des Weihnachtsmanns\" von Google das Spiel %2$s mit den Wichteln gespielt und %1$d Punkte erreicht. Schaffst du das auch?
+ 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 \"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-gsw/strings_jetpack.xml b/common/src/main/res/values-gsw/strings_jetpack.xml
index 94ecb86e2..d710d6d00 100644
--- a/common/src/main/res/values-gsw/strings_jetpack.xml
+++ b/common/src/main/res/values-gsw/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten!
- Neues Spiel
- Punktzahl
+ Melde dich an, um deine Erfolge zu speichern und deine Punktzahl zu posten!
+ Neues Spiel
+ Zurück zur Karte
+ PUNKTE
diff --git a/common/src/main/res/values-hdpi/dimens.xml b/common/src/main/res/values-hdpi/dimens.xml
index 800ae1042..e023cbeaa 100644
--- a/common/src/main/res/values-hdpi/dimens.xml
+++ b/common/src/main/res/values-hdpi/dimens.xml
@@ -1,7 +1,42 @@
+
+
+ 16dp
+
+ 8dp
+ 320dp
+ 202.5dp
+ 128dp
+ 72dp
+ 8dp
+ 4dp
8dp
45dp
+
16dp
+ 16dp
+ 24dp
+ 8dp
+ 55dp
+
+ 60dp
+ 0dp
+ 25dp
+ 180dp
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..611917bc6
--- /dev/null
+++ b/common/src/main/res/values-hr/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Igra je gotova
+ Učitavanje zaslona
+ Nastavi
+ Ponovna igra
+ Početna
+ Dijeli
+ Došlo je do pogreške pri preuzimanju%1$s. Radi li tvoja mreža pravilno?
+
diff --git a/common/src/main/res/values-hr/strings_appname.xml b/common/src/main/res/values-hr/strings_appname.xml
new file mode 100644
index 000000000..5f12424b6
--- /dev/null
+++ b/common/src/main/res/values-hr/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Slijedi Djeda Božićnjaka
+
diff --git a/common/src/main/res/values-hr/strings_doodles.xml b/common/src/main/res/values-hr/strings_doodles.xml
new file mode 100644
index 000000000..f570dd958
--- /dev/null
+++ b/common/src/main/res/values-hr/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Grudanje vilenjaka
+ Plivačka utrka pingvina
+ Bacanje darova
+ Najbolji rezultat: %1$s
+ Isključi zvuk
+ Uključi zvuk
+ Zatvori
+ Pauziraj
+ NAJBOLJI REZULTAT: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-hr/strings_gamenames.xml b/common/src/main/res/values-hr/strings_gamenames.xml
index 02b472a3f..54147632b 100644
--- a/common/src/main/res/values-hr/strings_gamenames.xml
+++ b/common/src/main/res/values-hr/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Igra pamćenja
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Igra Snowball
- Snowdown
+ Gumball
+ Igra pamćenja
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Kviz o gradovima
+ Lov na darove
+ Djedov fotograf
+ Ubacivanje darova
+ Vilenjačka sprava za letenje
+ Zračna luka na Sjevernom polu
+ Praćka za darove
+ Djedovi crteži
+ Ples kodova
+ Laboratorij za pisanje koda
+ Igra s kuglicama
+ Vilenjački bend
+ Utrka pingvina
+ Skakutanje s darovima
+ Ispuštanje darova
+ Rudolf trkač
+ Utrka sobova
+ Potraga za Djedom Božićnjakom
+ Djedičin selfie
+ Vrijeme darivanja
+ Skijalište vilenjaka
+ Grudalište
+ Izrada pahuljice pomoću koda
+ Brzo skiciranje
+ Dvoboj u zamatanju darova
+ Tvorac vilenjaka
+ Ponovo na radnom mjestu
+ Uredska podvala
+ Dijeljenje vožnje
diff --git a/common/src/main/res/values-hr/strings_invite.xml b/common/src/main/res/values-hr/strings_invite.xml
index ad350bc43..5fe0d1e43 100644
--- a/common/src/main/res/values-hr/strings_invite.xml
+++ b/common/src/main/res/values-hr/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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!
- Moj rezultat u igri %2$s s vilenjacima u Slijedi Djeda Božićnjaka: %1$d. Misliš da možeš bolje?
+ 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!
+ Moj rezultat u igri %2$s s vilenjacima u Slijedi Djeda Božićnjaka: %1$d. Misliš da možeš bolje?
diff --git a/common/src/main/res/values-hr/strings_jetpack.xml b/common/src/main/res/values-hr/strings_jetpack.xml
index df14efe57..32e229958 100644
--- a/common/src/main/res/values-hr/strings_jetpack.xml
+++ b/common/src/main/res/values-hr/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Prijavite se da biste otključali uspjehe i objavili rezultat!
- Igraj ponovo
- Rezultat
+ Prijavite se da biste otključali uspjehe i objavili rezultat!
+ Igraj ponovo
+ Natrag na kartu
+ REZULTAT
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..4ea0fbeb4
--- /dev/null
+++ b/common/src/main/res/values-id/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Balik ke peta
+ Balik ke desa
+ Pelacak Sinterklas versi ini sudah usang. Kunjungi Play Store untuk update ke versi terbaru.
+ Game Selesai
+ Memuat layar
+ Lanjutkan
+ Main Lagi
+ Beranda
+ Bagikan
+ Terjadi error saat mendownload %1$s. Apakah koneksi jaringan Anda berfungsi?
+
diff --git a/common/src/main/res/values-id/strings_appname.xml b/common/src/main/res/values-id/strings_appname.xml
new file mode 100644
index 000000000..e519e71dd
--- /dev/null
+++ b/common/src/main/res/values-id/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Pelacak Sinterklas
+
diff --git a/common/src/main/res/values-id/strings_doodles.xml b/common/src/main/res/values-id/strings_doodles.xml
new file mode 100644
index 000000000..eaeb9d307
--- /dev/null
+++ b/common/src/main/res/values-id/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Lari dari Kejaran Bola Salju
+ Renang Penguin
+ Melempar Hadiah
+ Terbaik: %1$s
+ Matikan suara
+ Nyalakan suara
+ Tutup
+ Jeda
+ SKOR TERBAIK: <b>%1$s</b>
+ %1$.1f dtk
+ %1$d m
+
diff --git a/common/src/main/res/values-id/strings_gamenames.xml b/common/src/main/res/values-id/strings_gamenames.xml
index c99fae438..114e77301 100644
--- a/common/src/main/res/values-id/strings_gamenames.xml
+++ b/common/src/main/res/values-id/strings_gamenames.xml
@@ -1,11 +1,55 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Game Snowball
- Snowdown
+ Bola Permen
+
+ Cocokkan Gambar
+ Elf Jetpack
+ Seluncur Roket
+ Seluncur Roket
+
+ Kuis Tebak Kota
+ Cari Hadiah
+ Selfie Sinterklas
+ Lempar Hadiah
+ Jetpack Kurcaci
+ Bandara Kutub Utara
+ Ketapel Hadiah
+ Menggambar Tema Sinterklas
+ Tarian Kode
+ Lab Kode
+ Miringkan Gumball
+ Kolaborasi Band Kurcaci
+ Penguin Dash
+ Pantulan Hadiah
+ Jatuhkan Hadiah
+ Pembalap Rudolph
+ Pelari Rusa Kutub
+ Cari Sinterklas
+ Selfie Sinterklas
+ Musim Berbagi
+ Ski Kurcaci
+ Badai Bola Salju
+ Kode Keping Salju
+ Sketsa Cepat
+ Lomba Bungkus
+ Pembuat Kurcaci
+ Kembali Bekerja
+ Gurauan Kantor
+ Nebeng
diff --git a/common/src/main/res/values-id/strings_invite.xml b/common/src/main/res/values-id/strings_invite.xml
index 16abd10be..ce4263a71 100644
--- a/common/src/main/res/values-id/strings_invite.xml
+++ b/common/src/main/res/values-id/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Undang teman Anda untuk melacak Sinterklas dengan Google
- Coba Pelacak Sinterklas dan tonton Sinterklas terbang ke seluruh dunia!
- Saya memperoleh skor %1$d saat bermain game %2$s dengan para kurcaci di Google Pelacak Sinterklas. Anda bisa mengalahkannya?
+ Undang teman Anda untuk melacak Sinterklas dengan Google
+ Coba Pelacak Sinterklas dan tonton Sinterklas terbang ke seluruh dunia!
+ Saya memperoleh skor %1$d saat bermain game %2$s dengan para kurcaci di Google Pelacak Sinterklas. Anda bisa mengalahkannya?
diff --git a/common/src/main/res/values-id/strings_jetpack.xml b/common/src/main/res/values-id/strings_jetpack.xml
index ee61b829c..dd1d09887 100644
--- a/common/src/main/res/values-id/strings_jetpack.xml
+++ b/common/src/main/res/values-id/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Masuk untuk membuka pencapaian dan mengeposkan skor!
- Main Lagi
- Skor
+ Masuk untuk membuka pencapaian dan memposting skor!
+ Main Lagi
+ Balik ke Peta
+ SKOR
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..4ea0fbeb4
--- /dev/null
+++ b/common/src/main/res/values-in/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Balik ke peta
+ Balik ke desa
+ Pelacak Sinterklas versi ini sudah usang. Kunjungi Play Store untuk update ke versi terbaru.
+ Game Selesai
+ Memuat layar
+ Lanjutkan
+ Main Lagi
+ Beranda
+ Bagikan
+ Terjadi error saat mendownload %1$s. Apakah koneksi jaringan Anda berfungsi?
+
diff --git a/common/src/main/res/values-in/strings_appname.xml b/common/src/main/res/values-in/strings_appname.xml
new file mode 100644
index 000000000..e519e71dd
--- /dev/null
+++ b/common/src/main/res/values-in/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Pelacak Sinterklas
+
diff --git a/common/src/main/res/values-in/strings_doodles.xml b/common/src/main/res/values-in/strings_doodles.xml
new file mode 100644
index 000000000..eaeb9d307
--- /dev/null
+++ b/common/src/main/res/values-in/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Lari dari Kejaran Bola Salju
+ Renang Penguin
+ Melempar Hadiah
+ Terbaik: %1$s
+ Matikan suara
+ Nyalakan suara
+ Tutup
+ Jeda
+ SKOR TERBAIK: <b>%1$s</b>
+ %1$.1f dtk
+ %1$d m
+
diff --git a/common/src/main/res/values-in/strings_gamenames.xml b/common/src/main/res/values-in/strings_gamenames.xml
index c99fae438..114e77301 100644
--- a/common/src/main/res/values-in/strings_gamenames.xml
+++ b/common/src/main/res/values-in/strings_gamenames.xml
@@ -1,11 +1,55 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Game Snowball
- Snowdown
+ Bola Permen
+
+ Cocokkan Gambar
+ Elf Jetpack
+ Seluncur Roket
+ Seluncur Roket
+
+ Kuis Tebak Kota
+ Cari Hadiah
+ Selfie Sinterklas
+ Lempar Hadiah
+ Jetpack Kurcaci
+ Bandara Kutub Utara
+ Ketapel Hadiah
+ Menggambar Tema Sinterklas
+ Tarian Kode
+ Lab Kode
+ Miringkan Gumball
+ Kolaborasi Band Kurcaci
+ Penguin Dash
+ Pantulan Hadiah
+ Jatuhkan Hadiah
+ Pembalap Rudolph
+ Pelari Rusa Kutub
+ Cari Sinterklas
+ Selfie Sinterklas
+ Musim Berbagi
+ Ski Kurcaci
+ Badai Bola Salju
+ Kode Keping Salju
+ Sketsa Cepat
+ Lomba Bungkus
+ Pembuat Kurcaci
+ Kembali Bekerja
+ Gurauan Kantor
+ Nebeng
diff --git a/common/src/main/res/values-in/strings_invite.xml b/common/src/main/res/values-in/strings_invite.xml
index 16abd10be..ce4263a71 100644
--- a/common/src/main/res/values-in/strings_invite.xml
+++ b/common/src/main/res/values-in/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Undang teman Anda untuk melacak Sinterklas dengan Google
- Coba Pelacak Sinterklas dan tonton Sinterklas terbang ke seluruh dunia!
- Saya memperoleh skor %1$d saat bermain game %2$s dengan para kurcaci di Google Pelacak Sinterklas. Anda bisa mengalahkannya?
+ Undang teman Anda untuk melacak Sinterklas dengan Google
+ Coba Pelacak Sinterklas dan tonton Sinterklas terbang ke seluruh dunia!
+ Saya memperoleh skor %1$d saat bermain game %2$s dengan para kurcaci di Google Pelacak Sinterklas. Anda bisa mengalahkannya?
diff --git a/common/src/main/res/values-in/strings_jetpack.xml b/common/src/main/res/values-in/strings_jetpack.xml
index ee61b829c..dd1d09887 100644
--- a/common/src/main/res/values-in/strings_jetpack.xml
+++ b/common/src/main/res/values-in/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Masuk untuk membuka pencapaian dan mengeposkan skor!
- Main Lagi
- Skor
+ Masuk untuk membuka pencapaian dan memposting skor!
+ Main Lagi
+ Balik ke Peta
+ SKOR
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..74730562d
--- /dev/null
+++ b/common/src/main/res/values-it/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Game over
+ Caricamento schermata
+ Riprendi
+ Gioca ancora
+ Home page
+ Condividi
+ Si è verificato un errore durante il download di %1$s. La tua connessione di rete funziona?
+
diff --git a/common/src/main/res/values-it/strings_appname.xml b/common/src/main/res/values-it/strings_appname.xml
new file mode 100644
index 000000000..c80783e1e
--- /dev/null
+++ b/common/src/main/res/values-it/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Segui Babbo Natale
+
diff --git a/common/src/main/res/values-it/strings_doodles.xml b/common/src/main/res/values-it/strings_doodles.xml
new file mode 100644
index 000000000..e539d0d03
--- /dev/null
+++ b/common/src/main/res/values-it/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Corri elfo, corri
+ Nuota pinguino
+ Lancio dei regali
+ Punteggio migliore: %1$s
+ Disattiva l\'audio
+ Riattiva l\'audio
+ Chiudi
+ Pausa
+ PUNTEGGIO MIGLIORE: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-it/strings_gamenames.xml b/common/src/main/res/values-it/strings_gamenames.xml
index 02d7c389b..e3924e557 100644
--- a/common/src/main/res/values-it/strings_gamenames.xml
+++ b/common/src/main/res/values-it/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Palline di zucchero
+ Memory
+ L\'elfo volante
+ Razzo di natale
+ Ballo di Natale
+ Indovina la città
+ Caccia ai regali
+ Santa Snap
+ Lancia il regalo
+ Il folletto volante
+ Aeroporto del Polo Nord
+ Fionda dei regali
+ Disegni di Babbo Natale
+ La danza del codice
+ Laboratorio del codice
+ Palline di zucchero
+ La band dei folletti
+ Lo scatto del pinguino
+ Palleggia con il regalo
+ Sgancia il regalo
+ La corsa di Rudolph
+ La corsa delle renne
+ La ricerca di Babbo Natale
+ Selfie con Babbo Natale
+ La stagione dei regali
+ Folletti che sciano
+ Battaglia di palle di neve
+ Disegna con il codice
+ Indovina il disegno
+ Incarta il regalo
+ Crea un folletto
+ Si torna al lavoro
+ Scherzo in ufficio
+ Car sharing
diff --git a/common/src/main/res/values-it/strings_invite.xml b/common/src/main/res/values-it/strings_invite.xml
index 84a1141bc..df4d2d90f 100644
--- a/common/src/main/res/values-it/strings_invite.xml
+++ b/common/src/main/res/values-it/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Invita i tuoi amici a seguire Babbo Natale con Google
- Prova l\'app Segui Babbo Natale e guardalo mentre vola intorno al mondo.
- Ho totalizzato %1$d punti a %2$s con i folletti di Segui Babbo Natale di Google. Puoi fare di meglio?
+ Invita i tuoi amici a seguire Babbo Natale con Google
+ Prova l\'app Segui Babbo Natale e guardalo mentre vola intorno al mondo.
+ Ho totalizzato %1$d punti a %2$s con i folletti di Segui Babbo Natale di Google. Puoi fare di meglio?
diff --git a/common/src/main/res/values-it/strings_jetpack.xml b/common/src/main/res/values-it/strings_jetpack.xml
index 9f2727738..8587124c9 100644
--- a/common/src/main/res/values-it/strings_jetpack.xml
+++ b/common/src/main/res/values-it/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Accedi per sbloccare i risultati e pubblicare il tuo punteggio.
- Gioca ancora
- Punteggio
+ Accedi per sbloccare i risultati e pubblicare il tuo punteggio.
+ Gioca ancora
+ Torna alla mappa
+ PUNTEGGIO
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..b4f5c4ada
--- /dev/null
+++ b/common/src/main/res/values-ja/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 地図に戻る
+ 村へ戻る
+ お使いの「サンタを追いかけよう」は、最新版ではありません。Google Play ストアで最新バージョンを入手してください。
+ ゲームオーバー
+ 画面を読み込み中
+ 再開
+ もう一度プレイ
+ ホーム
+ 共有
+ %1$sのダウンロード中にエラーが発生しました。ネットワークに正常に接続されていますか?
+
diff --git a/common/src/main/res/values-ja/strings_appname.xml b/common/src/main/res/values-ja/strings_appname.xml
new file mode 100644
index 000000000..ca1e2a05d
--- /dev/null
+++ b/common/src/main/res/values-ja/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ サンタを追いかけよう
+
diff --git a/common/src/main/res/values-ja/strings_doodles.xml b/common/src/main/res/values-ja/strings_doodles.xml
new file mode 100644
index 000000000..7af849797
--- /dev/null
+++ b/common/src/main/res/values-ja/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ 雪玉ダッシュ
+ ペンギン スイミング
+ プレゼント投げ
+ ベストスコア: %1$s
+ ミュート
+ ミュートを解除
+ 閉じる
+ 一時停止
+ ベストスコア: <b>%1$s</b>
+ %1$.1f 秒
+ %1$d m
+
diff --git a/common/src/main/res/values-ja/strings_gamenames.xml b/common/src/main/res/values-ja/strings_gamenames.xml
index 02d7c389b..a70036c1a 100644
--- a/common/src/main/res/values-ja/strings_gamenames.xml
+++ b/common/src/main/res/values-ja/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ ガムボール
+ 記憶ゲーム
+ ジェットパック
+ ロケットそり
+ ダッシャー ダンサー
+ 都市クイズ
+ プレゼント クエスト
+ サンタのスナップ写真
+ プレゼントトス
+ ジェットパック
+ 北極空港
+ ギフト スリングショット
+ サンタのお絵かき
+ コードブギ
+ コードラボ
+ ガムボール ティルト
+ Elf Jamband
+ ペンギン ダッシュ
+ プレゼント バウンス
+ プレゼント ドロップ
+ 赤鼻のトナカイのレース
+ トナカイ ランナー
+ サンタさんを探す
+ サンタの自撮り写真
+ プレゼントの季節
+ 妖精のスキー
+ 雪球の嵐
+ 雪の結晶を描こう
+ スピード スケッチ
+ 妖精のプレゼント ラッピング
+ 妖精メーカー
+ サンタさんが戻ってくる
+ オフィスでのいたずら
+ みんなで相乗り
diff --git a/common/src/main/res/values-ja/strings_invite.xml b/common/src/main/res/values-ja/strings_invite.xml
index 10f3862cc..70d1a06b4 100644
--- a/common/src/main/res/values-ja/strings_invite.xml
+++ b/common/src/main/res/values-ja/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Google の「サンタを追いかけよう」に友だちを招待
- 「サンタを追いかけよう」で世界中を飛び回るサンタさんを見よう!
- Google の「サンタを追いかけよう」で、妖精たちと %2$s ゲームをして %1$d 点達成!あなたもチャレンジしませんか?
+ Google の「サンタを追いかけよう」に友だちを招待
+ 「サンタを追いかけよう」で世界中を飛び回るサンタさんを見よう!
+ Google の「サンタを追いかけよう」で、妖精たちと %2$s ゲームをして %1$d 点達成!あなたもチャレンジしませんか?
diff --git a/common/src/main/res/values-ja/strings_jetpack.xml b/common/src/main/res/values-ja/strings_jetpack.xml
index 05f6fb0a7..7d9200069 100644
--- a/common/src/main/res/values-ja/strings_jetpack.xml
+++ b/common/src/main/res/values-ja/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- ログインしたら、結果を開放してスコアを投稿しよう!
- もう一度プレイ
- スコア
+ ログインしたら、結果を開放してスコアを投稿しよう!
+ もう一度プレイ
+ 地図に戻る
+ スコア
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..bca6ab357
--- /dev/null
+++ b/common/src/main/res/values-ko/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 지도로 돌아가기
+ 마을로 돌아가기
+ 산타 추적기의 버전이 오래되었습니다. Play 스토어를 방문하여 최신 버전으로 업데이트하세요.
+ 게임 종료
+ 화면 로드 중
+ 계속
+ 다시 시작
+ 홈
+ 공유
+ %1$s 다운로드 중에 오류가 발생했습니다. 네트워크에 연결되어 있나요?
+
diff --git a/common/src/main/res/values-ko/strings_appname.xml b/common/src/main/res/values-ko/strings_appname.xml
new file mode 100644
index 000000000..5db30a627
--- /dev/null
+++ b/common/src/main/res/values-ko/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ 산타 추적기
+
diff --git a/common/src/main/res/values-ko/strings_doodles.xml b/common/src/main/res/values-ko/strings_doodles.xml
new file mode 100644
index 000000000..032e96ac1
--- /dev/null
+++ b/common/src/main/res/values-ko/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ 눈덩이 피해 달리기
+ 펭귄 수영
+ 선물 던지기
+ 최고 득점: %1$s
+ 음소거
+ 음소거 해제
+ 닫기
+ 일시중지
+ 최고 득점: <b>%1$s</b>
+ %1$.1f초
+ %1$d미터
+
diff --git a/common/src/main/res/values-ko/strings_gamenames.xml b/common/src/main/res/values-ko/strings_gamenames.xml
index 2865e0004..021b37d83 100644
--- a/common/src/main/res/values-ko/strings_gamenames.xml
+++ b/common/src/main/res/values-ko/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- 풍선껌
- 기억력
- 제트 추진 엘프
- 스노우글로브
- 로켓 썰매
- 대셔 댄서
- 눈싸움 게임
- 최후의 눈싸움 결전
+ 풍선껌
+ 기억력
+ 제트 추진 엘프
+ 로켓 썰매
+ 대셔 댄서
+ 도시 퀴즈
+ 선물 찾기
+ 산타 셀카
+ 선물 던지기
+ 제트 추진 엘프
+ 북극 공항
+ 새총으로 선물 날리기
+ 산타 그리기
+ 코드와 함께 춤을
+ 코드 실험실
+ 풍선껌 기울이기
+ 엘프 즉석밴드
+ 펭귄 질주
+ 선물 튕기기
+ 선물 떨구기
+ 루돌프 경주
+ 사슴 달리기
+ 산타 찾기
+ 산타 셀카
+ 나눔의 계절
+ 엘프 스키
+ 맹공의 눈싸움
+ 눈송이 코드
+ 빨리 그리기
+ 선물 포장 시합
+ 엘프 만들기
+ 산타가 돌아옵니다
+ 사무실 장난
+ 카풀
diff --git a/common/src/main/res/values-ko/strings_invite.xml b/common/src/main/res/values-ko/strings_invite.xml
index a84a61ddb..e4eb9e532 100644
--- a/common/src/main/res/values-ko/strings_invite.xml
+++ b/common/src/main/res/values-ko/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 친구를 초대하여 Google에서 산타 추적하기
- 산타 추적기를 사용해 전 세계를 도는 산타의 여정을 지켜봐 주세요.
- Google 산타 추적기에서 엘프 친구들과 함께 %2$s에서 %1$d점을 득점했어요. 따라잡을 테면 따라잡아 보세요.
+ 친구를 초대하여 Google에서 산타 추적하기
+ 산타 추적기를 사용해 전 세계를 도는 산타의 여정을 지켜봐 주세요.
+ Google 산타 추적기에서 엘프 친구들과 함께 %2$s에서 %1$d점을 득점했어요. 따라잡을 테면 따라잡아 보세요.
diff --git a/common/src/main/res/values-ko/strings_jetpack.xml b/common/src/main/res/values-ko/strings_jetpack.xml
index 0919deb72..5d2fdf653 100644
--- a/common/src/main/res/values-ko/strings_jetpack.xml
+++ b/common/src/main/res/values-ko/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- 로그인하여 업적을 달성하고 점수를 게시해 보세요.
- 다시 하기
- 점수
+ 로그인하여 업적을 달성하고 점수를 게시해 보세요.
+ 다시 하기
+ 지도로 돌아가기
+ 점수
diff --git a/common/src/main/res/values-land/dimens.xml b/common/src/main/res/values-land/dimens.xml
new file mode 100644
index 000000000..64135fbd7
--- /dev/null
+++ b/common/src/main/res/values-land/dimens.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ 60dp
+ 40dp
+
\ No newline at end of file
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..164b3ff7a
--- /dev/null
+++ b/common/src/main/res/values-ln/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Jeu terminé
+ Écran de chargement
+ Reprendre
+ Réessayer
+ Accueil
+ Partager
+ Une erreur s\'est produite lors du téléchargement %1$s. Votre connexion réseau fonctionne-t-elle correctement ?
+
diff --git a/common/src/main/res/values-ln/strings_appname.xml b/common/src/main/res/values-ln/strings_appname.xml
new file mode 100644
index 000000000..b9a8fb866
--- /dev/null
+++ b/common/src/main/res/values-ln/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Sur la piste du père Noël
+
diff --git a/common/src/main/res/values-ln/strings_doodles.xml b/common/src/main/res/values-ln/strings_doodles.xml
new file mode 100644
index 000000000..a46c86107
--- /dev/null
+++ b/common/src/main/res/values-ln/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ La course-poursuite enneigée
+ La nage du pingouin
+ Lancer de cadeaux
+ Meilleur score : %1$s
+ Couper le son
+ Réactiver le son
+ Fermer
+ Mettre en pause
+ MEILLEUR SCORE : <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-ln/strings_gamenames.xml b/common/src/main/res/values-ln/strings_gamenames.xml
index 97d7d7ef0..7b01a0ae8 100644
--- a/common/src/main/res/values-ln/strings_gamenames.xml
+++ b/common/src/main/res/values-ln/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Jeu Snowball
- Snowdown
+ Le flipper bonbons
+ Memory
+ Elf Jetpack
+ Le traîneau-fusée
+ La disco de Noël
+ Le quiz des villes
+ La quête des cadeaux
+ Selfie d\'elfe
+ Lancer de cadeaux
+ Fusée du lutin
+ L\'aéroport du pôle Nord
+ Le lance-cadeaux
+ Dessine avec le père Noël
+ La danse du code
+ L\'atelier de programmation
+ Boules de chewing-gum en balade
+ Le groupe des lutins
+ La promenade du pingouin
+ Le cadeau rebondissant
+ Le lâcher de cadeaux
+ La course de Rudolphe
+ La course du renne
+ Où est le père Noël
+ Le selfie du père Noël
+ La saison des fêtes
+ La descente en skis de l\'elfe
+ Tempête de boules de neige
+ Code un flocon de neige
+ Esquisse rapide
+ Concours d\'emballage de cadeaux
+ Créateur de lutin
+ La reprise du travail
+ La farce au bureau
+ Le covoiturage
diff --git a/common/src/main/res/values-ln/strings_invite.xml b/common/src/main/res/values-ln/strings_invite.xml
index 684b63131..e11a4441a 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 !
- 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 ?
+ Invitez vos amis à suivre le père Noël avec Google
+ 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..72a8f454d 100644
--- a/common/src/main/res/values-ln/strings_jetpack.xml
+++ b/common/src/main/res/values-ln/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Connectez-vous pour débloquer vos exploits et publier vos scores !
- Rejouer
- Résultats
+ Connectez-vous pour débloquer vos exploits et publier vos scores !
+ Rejouer
+ Revenir à la carte
+ SCORE
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..5b64f29a2
--- /dev/null
+++ b/common/src/main/res/values-lt/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Grįžti į žemėlapį
+ Grįžti į kaimą
+ Ši Kalėdų Senelio kelionės versija pasenusi. Apsilankykite „Play“ parduotuvėje ir atnaujinkite į naujausią versiją.
+ Žaidimo pabaiga
+ Įkeliamas ekranas
+ Tęsti
+ Paleisti iš naujo
+ Pagrindinis puslapis
+ Bendrinti
+ Atsisiunčiant „%1$s“ įvyko klaida. Ar esate prisijungę prie tinklo?
+
diff --git a/common/src/main/res/values-lt/strings_appname.xml b/common/src/main/res/values-lt/strings_appname.xml
new file mode 100644
index 000000000..48b910d72
--- /dev/null
+++ b/common/src/main/res/values-lt/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Kalėdų Senelio kelionė
+
diff --git a/common/src/main/res/values-lt/strings_doodles.xml b/common/src/main/res/values-lt/strings_doodles.xml
new file mode 100644
index 000000000..f2297ce64
--- /dev/null
+++ b/common/src/main/res/values-lt/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Bėgimas nuo sniego kamuolio
+ Plaukiojantis pingvinas
+ Dovanų svaidymas
+ Geriausias rezultatas: %1$s
+ Nutildyti
+ Įjungti garsą
+ Uždaryti
+ Pristabdyti
+ GERIAUSIAS REZULTATAS: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-lt/strings_gamenames.xml b/common/src/main/res/values-lt/strings_gamenames.xml
index 1ac5dea40..f3af2a588 100644
--- a/common/src/main/res/values-lt/strings_gamenames.xml
+++ b/common/src/main/res/values-lt/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Žaidimas „Snowball“
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Miestų viktorina
+ Dovanų ieškynės
+ Kalėdų Senelio asmenukė
+ Dovanų mėtymas
+ Elfų skraidyklė
+ Šiaurės ašigalio oro uostas
+ Dovanų laidynė
+ Kalėdų Senelio piešiniai
+ Bugivugio kodai
+ Kodų laboratorija
+ Gumos kamuoliukų svyriai
+ Elfų muzikinė grupė
+ Pingvinas ant ledkalnių
+ Dovanų atmušinėjimas
+ Dovanų mėtymas
+ Rudolfas lenktynininkas
+ Bėgimas su šiaurės elniu
+ Kalėdų Senelio paieška
+ Kalėdų Senelio asmenukė
+ Dovanų laikas
+ Elfų slidinėjimas
+ Gniūžčių lietus
+ Sugeneruokite snaigės kodą
+ Greitas eskizas
+ Vyniotuvės
+ Elfo kūrimas
+ Grįžimas prie darbų
+ Biuro juokelis
+ Pavežimas
diff --git a/common/src/main/res/values-lt/strings_invite.xml b/common/src/main/res/values-lt/strings_invite.xml
index cb43cba44..7b4ca541f 100644
--- a/common/src/main/res/values-lt/strings_invite.xml
+++ b/common/src/main/res/values-lt/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Pakvieskite draugus stebėti Kalėdų Senelį „Google“
- Išbandykite „Santa Tracker“ ir pamatysite, kaip Kalėdų Senelis skrenda per pasaulį!
- Žaisdamas (-a) %2$s su elfais programoje „Google“ Kalėdų Senelio kelionė pelniau %1$d. Galite geriau?
+ Pakvieskite draugus stebėti Kalėdų Senelį „Google“
+ Išbandykite „Santa Tracker“ ir pamatysite, kaip Kalėdų Senelis skrenda per pasaulį!
+ Žaisdamas (-a) %2$s su elfais programoje „Google“ Kalėdų Senelio kelionė pelniau %1$d. Galite geriau?
diff --git a/common/src/main/res/values-lt/strings_jetpack.xml b/common/src/main/res/values-lt/strings_jetpack.xml
index ce384530a..a9302bd10 100644
--- a/common/src/main/res/values-lt/strings_jetpack.xml
+++ b/common/src/main/res/values-lt/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Prisijunkite, jei norite atrakinti laimėjimus ir paskelbti savo rezultatą!
- Žaisti dar kartą
- Rezultatas
+ Prisijunkite, jei norite atrakinti laimėjimus ir paskelbti savo rezultatą!
+ Žaisti dar kartą
+ Grįžti į žemėlapį
+ REZULTATAS
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..7e2ca8328
--- /dev/null
+++ b/common/src/main/res/values-lv/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Spēle beigusies
+ Notiek ekrāna ielāde
+ Atsākt
+ Spēlēt atkārtoti
+ Sākums
+ Kopīgot
+ Lejupielādējot %1$s, radās kļūda. Vai jūsu tīkla savienojums darbojas?
+
diff --git a/common/src/main/res/values-lv/strings_appname.xml b/common/src/main/res/values-lv/strings_appname.xml
new file mode 100644
index 000000000..f6ca6af0c
--- /dev/null
+++ b/common/src/main/res/values-lv/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Ziemassvētku vecīša ceļojums
+
diff --git a/common/src/main/res/values-lv/strings_doodles.xml b/common/src/main/res/values-lv/strings_doodles.xml
new file mode 100644
index 000000000..30910700b
--- /dev/null
+++ b/common/src/main/res/values-lv/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Bēgšana no sniega pikām
+ Pingvīna peldēšana
+ Dāvanu mešanas spēle (Present Throw)
+ Labākais rezultāts: %1$s
+ Izslēgt skaņu
+ Ieslēgt skaņu
+ Aizvērt
+ Apturēt
+ LABĀKAIS REZULTĀTS: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-lv/strings_gamenames.xml b/common/src/main/res/values-lv/strings_gamenames.xml
index 1242da71d..37f701077 100644
--- a/common/src/main/res/values-lv/strings_gamenames.xml
+++ b/common/src/main/res/values-lv/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- 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
+ Pilsētu viktorīnas spēle (City Quiz)
+ Dāvanu meklēšanas spēle (Present Quest)
+ Ziemassvētku vecīša pašbildes
+ Dāvanu mešana
+ Lidojošie rūķīši
+ Ziemeļpola lidosta
+ Dāvanu katapulta
+ Ziemassvētku vecīša zīmēšanas spēle
+ Kods: bugi
+ Kodu laboratorija
+ Spēle Gumball Tilt
+ Rūķīšu muzikālā apvienība
+ Pingvīna skrējiens
+ Dāvanu mētāšana
+ Dāvanu piegāde
+ Ziemeļbrieža Rūdolfa brauciens
+ Ziemeļbrieža skrējiens
+ Ziemassvētku vecīša meklēšana
+ Ziemassvētku vecīša pašbilde
+ Dāvanu laiks
+ Slēpojošie rūķīši
+ Sniega piku kauja
+ Sniegpārsliņas izveide ar kodu
+ Zīmēšana uz ātrumu
+ Dāvanu saiņošanas spēle
+ Rūķīšu veidotājs
+ Atpakaļ pie darba
+ Izjokošana birojā
+ Kopbraukšana
diff --git a/common/src/main/res/values-lv/strings_invite.xml b/common/src/main/res/values-lv/strings_invite.xml
index 8854d77bc..0b9ffc014 100644
--- a/common/src/main/res/values-lv/strings_invite.xml
+++ b/common/src/main/res/values-lv/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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!
- Es ieguvu %1$d punktus, spēlējot spēli %2$s ar elfiem Google Ziemassvētku vecīša ceļojumā. Vai varat to pārspēt?
+ 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!
+ Es ieguvu %1$d punktus, spēlējot spēli %2$s ar elfiem Google Ziemassvētku vecīša ceļojumā. Vai varat to pārspēt?
diff --git a/common/src/main/res/values-lv/strings_jetpack.xml b/common/src/main/res/values-lv/strings_jetpack.xml
index 3fed2efa9..2e71531b7 100644
--- a/common/src/main/res/values-lv/strings_jetpack.xml
+++ b/common/src/main/res/values-lv/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Pierakstieties, lai atbloķētu sasniegumus un izliktu savu rezultātu!
- Spēlēt vēlreiz
- Rezultāts
+ Pierakstieties, lai atbloķētu sasniegumus un izliktu savu rezultātu!
+ Spēlēt vēlreiz
+ Atgriezties kartē
+ REZULTĀTS
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..da02a970f
--- /dev/null
+++ b/common/src/main/res/values-ml/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ മാപ്പിലേക്ക് മടങ്ങുക
+ ഗ്രാമത്തിലേക്ക് മടങ്ങുക
+ ഈ സാന്ത ട്രാക്കർ പതിപ്പ് കാലഹരണപ്പെട്ടതാണ്. ഏറ്റവും പുതിയ പതിപ്പിലേക്ക് അപ്ഡേറ്റ് ചെയ്യാൻ \'പ്ലേ സ്റ്റോർ\' സന്ദർശിക്കുക.
+ ഗെയിം കഴിഞ്ഞു
+ സ്ക്രീൻ ലോഡ് ചെയ്യുന്നു
+ പുനരാരംഭിക്കുക
+ വീണ്ടും പ്ലേ ചെയ്യുക
+ ഹോം
+ പങ്കിടുക
+ %1$s ഡൗൺലോഡ് ചെയ്യുമ്പോൾ പിശകുണ്ടായി. നിങ്ങളുടെ നെറ്റ്വര്ക്ക് കണക്ഷന് പ്രവർത്തനക്ഷമമാണോ?
+
diff --git a/common/src/main/res/values-ml/strings_appname.xml b/common/src/main/res/values-ml/strings_appname.xml
new file mode 100644
index 000000000..dab0828f9
--- /dev/null
+++ b/common/src/main/res/values-ml/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ സാന്താ ട്രാക്കർ
+
diff --git a/common/src/main/res/values-ml/strings_doodles.xml b/common/src/main/res/values-ml/strings_doodles.xml
new file mode 100644
index 000000000..af11bd630
--- /dev/null
+++ b/common/src/main/res/values-ml/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ സ്നോബോൾ റൺ
+ പെൻഗ്വിൻ സ്വിം
+ പ്രസന്റ് ത്രോ
+ മികച്ചത്: %1$s
+ മ്യൂട്ടുചെയ്യുക
+ അൺമ്യൂട്ടുചെയ്യുക
+ അടയ്ക്കുക
+ താൽക്കാലികമായി നിർത്തുക
+ മികച്ച സ്കോർ: <b>%1$s</b>
+ %1$.1fസെക്കൻഡ്
+ %1$dമിനിറ്റ്
+
diff --git a/common/src/main/res/values-ml/strings_gamenames.xml b/common/src/main/res/values-ml/strings_gamenames.xml
index 74de7aee7..4ea8ac1ca 100644
--- a/common/src/main/res/values-ml/strings_gamenames.xml
+++ b/common/src/main/res/values-ml/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- ഗംബോൾ
- മെമ്മറി
- എൽഫ് ജെറ്റ്പാക്ക്
- സ്നോഗ്ലോബ്
- റോക്കറ്റ് ഹിമവണ്ടി
- ഡാഷർ ഡാൻസർ
- സ്നോബോൾ ഗെയിം
- സ്നോഡൗൺ
+ ഗംബോൾ
+ മെമ്മറി
+ എൽഫ് ജെറ്റ്പാക്ക്
+ റോക്കറ്റ് ഹിമവണ്ടി
+ ഡാഷർ ഡാൻസർ
+ സിറ്റി ക്വിസ്
+ പ്രസന്റ് ക്വസ്റ്റ്
+ സാന്താ സ്നാപ്പ്
+ പ്രസന്റ് ടോസ് ഗെയിം
+ ജെറ്റ്പായ്ക്ക് ധരിച്ച കുട്ടിച്ചാത്തൻ
+ ഉത്തരധ്രുവ എയർപോർട്ട്
+ ഗിഫ്റ്റ് സ്ലിംഗ്ഷോട്ട്
+ ക്ലോസ് ഡ്രോസ്
+ കോഡ് ബൂഗി
+ കോഡ് ലാബ്
+ ഗംബോൾ ടിൽറ്റ്
+ എൽഫ് ജാംബാൻഡ്
+ പെൻഗ്വിൻ ഡാഷ്
+ നിലവിലെ ബൗൺസ്
+ നിലവിലെ ഡ്രോപ്പ്
+ റുഡോൾഫ് റേസർ
+ റെയിൻഡിയർ റണ്ണർ
+ സാന്തയെ തിരയൽ
+ സാന്തയുടെ സെൽഫി
+ ദാനധർമ്മങ്ങളുടെ കാലം
+ എൽഫ് സ്കീ
+ സ്നോബോൾ സ്റ്റോം
+ കോഡ് എ സ്നോഫ്ലെയ്ക്ക്
+ സ്പീഡ് സ്കെച്ച്
+ റാപ് ബാറ്റിൽ
+ കുട്ടിച്ചാത്തൻ സ്രഷ്ടാവ്
+ ജോലിയിലേക്ക് മടങ്ങുകയാണ്
+ ഓഫീസ് പ്രാങ്ക്
+ കാർപൂൾ
diff --git a/common/src/main/res/values-ml/strings_invite.xml b/common/src/main/res/values-ml/strings_invite.xml
index c54c246e9..743250c9f 100644
--- a/common/src/main/res/values-ml/strings_invite.xml
+++ b/common/src/main/res/values-ml/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Google വഴി സാന്തയെ ട്രാക്കുചെയ്യുന്നതിന് സുഹൃത്തുക്കളെ ക്ഷണിക്കുക
- സാന്ത ട്രാക്കർ പരീക്ഷിച്ചുകൊണ്ട് ലോകമെമ്പാടുമുള്ള സാന്തയുടെ സഞ്ചാരം കാണുക!
- Google-ന്റെ സാന്ത ട്രാക്കറിൽ കുട്ടിച്ചാത്തന്മാരോടൊപ്പം %2$s ഗെയിം കളിച്ച് ഞാൻ %1$d സ്കോർ ചെയ്തു, നിങ്ങൾക്കത് മറികടക്കാനാകുമോ?
+ Google വഴി സാന്തയെ ട്രാക്കുചെയ്യുന്നതിന് സുഹൃത്തുക്കളെ ക്ഷണിക്കുക
+ സാന്ത ട്രാക്കർ പരീക്ഷിച്ചുകൊണ്ട് ലോകമെമ്പാടുമുള്ള സാന്തയുടെ സഞ്ചാരം കാണുക!
+ Google-ന്റെ സാന്ത ട്രാക്കറിൽ കുട്ടിച്ചാത്തന്മാരോടൊപ്പം %2$s ഗെയിം കളിച്ച് ഞാൻ %1$d സ്കോർ ചെയ്തു, നിങ്ങൾക്കത് മറികടക്കാനാകുമോ?
diff --git a/common/src/main/res/values-ml/strings_jetpack.xml b/common/src/main/res/values-ml/strings_jetpack.xml
index fb73aba23..e2b55ead9 100644
--- a/common/src/main/res/values-ml/strings_jetpack.xml
+++ b/common/src/main/res/values-ml/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- നേട്ടങ്ങൾ അൺലോക്കുചെയ്യാനും നിങ്ങളുടെ സ്കോർ പോസ്റ്റ് ചെയ്യാനും സൈൻ ഇൻ ചെയ്യുക!
- വീണ്ടും കളിക്കുക
- സ്കോർ
+ നേട്ടങ്ങൾ അൺലോക്കുചെയ്യാനും നിങ്ങളുടെ സ്കോർ പോസ്റ്റ് ചെയ്യാനും സൈൻ ഇൻ ചെയ്യുക!
+ വീണ്ടും കളിക്കുക
+ മാപ്പിലേക്ക് മടങ്ങുക
+ സ്കോർ
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..3d2bf4886
--- /dev/null
+++ b/common/src/main/res/values-mo/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Î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.
+ Joc încheiat
+ Ecran de încărcare
+ Reia
+ Redă
+ Pagina de pornire
+ Arată
+ A apărut o eroare la descărcarea jocului %1$s. Funcționează conexiunea la rețea?
+
diff --git a/common/src/main/res/values-mo/strings_appname.xml b/common/src/main/res/values-mo/strings_appname.xml
new file mode 100644
index 000000000..a18f70ed2
--- /dev/null
+++ b/common/src/main/res/values-mo/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Pe urmele lui Moș Crăciun
+
diff --git a/common/src/main/res/values-mo/strings_doodles.xml b/common/src/main/res/values-mo/strings_doodles.xml
new file mode 100644
index 000000000..dbc74fdc4
--- /dev/null
+++ b/common/src/main/res/values-mo/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Fugi de bulgăre
+ Înotul pinguinului
+ Azvârle cadouri
+ Cel mai bun: %1$s
+ Dezactivează
+ Activează
+ Închide
+ Întrerupe
+ CEL MAI BUN SCOR: <b>%1$s</b>
+ Secunde: %1$.1f
+ Metri: %1$d
+
diff --git a/common/src/main/res/values-mo/strings_gamenames.xml b/common/src/main/res/values-mo/strings_gamenames.xml
index 41cc42d93..a212b46a4 100644
--- a/common/src/main/res/values-mo/strings_gamenames.xml
+++ b/common/src/main/res/values-mo/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Jocul Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Sania-rachetă
+ Dansează cu Dasher
+ Găsește orașul
+ În căutarea cadourilor
+ Sesiune foto
+ Aruncarea cadourilor
+ Elf zburător
+ Aeroportul de la Polul Nord
+ Praștia pentru cadouri
+ Desenează cu Moș Crăciun
+ Dans codificat
+ Laborator de programare
+ Direct la țintă
+ Orchestra elfilor
+ Goana pinguinului
+ Cadouri săltărețe
+ Împărțirea cadourilor
+ Cursa lui Rudolph
+ Aleargă cu renii
+ Unde este Moș Crăciun?
+ Moș Crăciun la frizer
+ Anotimpul cadourilor
+ Elfi schiori
+ Furtună cu bulgări de zăpadă
+ Scrie codul unui fulg de zăpadă
+ Ghicitori desenate
+ Bătălia de împachetat cadouri
+ Creator de elfi
+ Înapoi la treabă
+ Farsă în birou
+ În drum spre petrecere
diff --git a/common/src/main/res/values-mo/strings_invite.xml b/common/src/main/res/values-mo/strings_invite.xml
index 2fa2ba7f3..44f35b913 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..72aef9e6b 100644
--- a/common/src/main/res/values-mo/strings_jetpack.xml
+++ b/common/src/main/res/values-mo/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- 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
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..f47576d31
--- /dev/null
+++ b/common/src/main/res/values-nb/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Tilbake til kartet
+ Tilbake til landsbyen
+ Denne versjonen av Følg julenissen er utdatert. Gå til Play-butikken for å oppdatere til den nyeste versjonen.
+ Spillet er over
+ Innlastingsskjermbilde
+ Gjenoppta
+ Spill på nytt
+ Startside
+ Del
+ Det oppsto en feil ved nedlasting av %1$s. Fungerer nettverkstilkoblingen som den skal?
+
diff --git a/common/src/main/res/values-nb/strings_appname.xml b/common/src/main/res/values-nb/strings_appname.xml
new file mode 100644
index 000000000..a4cfe16f2
--- /dev/null
+++ b/common/src/main/res/values-nb/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Følg julenissen
+
diff --git a/common/src/main/res/values-nb/strings_doodles.xml b/common/src/main/res/values-nb/strings_doodles.xml
new file mode 100644
index 000000000..b0abb177e
--- /dev/null
+++ b/common/src/main/res/values-nb/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snøballflukten
+ Pingvinsvømming
+ Gavekasting
+ Beste: %1$s
+ Slå av lyden
+ Slå på lyden
+ Lukk
+ Sett på pause
+ BESTE RESULTAT: <b>%1$s</b>
+ %1$.1f s
+ %1$d min
+
diff --git a/common/src/main/res/values-nb/strings_gamenames.xml b/common/src/main/res/values-nb/strings_gamenames.xml
index 02d7c389b..5692f044c 100644
--- a/common/src/main/res/values-nb/strings_gamenames.xml
+++ b/common/src/main/res/values-nb/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Rulledrops
+ Memory
+ Elf Jetpack
+ Rakettsleden
+ Nissedans
+ Byquiz
+ Gavejakten
+ Nisseknips
+ Gavekast
+ Alvejetpack
+ Nordpolen flyplass
+ Gavesprettert
+ Nissetegning
+ Kodeboogie
+ Kodingslab
+ Rulledrops
+ Alveband
+ Pingvinrennet
+ Gavesprett
+ Gaveslipp
+ Rudolf-løpet
+ Gavegalopp
+ Julenissesøk
+ Julenissens selfie
+ En tid for å gi
+ Alveskikjøring
+ Snøballstorm
+ Snøfnuggkoding
+ Hurtigtegning
+ Pakkekamp
+ Lag en alv
+ Tilbake til arbeidet
+ Alvestreker
+ Samkjøring
diff --git a/common/src/main/res/values-nb/strings_invite.xml b/common/src/main/res/values-nb/strings_invite.xml
index 06fb2db7a..1fab794e4 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
- 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?
+ 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..54b15ccdc 100644
--- a/common/src/main/res/values-nb/strings_jetpack.xml
+++ b/common/src/main/res/values-nb/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Logg på for å låse opp prestasjoner og legge ut poengsummen din.
- Spill igjen
- Poeng
+ Logg på for å låse opp prestasjoner og legge ut poengsummen din.
+ Spill igjen
+ Gå tilbake til kartet
+ POENG
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..f47576d31
--- /dev/null
+++ b/common/src/main/res/values-no/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Tilbake til kartet
+ Tilbake til landsbyen
+ Denne versjonen av Følg julenissen er utdatert. Gå til Play-butikken for å oppdatere til den nyeste versjonen.
+ Spillet er over
+ Innlastingsskjermbilde
+ Gjenoppta
+ Spill på nytt
+ Startside
+ Del
+ Det oppsto en feil ved nedlasting av %1$s. Fungerer nettverkstilkoblingen som den skal?
+
diff --git a/common/src/main/res/values-no/strings_appname.xml b/common/src/main/res/values-no/strings_appname.xml
new file mode 100644
index 000000000..a4cfe16f2
--- /dev/null
+++ b/common/src/main/res/values-no/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Følg julenissen
+
diff --git a/common/src/main/res/values-no/strings_doodles.xml b/common/src/main/res/values-no/strings_doodles.xml
new file mode 100644
index 000000000..b0abb177e
--- /dev/null
+++ b/common/src/main/res/values-no/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snøballflukten
+ Pingvinsvømming
+ Gavekasting
+ Beste: %1$s
+ Slå av lyden
+ Slå på lyden
+ Lukk
+ Sett på pause
+ BESTE RESULTAT: <b>%1$s</b>
+ %1$.1f s
+ %1$d min
+
diff --git a/common/src/main/res/values-no/strings_gamenames.xml b/common/src/main/res/values-no/strings_gamenames.xml
index 02d7c389b..5692f044c 100644
--- a/common/src/main/res/values-no/strings_gamenames.xml
+++ b/common/src/main/res/values-no/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ Rulledrops
+ Memory
+ Elf Jetpack
+ Rakettsleden
+ Nissedans
+ Byquiz
+ Gavejakten
+ Nisseknips
+ Gavekast
+ Alvejetpack
+ Nordpolen flyplass
+ Gavesprettert
+ Nissetegning
+ Kodeboogie
+ Kodingslab
+ Rulledrops
+ Alveband
+ Pingvinrennet
+ Gavesprett
+ Gaveslipp
+ Rudolf-løpet
+ Gavegalopp
+ Julenissesøk
+ Julenissens selfie
+ En tid for å gi
+ Alveskikjøring
+ Snøballstorm
+ Snøfnuggkoding
+ Hurtigtegning
+ Pakkekamp
+ Lag en alv
+ Tilbake til arbeidet
+ Alvestreker
+ Samkjøring
diff --git a/common/src/main/res/values-no/strings_invite.xml b/common/src/main/res/values-no/strings_invite.xml
index 06fb2db7a..1fab794e4 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
- 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?
+ 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..54b15ccdc 100644
--- a/common/src/main/res/values-no/strings_jetpack.xml
+++ b/common/src/main/res/values-no/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Logg på for å låse opp prestasjoner og legge ut poengsummen din.
- Spill igjen
- Poeng
+ Logg på for å låse opp prestasjoner og legge ut poengsummen din.
+ Spill igjen
+ Gå tilbake til kartet
+ POENG
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..5fc5b692e
--- /dev/null
+++ b/common/src/main/res/values-pl/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Wróć do mapy
+ Wróć do wioski
+ Ta wersja Trasy Świętego Mikołaja jest nieaktualna. Odwiedź Sklep Google Play, aby pobrać najnowszą wersję.
+ Koniec gry
+ Wczytuję ekran
+ Wznów
+ Zagraj jeszcze raz
+ Ekran główny
+ Udostępnij
+ Podczas pobierania gry %1$s wystąpił błąd. Czy masz połączenie z siecią?
+
diff --git a/common/src/main/res/values-pl/strings_appname.xml b/common/src/main/res/values-pl/strings_appname.xml
new file mode 100644
index 000000000..fd632ae59
--- /dev/null
+++ b/common/src/main/res/values-pl/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Trasa Świętego Mikołaja
+
diff --git a/common/src/main/res/values-pl/strings_doodles.xml b/common/src/main/res/values-pl/strings_doodles.xml
new file mode 100644
index 000000000..2ffdebf96
--- /dev/null
+++ b/common/src/main/res/values-pl/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Ucieczka przed śnieżką
+ Pływające pingwiny
+ Rzut prezentem
+ Najlepszy wynik: %1$s
+ Wycisz
+ Wyłącz wyciszenie
+ Zamknij
+ Wstrzymaj
+ NAJLEPSZY WYNIK: <b>%1$s</b>j
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-pl/strings_gamenames.xml b/common/src/main/res/values-pl/strings_gamenames.xml
index 5104d6966..76002b088 100644
--- a/common/src/main/res/values-pl/strings_gamenames.xml
+++ b/common/src/main/res/values-pl/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- 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
+ Miejski quiz
+ Wyprawa po prezenty
+ Mikołajowe fotki
+ Rzut prezentem
+ Odrzutowy plecak elfów
+ Lotnisko na Biegunie Północnym
+ Proca z prezentami
+ Rysowanie z Mikołajem
+ Kodowanie w rytmie boogie
+ Programowanie trasy
+ Spadające kulki
+ Muzyczny zespół elfów
+ Bieg pingwina
+ Podskakujące prezenty
+ Wrzucanie prezentów
+ Wyścigi z Rudolfem
+ Pędzący renifer
+ Poszukiwanie Mikołaja
+ Selfie Świętego Mikołaja
+ Czas prezentów
+ Elf na nartach
+ Atak śnieżkami
+ Zakoduj śnieżynkę
+ Rysowanie na czas
+ Pojedynek na pakowanie
+ Kreator elfów
+ Powrót do pracy
+ Żart biurowy
+ Wspólna jazda
diff --git a/common/src/main/res/values-pl/strings_invite.xml b/common/src/main/res/values-pl/strings_invite.xml
index 403829439..c2452f583 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
- 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ć?
+ 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..96f23f777 100644
--- a/common/src/main/res/values-pl/strings_jetpack.xml
+++ b/common/src/main/res/values-pl/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Zaloguj się, aby odblokować osiągnięcia i opublikować swój wynik.
- Zagraj jeszcze raz
- Wynik
+ Zaloguj się, aby odblokować osiągnięcia i opublikować swój wynik.
+ Zagraj jeszcze raz
+ Wróć do mapy
+ WYNIK
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..45042eec6
--- /dev/null
+++ b/common/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fim de jogo
+ Tela de carregamento
+ Retomar
+ Jogar novamente
+ Página inicial
+ Compartilhar
+ Ocorreu um erro durante o download de %1$s. Sua conexão de rede está funcionando?
+
diff --git a/common/src/main/res/values-pt-rBR/strings_appname.xml b/common/src/main/res/values-pt-rBR/strings_appname.xml
new file mode 100644
index 000000000..9cd66ed7c
--- /dev/null
+++ b/common/src/main/res/values-pt-rBR/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Siga o Papai Noel
+
diff --git a/common/src/main/res/values-pt-rBR/strings_doodles.xml b/common/src/main/res/values-pt-rBR/strings_doodles.xml
new file mode 100644
index 000000000..c92fb723d
--- /dev/null
+++ b/common/src/main/res/values-pt-rBR/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Corrida da bola de neve
+ Pinguim nadador
+ Presente ao alvo
+ Melhor pontuação: %1$s
+ Desativar som
+ Ativar som
+ Fechar
+ Pausar
+ MELHOR PONTUAÇÃO: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
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..65c6d932f 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,53 @@
+
+
- Gumball
- Memória
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Jogo Snowball
- Snowdown
+ Ladeira dos chicletes
+ Jogo da memória
+ Elf Jetpack
+ Trenó-foguete
+ Dança das renas
+ Jogo das cidades
+ Caça ao presente
+ Selfie do Papai Noel
+ Jogue o presente
+ Duende a jato
+ Aeroporto do Polo Norte
+ Estilingue de presentes
+ Desenhe com o Papai Noel
+ Dança dos códigos
+ Laboratório de códigos
+ Ladeira dos chicletes
+ Banda dos duendes
+ Corrida do pinguim
+ Pula-pula de presentes
+ Entrega de presentes
+ Corrida do Rudolph
+ Rena corredora
+ Onde está o Papai Noel?
+ Selfie do Papai Noel
+ Época de bondade
+ Esqui de duendes
+ Batalha de bolas de neve
+ Crie um floco de neve
+ Desenho rápido
+ Competição de embrulhos
+ Criador de duendes
+ De volta ao trabalho
+ Pegadinha no escritório
+ Carona
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..0e9137cf8 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!
- Fiz %1$d pontos no jogo %2$s com os duendes no Siga o Papai Noel do Google. Você consegue fazer mais?
+ Convide seus amigos para seguir o Papai Noel com o Google
+ 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..44d10f953 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,23 @@
+
+
- Faça login para desbloquear conquistas e postar sua pontuação.
- Jogar novamente
- Pontuação
+ Faça login para desbloquear conquistas e postar sua pontuação.
+ Jogar novamente
+ Retornar ao mapa
+ PONTUAÇÃO
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..4e4627304
--- /dev/null
+++ b/common/src/main/res/values-pt-rPT/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fim do jogo
+ Ecrã de carregamento
+ Retomar
+ Reiniciar jogo
+ Página inicial
+ Partilhar
+ Ocorreu um erro ao transferir o jogo %1$s. A sua ligação de rede está a funcionar?
+
diff --git a/common/src/main/res/values-pt-rPT/strings_appname.xml b/common/src/main/res/values-pt-rPT/strings_appname.xml
new file mode 100644
index 000000000..0538667f7
--- /dev/null
+++ b/common/src/main/res/values-pt-rPT/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ A viagem do Pai Natal
+
diff --git a/common/src/main/res/values-pt-rPT/strings_doodles.xml b/common/src/main/res/values-pt-rPT/strings_doodles.xml
new file mode 100644
index 000000000..5550789b5
--- /dev/null
+++ b/common/src/main/res/values-pt-rPT/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Fuga da bola de neve
+ Natação do pinguim
+ Atirar presentes
+ Melhor: %1$s
+ Desativar som
+ Reativar som
+ Fechar
+ Interromper
+ MELHOR PONTUAÇÃO: <b>%1$s</b>
+ %1$.1f seg.
+ %1$d min
+
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..afef1f37c 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,53 @@
+
+
- Gumball
- Memória
- Elf Jetpack
- Globo de Neve
- Trenó-foguete
- Dançarino Veloz
- Jogo Bola de Neve
- Snowdown
+ Pastilha elástica
+ Memória
+ Elf Jetpack
+ Trenó-foguete
+ Dançarino veloz
+ Questionário de cidades
+ Caça aos presentes
+ Foto com o Pai Natal
+ Lançamento de presentes
+ Elfos com propulsores a jato
+ Aeroporto do Polo Norte
+ Fisga de presentes
+ Desenhos festivos
+ Baile de código
+ Laboratório de Códigos
+ Flipper dos rebuçados
+ Banda dos gnomos
+ Corrida do pinguim
+ Salto dos presentes
+ Lançamento de presentes
+ Piloto Rodolfo
+ Corrida da rena
+ Procura do Pai Natal
+ Selfie do Pai Natal
+ Tempo de dar
+ Elfos esquiadores
+ Tempestade de bolas de neve
+ Codifique um floco de neve
+ Esboços rápidos
+ Toca a embrulhar
+ Criador de elfos
+ De volta ao trabalho
+ Praxe no escritório
+ Partilha de carro
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..4a0035e69 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?
+ Convidar os seus amigos para seguirem o Pai Natal com o Google
+ 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..4c5658e69 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,23 @@
+
+
- Inicie sessão para desbloquear conquistas e publicar a sua pontuação!
- Jogar de novo
- Pontuação
+ Inicie sessão para desbloquear conquistas e publicar a sua pontuação!
+ Jogar de novo
+ Voltar ao mapa
+ PONTUAÇÃO
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..45042eec6
--- /dev/null
+++ b/common/src/main/res/values-pt/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Fim de jogo
+ Tela de carregamento
+ Retomar
+ Jogar novamente
+ Página inicial
+ Compartilhar
+ Ocorreu um erro durante o download de %1$s. Sua conexão de rede está funcionando?
+
diff --git a/common/src/main/res/values-pt/strings_appname.xml b/common/src/main/res/values-pt/strings_appname.xml
new file mode 100644
index 000000000..9cd66ed7c
--- /dev/null
+++ b/common/src/main/res/values-pt/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Siga o Papai Noel
+
diff --git a/common/src/main/res/values-pt/strings_doodles.xml b/common/src/main/res/values-pt/strings_doodles.xml
new file mode 100644
index 000000000..c92fb723d
--- /dev/null
+++ b/common/src/main/res/values-pt/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Corrida da bola de neve
+ Pinguim nadador
+ Presente ao alvo
+ Melhor pontuação: %1$s
+ Desativar som
+ Ativar som
+ Fechar
+ Pausar
+ MELHOR PONTUAÇÃO: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-pt/strings_gamenames.xml b/common/src/main/res/values-pt/strings_gamenames.xml
index 9f9c58d34..65c6d932f 100644
--- a/common/src/main/res/values-pt/strings_gamenames.xml
+++ b/common/src/main/res/values-pt/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memória
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Jogo Snowball
- Snowdown
+ Ladeira dos chicletes
+ Jogo da memória
+ Elf Jetpack
+ Trenó-foguete
+ Dança das renas
+ Jogo das cidades
+ Caça ao presente
+ Selfie do Papai Noel
+ Jogue o presente
+ Duende a jato
+ Aeroporto do Polo Norte
+ Estilingue de presentes
+ Desenhe com o Papai Noel
+ Dança dos códigos
+ Laboratório de códigos
+ Ladeira dos chicletes
+ Banda dos duendes
+ Corrida do pinguim
+ Pula-pula de presentes
+ Entrega de presentes
+ Corrida do Rudolph
+ Rena corredora
+ Onde está o Papai Noel?
+ Selfie do Papai Noel
+ Época de bondade
+ Esqui de duendes
+ Batalha de bolas de neve
+ Crie um floco de neve
+ Desenho rápido
+ Competição de embrulhos
+ Criador de duendes
+ De volta ao trabalho
+ Pegadinha no escritório
+ Carona
diff --git a/common/src/main/res/values-pt/strings_invite.xml b/common/src/main/res/values-pt/strings_invite.xml
index c92fd0956..0e9137cf8 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!
- Fiz %1$d pontos no jogo %2$s com os duendes no Siga o Papai Noel do Google. Você consegue fazer mais?
+ Convide seus amigos para seguir o Papai Noel com o Google
+ 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..44d10f953 100644
--- a/common/src/main/res/values-pt/strings_jetpack.xml
+++ b/common/src/main/res/values-pt/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Faça login para desbloquear conquistas e postar sua pontuação.
- Jogar novamente
- Pontuação
+ Faça login para desbloquear conquistas e postar sua pontuação.
+ Jogar novamente
+ Retornar ao mapa
+ PONTUAÇÃO
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..3d2bf4886
--- /dev/null
+++ b/common/src/main/res/values-ro/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Î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.
+ Joc încheiat
+ Ecran de încărcare
+ Reia
+ Redă
+ Pagina de pornire
+ Arată
+ A apărut o eroare la descărcarea jocului %1$s. Funcționează conexiunea la rețea?
+
diff --git a/common/src/main/res/values-ro/strings_appname.xml b/common/src/main/res/values-ro/strings_appname.xml
new file mode 100644
index 000000000..a18f70ed2
--- /dev/null
+++ b/common/src/main/res/values-ro/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Pe urmele lui Moș Crăciun
+
diff --git a/common/src/main/res/values-ro/strings_doodles.xml b/common/src/main/res/values-ro/strings_doodles.xml
new file mode 100644
index 000000000..dbc74fdc4
--- /dev/null
+++ b/common/src/main/res/values-ro/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Fugi de bulgăre
+ Înotul pinguinului
+ Azvârle cadouri
+ Cel mai bun: %1$s
+ Dezactivează
+ Activează
+ Închide
+ Întrerupe
+ CEL MAI BUN SCOR: <b>%1$s</b>
+ Secunde: %1$.1f
+ Metri: %1$d
+
diff --git a/common/src/main/res/values-ro/strings_gamenames.xml b/common/src/main/res/values-ro/strings_gamenames.xml
index 41cc42d93..a212b46a4 100644
--- a/common/src/main/res/values-ro/strings_gamenames.xml
+++ b/common/src/main/res/values-ro/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Jocul Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Sania-rachetă
+ Dansează cu Dasher
+ Găsește orașul
+ În căutarea cadourilor
+ Sesiune foto
+ Aruncarea cadourilor
+ Elf zburător
+ Aeroportul de la Polul Nord
+ Praștia pentru cadouri
+ Desenează cu Moș Crăciun
+ Dans codificat
+ Laborator de programare
+ Direct la țintă
+ Orchestra elfilor
+ Goana pinguinului
+ Cadouri săltărețe
+ Împărțirea cadourilor
+ Cursa lui Rudolph
+ Aleargă cu renii
+ Unde este Moș Crăciun?
+ Moș Crăciun la frizer
+ Anotimpul cadourilor
+ Elfi schiori
+ Furtună cu bulgări de zăpadă
+ Scrie codul unui fulg de zăpadă
+ Ghicitori desenate
+ Bătălia de împachetat cadouri
+ Creator de elfi
+ Înapoi la treabă
+ Farsă în birou
+ În drum spre petrecere
diff --git a/common/src/main/res/values-ro/strings_invite.xml b/common/src/main/res/values-ro/strings_invite.xml
index 2fa2ba7f3..44f35b913 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..72aef9e6b 100644
--- a/common/src/main/res/values-ro/strings_jetpack.xml
+++ b/common/src/main/res/values-ro/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- 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
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..883231193
--- /dev/null
+++ b/common/src/main/res/values-ru/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Назад к карте
+ Вернуться в деревню
+ Эта версия приложения устарела. Обновите его.
+ Игра окончена
+ Загрузка…
+ Продолжить
+ Сыграть ещё раз
+ Главная
+ Поделиться
+ При скачивании данных игры \"%1$s\" произошла ошибка. Проверьте подключение к Интернету.
+
diff --git a/common/src/main/res/values-ru/strings_appname.xml b/common/src/main/res/values-ru/strings_appname.xml
new file mode 100644
index 000000000..7b4a522f5
--- /dev/null
+++ b/common/src/main/res/values-ru/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Радар Санта-Клауса
+
diff --git a/common/src/main/res/values-ru/strings_doodles.xml b/common/src/main/res/values-ru/strings_doodles.xml
new file mode 100644
index 000000000..661e1840f
--- /dev/null
+++ b/common/src/main/res/values-ru/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Убеги от снежка
+ Заплыв пингвинов
+ Доставь подарок
+ Лучший результат: %1$s
+ Отключить звук
+ Включить звук
+ Закрыть
+ Пауза
+ ЛУЧШИЙ РЕЗУЛЬТАТ: <b>%1$s</b>
+ %1$.1f сек.
+ %1$d м
+
diff --git a/common/src/main/res/values-ru/strings_gamenames.xml b/common/src/main/res/values-ru/strings_gamenames.xml
index f3557ddb9..f7a2a3f9b 100644
--- a/common/src/main/res/values-ru/strings_gamenames.xml
+++ b/common/src/main/res/values-ru/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Жвачка
- Память
- Летающий эльф
- Снежный шар
- Реактивные сани
- Лучший танцор
- Снежок
- Снежная битва
+ Жвачка
+ Память
+ Летающий эльф
+ Реактивные сани
+ Лучший танцор
+ Угадай город
+ Найди подарок
+ Полет за подарками
+ Метание подарков
+ Летающий эльф
+ Аэропорт Северного полюса
+ Стреляй подарками
+ Новогодние рисунки
+ Буги-вуги
+ Управляй эльфом
+ Леденцы
+ Эльфы-музыканты
+ Быстрый пингвин
+ Попади в цель
+ Доставка подарков
+ Гонки с Рудольфом
+ Охота за подарками
+ Найди Санту
+ Санта меняет имидж
+ Раскрась елочную игрушку
+ Лыжный спуск
+ Снежная перестрелка
+ Создай снежинку из кода
+ Узоры на окне
+ Упаковка на скорость
+ Создаем эльфа
+ Снова за дело
+ Розыгрыш в офисе
+ На вечеринку в одной машине
diff --git a/common/src/main/res/values-ru/strings_invite.xml b/common/src/main/res/values-ru/strings_invite.xml
index 9fe6762c9..fca3a0f45 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 очков! Сможешь набрать больше?
+ Пригласите друзей
+ Скачай приложение \"Радар Санта-Клауса\" и следи за путешествиями Санты.
+ Мой результат в игре %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..95fc24df1 100644
--- a/common/src/main/res/values-ru/strings_jetpack.xml
+++ b/common/src/main/res/values-ru/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Хотите получать награды и делиться результатами с друзьями? Войдите в аккаунт!
- Сыграть ещё раз
- Счет
+ Хотите получать награды и делиться результатами с друзьями? Войдите в аккаунт!
+ Сыграть ещё раз
+ Перейти к карте
+ СЧЕТ
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..ad1f9f94d
--- /dev/null
+++ b/common/src/main/res/values-sl/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Igra je končana
+ Zaslon za nalaganje
+ Nadaljuj
+ Ponovno predvajaj
+ Domača stran
+ Daj v skupno rabo
+ Med prenašanjem igre %1$s je prišlo do napake. Ali je vaša omrežna povezava vzpostavljena?
+
diff --git a/common/src/main/res/values-sl/strings_appname.xml b/common/src/main/res/values-sl/strings_appname.xml
new file mode 100644
index 000000000..5d922fc47
--- /dev/null
+++ b/common/src/main/res/values-sl/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Spremljanje Božičkove poti
+
diff --git a/common/src/main/res/values-sl/strings_doodles.xml b/common/src/main/res/values-sl/strings_doodles.xml
new file mode 100644
index 000000000..151db807f
--- /dev/null
+++ b/common/src/main/res/values-sl/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Beg pred snežno kepo
+ Pingvinovo plavanje
+ Metanje daril
+ Najboljši rezultat: %1$s
+ Izklopi zvok
+ Vklopi zvok
+ Zapri
+ Začasno ustavi
+ NAJBOLJŠI REZULTAT: <b>%1$s</b>
+ %1$.1f s
+ %1$d m
+
diff --git a/common/src/main/res/values-sl/strings_gamenames.xml b/common/src/main/res/values-sl/strings_gamenames.xml
index e86193943..d3f7c1fb2 100644
--- a/common/src/main/res/values-sl/strings_gamenames.xml
+++ b/common/src/main/res/values-sl/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Igra Snowball
- Snežni spopad
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Ugibanje mest
+ Iskanje daril
+ Božičkovi sebki
+ Metanje daril
+ Palčkov raketni nahrbtnik
+ Letališče Severni pol
+ Frača z darili
+ Božično risanje
+ Kodirni ples
+ Laboratorij za kodiranje
+ Vodenje bonbonov
+ Skupina Palčki
+ Pingvinovo iskanje
+ Poskočna darila
+ Spust darila
+ Hitri Rudolf
+ Jelenov tek
+ Iskanje Božička
+ Božičkov selfi
+ Čas podarjanja
+ Palček smuča
+ Nevihta kep
+ Kodiranje snežinke
+ Hitrostno skiciranje
+ Zavijalni dvoboj
+ Ustvarjanje palčka
+ Znova na delu
+ Pisarniška potegavščina
+ Skupna vožnja
diff --git a/common/src/main/res/values-sl/strings_invite.xml b/common/src/main/res/values-sl/strings_invite.xml
index 4030a6571..9f7fe991d 100644
--- a/common/src/main/res/values-sl/strings_invite.xml
+++ b/common/src/main/res/values-sl/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 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.
- V Googlovi aplikaciji Spremljanje Božičkove poti sem v igri %2$s s palčki dosegel rezultat %1$d. Me lahko premagate?
+ 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.
+ V Googlovi aplikaciji Spremljanje Božičkove poti sem v igri %2$s s palčki dosegel rezultat %1$d. Me lahko premagate?
diff --git a/common/src/main/res/values-sl/strings_jetpack.xml b/common/src/main/res/values-sl/strings_jetpack.xml
index 596140dbc..ef5204d3b 100644
--- a/common/src/main/res/values-sl/strings_jetpack.xml
+++ b/common/src/main/res/values-sl/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Prijavite se, da odklenete dosežke in objavite svoj rezultat.
- Igraj znova
- Rezultat
+ Prijavite se, da odklenete dosežke in objavite svoj rezultat.
+ Igraj znova
+ Nazaj na zemljevid
+ REZULTAT
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..0b4f388ef
--- /dev/null
+++ b/common/src/main/res/values-sv/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Spelet är slut
+ Läser in scenen
+ Återuppta
+ Spela igen
+ Startsida
+ Dela
+ Ett fel inträffade när %1$s laddades ned. Kontrollera nätverksanslutningen.
+
diff --git a/common/src/main/res/values-sv/strings_appname.xml b/common/src/main/res/values-sv/strings_appname.xml
new file mode 100644
index 000000000..3bfe8b154
--- /dev/null
+++ b/common/src/main/res/values-sv/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Följ jultomten
+
diff --git a/common/src/main/res/values-sv/strings_doodles.xml b/common/src/main/res/values-sv/strings_doodles.xml
new file mode 100644
index 000000000..c58969ee8
--- /dev/null
+++ b/common/src/main/res/values-sv/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snowball Run
+ Penguin Swim
+ Klappkast
+ Bäst: %1$s
+ Ljud av
+ Ljud på
+ Stäng
+ Pausa
+ TOPPRESULTAT: <b>%1$s</b>
+ %1$.1f sek
+ %1$d min
+
diff --git a/common/src/main/res/values-sv/strings_gamenames.xml b/common/src/main/res/values-sv/strings_gamenames.xml
index b84b3125b..bd47d2d97 100644
--- a/common/src/main/res/values-sv/strings_gamenames.xml
+++ b/common/src/main/res/values-sv/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Tomtenisse-jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Spelet Snowball
- Snowdown
+ Gumball
+ Memory
+ Tomtenisse-jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ Stadsfrågor
+ Klappjakten
+ Tomteselfies
+ Presentkast
+ Tomtenisse-jetpack
+ Nordpolens flygplats
+ Julklappskastning
+ Ritkul i jul
+ Koddans
+ Kodlabb
+ Godisspel
+ Tomtenissarna jammar
+ Pingvinloppet
+ Julklappsstuds
+ Julklappsutdelning
+ Rudolfloppet
+ Renspurten
+ Tomtesökning
+ Tomteselfie
+ Gåvornas säsong
+ Nisseslalom
+ Snöbollsstorm
+ Koda en snöflinga
+ Snabbskissa
+ Den stora inslagningen
+ Skapa en tomtenisse
+ Tillbaka på jobbet
+ Kontorsspratt
+ Bilpool
diff --git a/common/src/main/res/values-sv/strings_invite.xml b/common/src/main/res/values-sv/strings_invite.xml
index 47ff8e79e..232afec89 100644
--- a/common/src/main/res/values-sv/strings_invite.xml
+++ b/common/src/main/res/values-sv/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Bjud in dina vänner att följa Jultomten med Google
- Prova Följ jultomten och se hur tomten flyger runt hela världen!
- Jag fick %1$d poäng när jag spelade %2$s med tomtenissarna i Googles Följ Jultomten. Kan du slå det?
+ Bjud in dina vänner att följa Jultomten med Google
+ Prova Följ jultomten och se hur tomten flyger runt hela världen!
+ Jag fick %1$d poäng när jag spelade %2$s med tomtenissarna i Googles Följ Jultomten. Kan du slå det?
diff --git a/common/src/main/res/values-sv/strings_jetpack.xml b/common/src/main/res/values-sv/strings_jetpack.xml
index ad1cbe0e6..f017f3a4d 100644
--- a/common/src/main/res/values-sv/strings_jetpack.xml
+++ b/common/src/main/res/values-sv/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Logga in för att låsa upp prestationer och skicka in ditt resultat.
- Spela igen
- Poäng
+ Logga in för att låsa upp prestationer och skicka in ditt resultat.
+ Spela igen
+ Tillbaka till kartan
+ POÄNG
diff --git a/common/src/main/res/values-sw600dp/dimens.xml b/common/src/main/res/values-sw600dp/dimens.xml
index 67af92005..9851d63ac 100644
--- a/common/src/main/res/values-sw600dp/dimens.xml
+++ b/common/src/main/res/values-sw600dp/dimens.xml
@@ -1,6 +1,36 @@
+
+
+ 16dp
+ 48dp
+ 28dp
+
+ 8dp
+ 320dp
+ 202.5dp
+ 128dp
+ 72dp
+ 8dp
+ 4dp
20dp
75dp
-
+ 16dp
+ 24dp
+ 8dp
+ 55dp
diff --git a/common/src/main/res/values-sw720dp/dimens.xml b/common/src/main/res/values-sw720dp/dimens.xml
index 70387207b..489d38f72 100644
--- a/common/src/main/res/values-sw720dp/dimens.xml
+++ b/common/src/main/res/values-sw720dp/dimens.xml
@@ -1,6 +1,36 @@
+
+
+ 16dp
+ 80dp
+ 56dp
+
+ 8dp
+ 320dp
+ 202.5dp
+ 128dp
+ 72dp
+ 8dp
+ 4dp
28sp
120dp
-
+ 16dp
+ 24dp
+ 8dp
+ 55dp
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..af7766055
--- /dev/null
+++ b/common/src/main/res/values-ta/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ வரைபடத்திற்குச் செல்
+ கிராமத்திற்குச் செல்
+ சான்டா டிராக்கரின் இந்தப் பதிப்பு காலாவதியானது. Play ஸ்டோருக்குச் சென்று, சமீபத்திய பதிப்புக்குப் புதுப்பிக்கவும்.
+ ஆட்டம் முடிந்தது
+ திரையை ஏற்றுகிறது
+ மீண்டும் தொடங்கு
+ மீண்டும் இயக்கு
+ முகப்பு
+ பகிர்
+ %1$sஐப் பதிவிறக்கும் போது பிழை ஏற்பட்டது. உங்கள் நெட்வொர்க் இணைப்பு இயங்குகிறதா?
+
diff --git a/common/src/main/res/values-ta/strings_appname.xml b/common/src/main/res/values-ta/strings_appname.xml
new file mode 100644
index 000000000..8818c1a6c
--- /dev/null
+++ b/common/src/main/res/values-ta/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ சான்டா டிராக்கர்
+
diff --git a/common/src/main/res/values-ta/strings_doodles.xml b/common/src/main/res/values-ta/strings_doodles.xml
new file mode 100644
index 000000000..593f52f93
--- /dev/null
+++ b/common/src/main/res/values-ta/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ ஸ்னோபால் ரன்
+ பென்குயின் ஸ்விம்
+ பிரசென்ட் த்ரோ
+ சிறந்தது: %1$s
+ ஒலியடக்கும் பொத்தான்
+ ஒலி இயக்கும் பொத்தான்
+ மூடும் பொத்தான்
+ இடைநிறுத்தும் பொத்தான்
+ சிறந்த ஸ்கோர்: <b>%1$s</b>
+ %1$.1fவி
+ %1$dமீ
+
diff --git a/common/src/main/res/values-ta/strings_gamenames.xml b/common/src/main/res/values-ta/strings_gamenames.xml
index 0db312ac1..9fdf6d91a 100644
--- a/common/src/main/res/values-ta/strings_gamenames.xml
+++ b/common/src/main/res/values-ta/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- கம் பால்
- மெமரி
- எல்ஃப் ஜெட்பேக்
- ஸ்னோகுளோப்
- ராக்கெட் ஸ்லெய்
- டேஷர் டான்சர்
- ஸ்னோபால் கேம்
- ஸ்னோடவுன்
+ கம் பால்
+ மெமரி
+ எல்ஃப் ஜெட்பேக்
+ ராக்கெட் ஸ்லெய்
+ டேஷர் டான்சர்
+ சிட்டி வினாடி வினா
+ பிரசென்ட் குவெஸ்ட்
+ சான்டா ஸ்னாப்
+ பிரசென்ட் டாஸ்
+ எல்ஃப் ஜெட்பேக்
+ வட துருவ விமான நிலையம்
+ கிஃப்ட் ஸ்லிங்ஷாட்
+ கிளாஸ் ஓவியம்
+ கோடு பூகி
+ கோடு லேப்
+ கம்பால் டில்ட்
+ எல்ஃப் ஜாம்பேண்ட்
+ பென்குயின் டேஷ்
+ பிரசென்ட் பவுன்ஸ்
+ பிரசென்ட் டிராப்
+ ருடால்ஃப் ரேஸர்
+ கலைமான் ஓட்டம்
+ சான்டா தேடல்
+ சான்டா செல்ஃபி
+ கொடையளிக்கும் காலம்
+ எல்ஃப் பனிச்சறுக்கு
+ ஸ்னோபால் ஸ்டோர்ம்
+ ஸ்னோஃப்ளேக்கைக் கோடிங் செய்யுங்கள்
+ ஸ்பீடு ஸ்கெட்ச்
+ ராப் பாட்டில்
+ எல்ஃப் மேக்கர்
+ மீண்டும் வேலை
+ அலுவலகக் குறும்பு
+ கார்பூல்
diff --git a/common/src/main/res/values-ta/strings_invite.xml b/common/src/main/res/values-ta/strings_invite.xml
index d5450cdff..e895f3f8b 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 இன் சான்டா டிராக்கரில் குட்டித் தேவதைகளுடன் %2$s கேமில் %1$d ஸ்கோர் செய்துள்ளேன்! இதை முறியடிக்க முடியுமா?
+ 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..ae051d3cc 100644
--- a/common/src/main/res/values-ta/strings_jetpack.xml
+++ b/common/src/main/res/values-ta/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- சாதனைகளை எட்டவும் உங்கள் ஸ்கோரை வெளியிடவும், உள்நுழையவும்!
- மீண்டும் விளையாடு
- ஸ்கோர்
+ சாதனைகளை எட்டவும் உங்கள் ஸ்கோரை வெளியிடவும், உள்நுழையவும்!
+ மீண்டும் விளையாடுக
+ வரைபடத்திற்குச் செல்
+ ஸ்கோர்
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..be5d739f8
--- /dev/null
+++ b/common/src/main/res/values-th/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ กลับไปยังแผนที่
+ กลับไปยังหมู่บ้าน
+ ตามติดซานต้าเวอร์ชันนี้ล้าสมัยแล้ว โปรดไปที่ Play Store เพื่ออัปเดตเป็นเวอร์ชันล่าสุด
+ จบเกม
+ หน้าจอโหลด
+ เล่นต่อ
+ เล่นอีกครั้ง
+ หน้าแรก
+ แชร์
+ เกิดข้อผิดพลาดขณะดาวน์โหลด %1$s การเชื่อมต่อเครือข่ายของคุณใช้งานได้ใช่ไหม
+
diff --git a/common/src/main/res/values-th/strings_appname.xml b/common/src/main/res/values-th/strings_appname.xml
new file mode 100644
index 000000000..f7865e874
--- /dev/null
+++ b/common/src/main/res/values-th/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ ตามติดซานต้า
+
diff --git a/common/src/main/res/values-th/strings_doodles.xml b/common/src/main/res/values-th/strings_doodles.xml
new file mode 100644
index 000000000..bc547afbd
--- /dev/null
+++ b/common/src/main/res/values-th/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ วิ่งท้าบอลหิมะ
+ เพนกวินแข่งว่ายน้ำ
+ โยนของขวัญ
+ ดีที่สุด: %1$s
+ ปิดเสียง
+ เปิดเสียง
+ ปิด
+ หยุดชั่วคราว
+ คะแนนที่ดีที่สุด: <b>%1$s</b>
+ %1$.1f วินาที
+ %1$d นาที
+
diff --git a/common/src/main/res/values-th/strings_gamenames.xml b/common/src/main/res/values-th/strings_gamenames.xml
index f6e5a3b68..1b26a9c52 100644
--- a/common/src/main/res/values-th/strings_gamenames.xml
+++ b/common/src/main/res/values-th/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- เกมความจำ
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+ ลูกบอลหรรษา
+ เกมความจำ
+ Elf Jetpack
+ เลื่อนจรวด
+ คริสต์มาสแดนซ์
+ ทายเมือง
+ ตามล่าของขวัญ
+ ซานต้าเซลฟี
+ โยนของขวัญ
+ เจ็ตแพ็คของเอลฟ์
+ สนามบินขั้วโลกเหนือ
+ โยนของขวัญด้วยหนังสติ๊ก
+ วาดรูปซานตาคลอส
+ โค้ดเต้นรำ
+ ห้องทดลองโค้ด
+ เอียง Gumball
+ วงแจมแบนด์ของชาวเอลฟ์
+ เพนกวินแดช
+ โยนของขวัญ
+ หย่อนของขวัญ
+ รูดอล์ฟนักวิ่งแข่ง
+ นักวิ่งเรนเดียร์
+ ค้นหาซานต้า
+ ซานต้าเซลฟี
+ เทศกาลแห่งการให้
+ เอลฟ์เล่นสกี
+ ศึกปาลูกบอลหิมะ
+ สร้างเกล็ดหิมะ
+ สเก็ตช์ภาพอย่างเร็ว
+ แข่งห่อของขวัญ
+ เครื่องผลิตเอลฟ์
+ ซานต้าแจกของ
+ แกล้งกันเล่น
+ คาร์พูล
diff --git a/common/src/main/res/values-th/strings_invite.xml b/common/src/main/res/values-th/strings_invite.xml
index db165e988..c75636940 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
- ลองตามติดซานต้าและดูซานต้าบินไปรอบโลก!
- ฉันได้ %1$d คะแนนในการเล่นเกม %2$s กับชาวเอลฟ์ในตามติดซานต้าของ 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..6457683f3 100644
--- a/common/src/main/res/values-th/strings_jetpack.xml
+++ b/common/src/main/res/values-th/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- ลงชื่อเข้าใช้เพื่อปลดล็อกรางวัลพิเศษและโพสต์คะแนนของคุณ
- เล่นอีกครั้ง
- คะแนน
+ ลงชื่อเข้าใช้เพื่อปลดล็อกรางวัลพิเศษและโพสต์คะแนนของคุณ
+ เล่นอีกครั้ง
+ กลับไปที่แผนที่
+ คะแนน
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..852634cc8
--- /dev/null
+++ b/common/src/main/res/values-tl/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Bumalik sa mapa
+ Bumalik sa village
+ Luma na ang bersyong ito ng Santa Tracker. Pakibisita ang Play Store upang makapag-update sa pinakabagong bersyon.
+ Tapos na ang Laro
+ Nilo-load ang screen
+ Magpatuloy
+ I-replay
+ Home
+ bahagi
+ Nagka-error habang dina-download ang %1$s. Gumagana ba ang koneksyon ng iyong network?
+
diff --git a/common/src/main/res/values-tl/strings_appname.xml b/common/src/main/res/values-tl/strings_appname.xml
new file mode 100644
index 000000000..77d556f56
--- /dev/null
+++ b/common/src/main/res/values-tl/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Santa Tracker
+
diff --git a/common/src/main/res/values-tl/strings_doodles.xml b/common/src/main/res/values-tl/strings_doodles.xml
new file mode 100644
index 000000000..ceb2b9f97
--- /dev/null
+++ b/common/src/main/res/values-tl/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Snowball Run
+ Penguin Swim
+ Present Throw
+ Pinakamataas: %1$s
+ I-mute
+ I-unmute
+ Isara
+ I-pause
+ PINAKAMATAAS NA SCORE: <b>%1$s</b>
+ %1$.1fs
+ %1$dm
+
diff --git a/common/src/main/res/values-tl/strings_gamenames.xml b/common/src/main/res/values-tl/strings_gamenames.xml
index 53e834857..bee518e97 100644
--- a/common/src/main/res/values-tl/strings_gamenames.xml
+++ b/common/src/main/res/values-tl/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Larong Snowball
- Snowdown
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ City Quiz
+ Present Quest
+ Santa Snap
+ Present Toss
+ Elf Jetpack
+ North Pole Airport
+ Gift Slingshot
+ Claus Draws
+ Code Boogie
+ Code Lab
+ Gumball Tilt
+ Elf Jamband
+ Penguin Dash
+ Present Bounce
+ Present Drop
+ Rudolph Racer
+ Reindeer Runner
+ Santa Search
+ Santa Selfie
+ Panahon ng Bigayan
+ Elf Ski
+ Snowball Storm
+ Code a Snowflake
+ Speed Sketch
+ Wrap Battle
+ Elf Maker
+ Back to Work
+ Office Prank
+ Carpool
diff --git a/common/src/main/res/values-tl/strings_invite.xml b/common/src/main/res/values-tl/strings_invite.xml
index ad736646d..f8920ce63 100644
--- a/common/src/main/res/values-tl/strings_invite.xml
+++ b/common/src/main/res/values-tl/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- Imbitahan ang iyong mga kaibigan na subaybayan si Santa sa Google
- Subukan ang Santa Tracker at panoorin ang paglipad ni Santa sa buong mundo!
- Nakapuntos ako ng %1$d sa paglalaro ng %2$s game na may elves sa Santa Tracker ng Google, kaya mo bang talunin iyon?
+ Imbitahan ang iyong mga kaibigan na subaybayan si Santa sa Google
+ Subukan ang Santa Tracker at panoorin ang paglipad ni Santa sa buong mundo!
+ Nakapuntos ako ng %1$d sa paglalaro ng %2$s game na may elves sa Santa Tracker ng Google, kaya mo bang talunin iyon?
diff --git a/common/src/main/res/values-tl/strings_jetpack.xml b/common/src/main/res/values-tl/strings_jetpack.xml
index 0723cba66..e5690d3c0 100644
--- a/common/src/main/res/values-tl/strings_jetpack.xml
+++ b/common/src/main/res/values-tl/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Mag-sign in upang mai-unlock ang mga achievement at mai-post ang iyong score!
- Maglaro Muli
- Score
+ Mag-sign in upang mai-unlock ang mga achievement at mai-post ang iyong score!
+ Maglaro Muli
+ Bumalik sa Mapa
+ SCORE
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..af17600ed
--- /dev/null
+++ b/common/src/main/res/values-uk/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ Назад на карту
+ Назад у містечко
+ Ця версія додатка Де Дід Мороз застаріла. Перейдіть у веб-магазин Play, щоб завантажити останню версію.
+ Гру закінчено
+ Завантаження екрана
+ Відновити
+ Грати ще раз
+ Головний екран
+ Поділитися
+ Помилка завантаження гри \"%1$s\". Перевірте підключення до мережі.
+
diff --git a/common/src/main/res/values-uk/strings_appname.xml b/common/src/main/res/values-uk/strings_appname.xml
new file mode 100644
index 000000000..3f47baaf9
--- /dev/null
+++ b/common/src/main/res/values-uk/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Де Дід Мороз
+
diff --git a/common/src/main/res/values-uk/strings_doodles.xml b/common/src/main/res/values-uk/strings_doodles.xml
new file mode 100644
index 000000000..10eb9771e
--- /dev/null
+++ b/common/src/main/res/values-uk/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Утікай від сніжки
+ Заплив пінгвіна
+ Роздача подарунків
+ Найкращий результат: %1$s
+ Вимкнути звук
+ Увімкнути звук
+ Закрити
+ Призупинити
+ НАЙКРАЩИЙ РЕЗУЛЬТАТ: <b>%1$s</b>
+ %1$.1f с
+ %1$d хв
+
diff --git a/common/src/main/res/values-uk/strings_gamenames.xml b/common/src/main/res/values-uk/strings_gamenames.xml
index c74f9043d..c9386428a 100644
--- a/common/src/main/res/values-uk/strings_gamenames.xml
+++ b/common/src/main/res/values-uk/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Гамбол
- Згадати все
- Реактивні ельфи
- Снігова куля
- Реактивні санчата
- Олені
- Гра \"Сніжки\"
- Сніжки
+ Гамбол
+ Згадати все
+ Реактивні ельфи
+ Реактивні санчата
+ Олені
+ Угадай місто
+ Знайди подарунок
+ Знімок для Діда Мороза
+ Подарунковий бум
+ Реактивні ельфи
+ Аеропорт Північного полюса
+ Подарункова рогатка
+ Малюнок для Діда Мороза
+ Бугі-вугі
+ Пазли
+ Перекоти кульку
+ Музичний гурт помічників Діда Мороза
+ Біг пінгвіна
+ Підкидання подарунків
+ Кидання подарунків
+ Гонщик Рудольф
+ Олень-бігун
+ Пошук Діда Мороза
+ Селфі Діда Мороза
+ Сезон подарунків
+ Ельф на лижах
+ Бій сніжками
+ Створення сніжинки
+ Швидка замальовка
+ Пакування подарунків
+ Мій власний ельф
+ Знову до роботи
+ Офісна витівка
+ Підготовка до вечірки
diff --git a/common/src/main/res/values-uk/strings_invite.xml b/common/src/main/res/values-uk/strings_invite.xml
index a51b7b640..5dbacc947 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
- Завантажте додаток Де Дід Мороз і стежте за пересуванням Діда Мороза по світу!
- У грі \"%2$s\" у Google Де Дід Мороз у мене вже стільки очок: %1$d. Наберете більше?
+ Запросіть друзів стежити за Дідом Морозом у 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..42267245f 100644
--- a/common/src/main/res/values-uk/strings_jetpack.xml
+++ b/common/src/main/res/values-uk/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Увійдіть, щоб розблокувати досягнення й повідомити свій результат іншим.
- Грати ще раз
- Результат
+ Увійдіть, щоб розблокувати досягнення й повідомити свій результат іншим.
+ Грати ще раз
+ Назад на карту
+ РАХУНОК
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..b47c71066
--- /dev/null
+++ b/common/src/main/res/values-vi/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 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.
+ Kết thúc
+ Đang tải màn hình
+ Tiếp tục
+ Phát lại
+ Trang chủ
+ Chia sẻ
+ Đã xảy ra lỗi khi tải %1$s. Vui lòng kiểm tra kết nối mạng.
+
diff --git a/common/src/main/res/values-vi/strings_appname.xml b/common/src/main/res/values-vi/strings_appname.xml
new file mode 100644
index 000000000..ff842c03b
--- /dev/null
+++ b/common/src/main/res/values-vi/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ Theo chân ông già Noel
+
diff --git a/common/src/main/res/values-vi/strings_doodles.xml b/common/src/main/res/values-vi/strings_doodles.xml
new file mode 100644
index 000000000..2b826737f
--- /dev/null
+++ b/common/src/main/res/values-vi/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Chạy bóng tuyết
+ Chim cánh cụt bơi lội
+ Ném quà
+ Điểm tốt nhất: %1$s
+ Tắt tiếng
+ Bật tiếng
+ Đóng
+ Tạm dừng
+ ĐIỂM TỐT NHẤT: <b>%1$s</b>
+ %1$.1f giây
+ %1$d mé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..779de57e4 100644
--- a/common/src/main/res/values-vi/strings_gamenames.xml
+++ b/common/src/main/res/values-vi/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- 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
+ Đoán tên thành phố
+ Săn tìm quà tặng
+ Santa Snap
+ Tung quà
+ Ba lô phản lực của chú lùn
+ Sân bay Bắc Cực
+ Súng bắn quà
+ Vẽ tranh ông già Noel
+ Vũ điệu của mã
+ Phòng thí nghiệm mã
+ Nghiêng Gumball
+ Ban nhạc của chú lùn
+ Chim cánh cụt nhặt quà
+ Trò chơi nảy quà
+ Thả quà
+ Tay đua Rudolph
+ Người cưỡi tuần lộc
+ Tìm kiếm ông già Noel
+ Ảnh tự chụp của ông già Noel
+ Mùa trao tặng
+ Yêu tinh trượt tuyết
+ Bão bóng tuyết
+ Viết mã cho bông tuyết
+ Ký họa nhanh
+ Wrap Battle
+ Công cụ tạo chú lùn
+ Quay lại làm việc
+ Trò đùa ở văn phòng
+ Đi chung xe
diff --git a/common/src/main/res/values-vi/strings_invite.xml b/common/src/main/res/values-vi/strings_invite.xml
index 753baa2af..7ba8721da 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
- 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?
+ 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..d4013effd 100644
--- a/common/src/main/res/values-vi/strings_jetpack.xml
+++ b/common/src/main/res/values-vi/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- Đă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
+ Đăng nhập để gặt hái thành tích và đăng điểm của bạn!
+ Chơi lại
+ Trở lại bản đồ
+ ĐIỂM
diff --git a/common/src/main/res/values-xhdpi/dimens.xml b/common/src/main/res/values-xhdpi/dimens.xml
index 6697d3c78..c214dff58 100644
--- a/common/src/main/res/values-xhdpi/dimens.xml
+++ b/common/src/main/res/values-xhdpi/dimens.xml
@@ -1,6 +1,34 @@
+
+
+ 16dp
+
+ 8dp
+ 320dp
+ 202.5dp
+ 128dp
+ 72dp
+ 8dp
+ 4dp
12sp
50dp
-
+ 16dp
+ 24dp
+ 8dp
+ 55dp
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..e8f4e8266
--- /dev/null
+++ b/common/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 返回地图
+ 返回小镇
+ 此版本的“追踪圣诞老人”应用已经失效。请访问 Google Play 商店更新为最新版本。
+ 游戏结束
+ 正在加载屏幕
+ 继续
+ 再玩一次
+ 主屏幕
+ 分享
+ 下载《%1$s》时出错。您的网络连接是否正常?
+
diff --git a/common/src/main/res/values-zh-rCN/strings_appname.xml b/common/src/main/res/values-zh-rCN/strings_appname.xml
new file mode 100644
index 000000000..e08aae898
--- /dev/null
+++ b/common/src/main/res/values-zh-rCN/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ 追踪圣诞老人
+
diff --git a/common/src/main/res/values-zh-rCN/strings_doodles.xml b/common/src/main/res/values-zh-rCN/strings_doodles.xml
new file mode 100644
index 000000000..57338d376
--- /dev/null
+++ b/common/src/main/res/values-zh-rCN/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ 雪球跑跑跑
+ 企鹅爱游泳
+ 扔礼物
+ 最高得分:%1$s
+ 静音
+ 取消静音
+ 关闭
+ 暂停
+ 最高得分:<b>%1$s</b>
+ %1$.1f 秒
+ %1$d 米
+
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..6816463d2 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,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball 游戏
- Snowdown
+ 掉落口香糖
+ 翻牌配对
+ Elf Jetpack
+ 火箭雪橇
+ 猛冲者跳舞
+ 城市知多少
+ 寻找礼物
+ 圣诞老人快拍
+ 投掷礼物
+ 精灵飞侠
+ 北极机场
+ 礼物弹弓
+ 圣诞老人绘图
+ 编码热舞
+ 编码实验室
+ 彩球滑落
+ 摇滚精灵乐
+ 企鹅向前冲
+ 礼物弹弹跳
+ 礼从天降
+ 驯鹿狂飙
+ 驯鹿快跑接大礼
+ 圣诞老人找找乐
+ 圣诞老人换造型
+ 温馨分享季
+ 精灵滑雪
+ 雪球风暴
+ 雪花编码
+ 快手画图
+ 包装快手
+ 精灵制造
+ 圣诞老人复工啦
+ 办公室恶作剧
+ 拼车欢乐多
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..3ec8b3c89 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 分。你敢来挑战吗?
+ 邀请好友在 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..8a8673f21 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,23 @@
+
+
- 登录即可记录您的成就并发布您的得分!
- 重玩
- 得分
+ 登录即可记录您的成就并发布您的得分!
+ 重玩
+ 返回地图
+ 得分
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..dfbca94c0
--- /dev/null
+++ b/common/src/main/res/values-zh-rHK/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 返回地圖
+ 返回村落
+ 這個「聖誕老人追蹤器」不是最新版本。請前往 Play 商店更新至最新版本。
+ 遊戲結束
+ 正在載入畫面
+ 繼續
+ 再玩一次
+ 主畫面
+ 分享
+ 下載 %1$s 時出現錯誤,請檢查網絡連線。
+
diff --git a/common/src/main/res/values-zh-rHK/strings_appname.xml b/common/src/main/res/values-zh-rHK/strings_appname.xml
new file mode 100644
index 000000000..469cfbd1c
--- /dev/null
+++ b/common/src/main/res/values-zh-rHK/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ 聖誕老人追蹤器
+
diff --git a/common/src/main/res/values-zh-rHK/strings_doodles.xml b/common/src/main/res/values-zh-rHK/strings_doodles.xml
new file mode 100644
index 000000000..15c046891
--- /dev/null
+++ b/common/src/main/res/values-zh-rHK/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ 雪球大暴走
+ 企鵝暢泳
+ 拋禮物
+ 最佳成績:%1$s
+ 靜音
+ 取消靜音
+ 關閉
+ 暫停
+ 最佳成績:<b>%1$s</b>
+ %1$.1f 秒
+ %1$d 分鐘
+
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..33390ea90 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,53 @@
+
+
- Gumball
- Memory
- 小精靈飛行背包
- 雪景球
- 火箭雪橇
- 猛衝‧跳舞
- 雪球遊戲
- Snowdown
+ Gumball
+ Memory
+ 小精靈飛行背包
+ 火箭雪橇
+ 猛衝‧跳舞
+ 城市問答
+ 禮物尋寶
+ 聖誕老人快照
+ 禮物拋拋樂
+ 小精靈一飛衝天
+ 北極機場
+ 禮物彈弓手
+ 聖誕老人畫畫
+ 編碼熱舞
+ 編碼實驗室
+ 口香糖遊戲機
+ 小精靈 Jam 歌夾 Band
+ 企鵝衝衝衝
+ 禮物彈彈跳
+ 禮物從天降
+ 聖誕馴鹿競賽
+ 馴鹿狂奔接大禮
+ 尋找聖誕老人
+ 聖誕老人自拍
+ 奉獻的季節
+ 小精靈高山滑雪
+ 雪球大戰
+ 編碼雪花樂
+ 極速繪畫
+ 聖誕禮物密密包
+ 小精靈製造器
+ 聖誕老人復工了
+ 辦公室惡作劇
+ 一起坐車
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..e38d43d79 100644
--- a/common/src/main/res/values-zh-rHK/strings_invite.xml
+++ b/common/src/main/res/values-zh-rHK/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 邀請好友在 Google 追蹤聖誕老人
- 試玩「追蹤聖誕老人」,追看聖誕老人遨遊世界各地!
- 我與小精靈在 Google「追蹤聖誕老人」玩%1$d時得獲得 %2$s 分,您能打敗我嗎?
+ 邀請好友在 Google 追蹤聖誕老人
+ 試玩「追蹤聖誕老人」,追看聖誕老人遨遊世界各地!
+ 我與小精靈在 Google「追蹤聖誕老人」玩%1$d時得獲得 %2$s 分,您能打敗我嗎?
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..094086182 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,23 @@
+
+
- 登入即可解鎖成就並發佈您的得分!
- 再玩一次
- 樂譜
+ 登入即可解鎖成就並發佈您的得分!
+ 再玩一次
+ 返回地圖
+ 得分
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..78fa5793a
--- /dev/null
+++ b/common/src/main/res/values-zh-rTW/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 返回地圖
+ 返回聖誕老人村
+ 目前的聖誕老人追蹤器版本已過期。請前往 Google Play 商店更新至最新版本。
+ 遊戲結束
+ 正在載入畫面
+ 繼續
+ 再玩一次
+ 主畫面
+ 分享
+ 下載「%1$s」時發生錯誤,請檢查你的網路連線。
+
diff --git a/common/src/main/res/values-zh-rTW/strings_appname.xml b/common/src/main/res/values-zh-rTW/strings_appname.xml
new file mode 100644
index 000000000..469cfbd1c
--- /dev/null
+++ b/common/src/main/res/values-zh-rTW/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ 聖誕老人追蹤器
+
diff --git a/common/src/main/res/values-zh-rTW/strings_doodles.xml b/common/src/main/res/values-zh-rTW/strings_doodles.xml
new file mode 100644
index 000000000..5d0237122
--- /dev/null
+++ b/common/src/main/res/values-zh-rTW/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ 雪球大進擊
+ 企鵝游泳大賽
+ 投擲禮物
+ 最佳成績:%1$s
+ 靜音
+ 取消靜音
+ 關閉
+ 暫停
+ 最佳成績:<b>%1$s</b>
+ %1$.1f 秒
+ %1$d 公尺
+
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..23a002618 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,53 @@
+
+
- 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..b3391261a 100644
--- a/common/src/main/res/values-zh-rTW/strings_invite.xml
+++ b/common/src/main/res/values-zh-rTW/strings_invite.xml
@@ -1,6 +1,22 @@
+
+
- 邀請好友與 Google 一起追蹤聖誕老人
- 快來體驗聖誕老人追蹤器,和聖誕老人一起遨遊世界!
- 我在 Google 聖誕老人追蹤器中與小精靈一起玩「%2$s」遊戲,獲得 %1$d 分!你能打敗我嗎?
+ 邀請好友與 Google 一起追蹤聖誕老人
+ 快來體驗聖誕老人追蹤器,和聖誕老人一起遨遊世界!
+ 我在 Google 聖誕老人追蹤器中與小精靈一起玩「%2$s」遊戲,獲得 %1$d 分!你能打敗我嗎?
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..3a1503571 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,23 @@
+
+
- 登入即可解開遊戲關卡並發表您的得分!
- 再玩一次
- 得分
+ 登入即可解開遊戲關卡並發表您的得分!
+ 再玩一次
+ 返回地圖
+ 總成績
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..e8f4e8266
--- /dev/null
+++ b/common/src/main/res/values-zh/strings.xml
@@ -0,0 +1,28 @@
+
+
+
+ 返回地图
+ 返回小镇
+ 此版本的“追踪圣诞老人”应用已经失效。请访问 Google Play 商店更新为最新版本。
+ 游戏结束
+ 正在加载屏幕
+ 继续
+ 再玩一次
+ 主屏幕
+ 分享
+ 下载《%1$s》时出错。您的网络连接是否正常?
+
diff --git a/common/src/main/res/values-zh/strings_appname.xml b/common/src/main/res/values-zh/strings_appname.xml
new file mode 100644
index 000000000..e08aae898
--- /dev/null
+++ b/common/src/main/res/values-zh/strings_appname.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ 追踪圣诞老人
+
diff --git a/common/src/main/res/values-zh/strings_doodles.xml b/common/src/main/res/values-zh/strings_doodles.xml
new file mode 100644
index 000000000..57338d376
--- /dev/null
+++ b/common/src/main/res/values-zh/strings_doodles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ 雪球跑跑跑
+ 企鹅爱游泳
+ 扔礼物
+ 最高得分:%1$s
+ 静音
+ 取消静音
+ 关闭
+ 暂停
+ 最高得分:<b>%1$s</b>
+ %1$.1f 秒
+ %1$d 米
+
diff --git a/common/src/main/res/values-zh/strings_gamenames.xml b/common/src/main/res/values-zh/strings_gamenames.xml
index 66587b8fd..6816463d2 100644
--- a/common/src/main/res/values-zh/strings_gamenames.xml
+++ b/common/src/main/res/values-zh/strings_gamenames.xml
@@ -1,11 +1,53 @@
+
+
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball 游戏
- Snowdown
+ 掉落口香糖
+ 翻牌配对
+ Elf Jetpack
+ 火箭雪橇
+ 猛冲者跳舞
+ 城市知多少
+ 寻找礼物
+ 圣诞老人快拍
+ 投掷礼物
+ 精灵飞侠
+ 北极机场
+ 礼物弹弓
+ 圣诞老人绘图
+ 编码热舞
+ 编码实验室
+ 彩球滑落
+ 摇滚精灵乐
+ 企鹅向前冲
+ 礼物弹弹跳
+ 礼从天降
+ 驯鹿狂飙
+ 驯鹿快跑接大礼
+ 圣诞老人找找乐
+ 圣诞老人换造型
+ 温馨分享季
+ 精灵滑雪
+ 雪球风暴
+ 雪花编码
+ 快手画图
+ 包装快手
+ 精灵制造
+ 圣诞老人复工啦
+ 办公室恶作剧
+ 拼车欢乐多
diff --git a/common/src/main/res/values-zh/strings_invite.xml b/common/src/main/res/values-zh/strings_invite.xml
index e4e256ba4..3ec8b3c89 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 分。你敢来挑战吗?
+ 邀请好友在 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..8a8673f21 100644
--- a/common/src/main/res/values-zh/strings_jetpack.xml
+++ b/common/src/main/res/values-zh/strings_jetpack.xml
@@ -1,6 +1,23 @@
+
+
- 登录即可记录您的成就并发布您的得分!
- 重玩
- 得分
+ 登录即可记录您的成就并发布您的得分!
+ 重玩
+ 返回地图
+ 得分
diff --git a/common/src/main/res/values/colors.xml b/common/src/main/res/values/colors.xml
new file mode 100644
index 000000000..8f77d1f14
--- /dev/null
+++ b/common/src/main/res/values/colors.xml
@@ -0,0 +1,73 @@
+
+
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
+ #16cc82
+ #1DC07D
+ #109f65
+ #87d745
+ #ffffff
+ #89000000
+ #b2138e61
+
+ #139538
+ @color/trackerPrimary
+ #FF5722
+ @color/trackerPrimary
+ #9affb4
+ #283593
+ #FFFFFF
+
+ #789088
+ #885090
+ #80A058
+ #786880
+ #686890
+ #6898B0
+ #A87880
+ #4898A0
+ #6890A8
+ #588090
+ #A8A8B0
+ #7860A0
+ #7f3d86
+ #58A060
+ #708088
+ #B05068
+ #90C8C0
+ #509870
+ #68A8A8
+ #9850A0
+ #88A0A8
+ #8888A8
+ #408080
+ #60B080
+ #605060
+ #504888
+ #50A868
+ #A098A8
+ #60B060
+ #FB8C00
+ #9E4A20
+
+ #ff00c3ea
+
+
diff --git a/common/src/main/res/values/dimens.xml b/common/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..b88afcdd8
--- /dev/null
+++ b/common/src/main/res/values/dimens.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ 16sp
+ 32dp
+ 32dp
+ 20dp
+
+ 250dp
+ 8dp
+
diff --git a/common/src/main/res/values/font_certs.xml b/common/src/main/res/values/font_certs.xml
new file mode 100644
index 000000000..539a0cc47
--- /dev/null
+++ b/common/src/main/res/values/font_certs.xml
@@ -0,0 +1,32 @@
+
+
+
+
+ - @array/com_google_android_gms_fonts_certs_dev
+ - @array/com_google_android_gms_fonts_certs_prod
+
+
+ -
+ MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
+
+
+
+ -
+ MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
+
+
+
diff --git a/common/src/main/res/values/game_colors.xml b/common/src/main/res/values/game_colors.xml
index a65a2f29e..7124bd5c0 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/preloaded_fonts.xml b/common/src/main/res/values/preloaded_fonts.xml
new file mode 100644
index 000000000..9d18e90d0
--- /dev/null
+++ b/common/src/main/res/values/preloaded_fonts.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ - @font/lobster
+
+
diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml
index 185e6f2ad..771bbc91b 100644
--- a/common/src/main/res/values/strings.xml
+++ b/common/src/main/res/values/strings.xml
@@ -1,3 +1,27 @@
-
- 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.
+ Game Over
+ Loading screen
+ Resume
+ Replay
+ Home
+ Share
+ extra_large_present
+ An error occurred while downloading %1$s. Is your network connection working?
diff --git a/common/src/main/res/values/strings_activity_uris.xml b/common/src/main/res/values/strings_activity_uris.xml
new file mode 100644
index 000000000..38d7c9909
--- /dev/null
+++ b/common/src/main/res/values/strings_activity_uris.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ http
+ https
+ www.google.com
+ /santatracker/android/jetpack
+ /santatracker/android/cityquiz
+ /santatracker/android/gumball
+ /santatracker/android/memory
+ /santatracker/now
+ /santatracker/android/dasherdancer
+ /santatracker/android/presentquest
+ /santatracker/android/rocketsleigh
+ /santatracker/android/unity
+
diff --git a/common/src/main/res/values/strings_appname.xml b/common/src/main/res/values/strings_appname.xml
new file mode 100644
index 000000000..73050b583
--- /dev/null
+++ b/common/src/main/res/values/strings_appname.xml
@@ -0,0 +1,18 @@
+
+
+ Santa Tracker
+
diff --git a/common/src/main/res/values/strings_doodles.xml b/common/src/main/res/values/strings_doodles.xml
new file mode 100644
index 000000000..2dc30714c
--- /dev/null
+++ b/common/src/main/res/values/strings_doodles.xml
@@ -0,0 +1,51 @@
+
+
+
+ Snowball Run
+ Penguin Swim
+ Present Throw
+ Best: %1$s
+ Mute
+ Unmute
+ Close
+ Pause
+
+ Load
+ Save
+ Reset
+ Delete
+ Delete
+ Save
+ Cancel
+ Create object
+ Collision
+ Scenery
+
+ BEST SCORE: <b>%1$s</b>
+
+
+
+ %1$.1fs
+
+
+ %1$dm
+
+ %1$d
+ %1$d
+ +%1$d
+ %1$d
+
diff --git a/common/src/main/res/values/strings_gamenames.xml b/common/src/main/res/values/strings_gamenames.xml
index 6529032bf..ff646f3e7 100644
--- a/common/src/main/res/values/strings_gamenames.xml
+++ b/common/src/main/res/values/strings_gamenames.xml
@@ -1,11 +1,51 @@
-
- Gumball
- Memory
- Elf Jetpack
- Snowglobe
- Rocket Sleigh
- Dasher Dancer
- Snowball game
- Snowdown
+
+ Gumball
+ Memory
+ Elf Jetpack
+ Rocket Sleigh
+ Dasher Dancer
+ City Quiz
+ Present Quest
+ Santa Snap
+ Present Toss
+ Elf Jetpack
+ North Pole Airport
+ Gift Slingshot
+ Claus Draws
+ Code Boogie
+ Code Lab
+ Gumball Tilt
+ Elf Jamband
+ Penguin Dash
+ Present Bounce
+ Present Drop
+ Rudolph Racer
+ Reindeer Runner
+ Santa Search
+ Santa Selfie
+ Season of Giving
+ Elf Ski
+ Snowball Storm
+ Code a Snowflake
+ Speed Sketch
+ Wrap Battle
+ Elf Maker
+ Back to Work
+ Office Prank
+ Carpool
diff --git a/common/src/main/res/values/strings_invite.xml b/common/src/main/res/values/strings_invite.xml
index 931856330..2696ac62f 100644
--- a/common/src/main/res/values/strings_invite.xml
+++ b/common/src/main/res/values/strings_invite.xml
@@ -1,12 +1,26 @@
-
-
+
+
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..9be04c546 100644
--- a/common/src/main/res/values/strings_jetpack.xml
+++ b/common/src/main/res/values/strings_jetpack.xml
@@ -1,6 +1,21 @@
-
- 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
diff --git a/common/src/main/res/values/styles.xml b/common/src/main/res/values/styles.xml
new file mode 100644
index 000000000..704d94e70
--- /dev/null
+++ b/common/src/main/res/values/styles.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/common/src/main/res/values/values_analytics.xml b/common/src/main/res/values/values_analytics.xml
new file mode 100644
index 000000000..440735496
--- /dev/null
+++ b/common/src/main/res/values/values_analytics.xml
@@ -0,0 +1,85 @@
+
+
+
+
+ Village
+ Gumball
+ Memory
+ Jetpack
+ Tracker
+ CastController
+ CityQuiz
+ WebScene: %1$s
+
+ Launch
+ Notification
+ Launch Button
+ Voice
+ Unhandled
+
+ Cast
+ ConnectionLaunchActivity
+ ConnectionMapActivity
+ Connected
+ Disconnected
+ StateChangeLaunchActivity
+ StateChangeMapActivity
+ overlayshown
+
+ OpenController
+ ActionBar
+ MediaRouter
+
+ SwitchController
+ Touch
+ Dpad
+
+ Tracker
+ SantaCamEnabled
+ ActionBar
+ FAB
+ Timeout
+
+ LocationSelected
+ OpenStreetView
+ OpenVideo
+ ClickSanta
+
+ Error
+ Finished
+ TimeUpdate
+ NoData
+ SwitchOff
+
+ Card
+ Expanded
+ Closed
+
+ StartGame
+ Village
+ Click
+ EasterEgg Unlocked
+
+ Moon
+ Sun
+ UFO
+ Plane
+
+ WebScene
+ Error
+ WebAction
+
diff --git a/common/src/main/res/xml/config_analytics_global.xml b/common/src/main/res/xml/config_analytics_global.xml
new file mode 100644
index 000000000..5b3f55272
--- /dev/null
+++ b/common/src/main/res/xml/config_analytics_global.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ warning
+ false
+
+
diff --git a/common/src/main/res/xml/config_analytics_tracker.xml b/common/src/main/res/xml/config_analytics_tracker.xml
index 5d667745c..0dc1620eb 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/google_now_actions.xml b/common/src/main/res/xml/google_now_actions.xml
new file mode 100644
index 000000000..44924cc58
--- /dev/null
+++ b/common/src/main/res/xml/google_now_actions.xml
@@ -0,0 +1,18 @@
+
+
+
+
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..d62bef5f2
--- /dev/null
+++ b/common/src/main/res/xml/remote_config_defaults.xml
@@ -0,0 +1,349 @@
+
+
+
+
+
+ DisableSanta
+ false
+
+
+ DisableCastButton
+ true
+
+
+ DisableDestinationPhoto
+ false
+
+
+ DisablePresentQuest
+ true
+
+
+ FeaturePresentQuest
+ false
+
+
+ FeatureCityQuiz
+ true
+
+
+ DisableCityQuiz
+ false
+
+
+ FeatureGumballGame
+ false
+
+
+ DisableGumballGame
+ false
+
+
+ FeatureJetpackGame
+ false
+
+
+ DisableJetpackGame
+ false
+
+
+ FeatureMemoryGame
+ false
+
+
+ DisableMemoryGame
+ false
+
+
+ FeatureRocketGame
+ false
+
+
+ DisableRocketGame
+ false
+
+
+ FeatureDancerGame
+ false
+
+
+ DisableDancerGame
+ false
+
+
+ FeatureSwimmingGame
+ false
+
+
+ DisableSwimmingGame
+ false
+
+
+ FeatureBmxGame
+ false
+
+
+ DisableBmxGame
+ false
+
+
+ FeatureRunningGame
+ true
+
+
+ DisableRunningGame
+ false
+
+
+ FeatureTennisGame
+ false
+
+
+ DisableTennisGame
+ false
+
+
+ FeatureWaterpoloGame
+ false
+
+
+ DisableWaterpoloGame
+ false
+
+
+ FeatureSantaSnap
+ false
+
+
+ DisableSantaSnap
+ true
+
+
+ Video1
+ zE_D9Vd69aw
+
+
+ Video15
+ IXmDOu-eSx4
+
+
+ Video23
+ h83b1lWPuvQ
+
+
+ SantaTakeoff
+ 1545645600
+
+
+ SantaArrival
+ 1545778800
+
+
+ UnlockGumball
+ 0
+
+
+ UnlockMemory
+ 0
+
+
+ UnlockJetpack
+ 0
+
+
+ UnlockRocket
+ 0
+
+
+ UnlockDancer
+ 0
+
+
+ UnlockRocket
+ 0
+
+
+ UnlockVideo1
+ 0
+
+
+ UnlockVideo15
+ 1544832000000
+
+
+ UnlockVideo23
+ 1545523200000
+
+
+ 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
+
+
+ WebAirportDisabled
+ true
+
+
+ WebBoatloadDisabled
+ true
+
+
+ WebClausdrawsDisabled
+ true
+
+
+ WebCodeboogieDisabled
+ true
+
+
+ WebCodelabDisabled
+ true
+
+
+ WebElfskiDisabled
+ true
+
+
+
+ WebGumballDisabled
+ true
+
+
+ WebJambandDisabled
+ true
+
+
+ WebJetpackDisabled
+ true
+
+
+ WebPenguindashDisabled
+ true
+
+
+ WebPresentbounceDisabled
+ true
+
+
+ WebPresentdropDisabled
+ true
+
+
+ WebRacerDisabled
+ true
+
+
+ WebRunnerDisabled
+ true
+
+
+ WebSantasearchDisabled
+ true
+
+
+ WebSantaselfieDisabled
+ true
+
+
+ WebSantasnapDisabled
+ true
+
+
+ WebSeasonofgivingDisabled
+ true
+
+ WebSnowballDisabled
+ true
+
+
+ WebSnowflakeDisabled
+ true
+
+
+ WebSpeedsketchDisabled
+ true
+
+
+ WebWrapbattleDisabled
+ true
+
+
+ WebElfMakerDisabled
+ true
+
+
+ StickersConfigUrl
+
+ https://firebasestorage.googleapis.com/v0/b/santa-tracker-firebase.appspot.com/o/stickers%2Fstickers.json?alt=media&token=aa113740-b356-4012-9a22-179c7650ce72
+
+
+
diff --git a/common/src/release/res/xml/config_analytics_global.xml b/common/src/release/res/xml/config_analytics_global.xml
new file mode 100644
index 000000000..5b3f55272
--- /dev/null
+++ b/common/src/release/res/xml/config_analytics_global.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ warning
+ false
+
+
diff --git a/dasherdancer/build.gradle b/dasherdancer/build.gradle
index 5e15ac2a0..aa3310d25 100644
--- a/dasherdancer/build.gradle
+++ b/dasherdancer/build.gradle
@@ -1,17 +1,32 @@
-apply plugin: 'com.android.library'
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
+apply plugin: 'com.android.dynamic-feature'
+apply plugin: 'kotlin-android'
android {
- compileSdkVersion 23
+ compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.tools
defaultConfig {
- minSdkVersion 15
- targetSdkVersion 23
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
}
}
dependencies {
- compile project(':common')
- compile rootProject.ext.supportV4
- compile rootProject.ext.seismic
+ api project(':santa-tracker')
}
diff --git a/dasherdancer/proguard-rules.pro b/dasherdancer/proguard-rules.pro
deleted file mode 100644
index 67abb7535..000000000
--- a/dasherdancer/proguard-rules.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /Users/rpetit/android_sdk/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/dasherdancer/src/main/AndroidManifest.xml b/dasherdancer/src/main/AndroidManifest.xml
index e6f01795f..1c9120f83 100644
--- a/dasherdancer/src/main/AndroidManifest.xml
+++ b/dasherdancer/src/main/AndroidManifest.xml
@@ -1,15 +1,62 @@
+
+
+ xmlns:dist="http://schemas.android.com/apk/distribution"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.google.android.apps.santatracker.dasherdancer"
+ tools:ignore="MissingLeanbackLauncher">
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
-
+
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
deleted file mode 100644
index d0afaf157..000000000
--- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Character.java
+++ /dev/null
@@ -1,47 +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.apps.santatracker.dasherdancer;
-
-/**
- * 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.
- * Generally implementing classes should use an array to store their durations, frame indices arrays,
- * and frame arrays.
- */
-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;
-
- long getDuration(int animationKey);
-
- int[] getFrameIndices(int animationKey);
-
- int[] getFrames(int animationKey);
-
- // 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.
- String getCharacterName();
-}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Character.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Character.kt
new file mode 100644
index 000000000..e89990cf0
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Character.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 androidx.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. Generally implementing classes should use an array to store their durations, frame
+ * indices arrays, and frame arrays.
+ */
+interface Character {
+
+ // 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.
+ val characterName: String
+
+ fun getDuration(animationKey: Int): Long
+
+ fun getFrameIndices(animationKey: Int): IntArray
+
+ fun getFrames(animationKey: Int): IntArray
+
+ @RawRes
+ fun getSoundResource(animationid: Int): Int
+
+ companion object {
+
+ const val ANIM_IDLE = 0
+ const val ANIM_TAP = 1
+ const val ANIM_SHAKE = 2
+ const val ANIM_SWIPE_DOWN = 3
+ const val ANIM_SWIPE_UP = 4
+ const val ANIM_SWIPE_LEFT = 5
+ const val ANIM_SWIPE_RIGHT = 6
+ const val ANIM_PINCH_IN = 7
+ const val ANIM_PINCH_OUT = 8
+
+ val ALL_ANIMS = intArrayOf(ANIM_IDLE, ANIM_TAP, ANIM_SHAKE, ANIM_SWIPE_DOWN, ANIM_SWIPE_UP, ANIM_SWIPE_LEFT, ANIM_SWIPE_RIGHT, ANIM_PINCH_IN, ANIM_PINCH_OUT)
+ }
+}
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
deleted file mode 100644
index 446cbb886..000000000
--- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterActivity.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.apps.santatracker.dasherdancer;
-
-import com.google.android.apps.santatracker.util.AnalyticsManager;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-
-public class CharacterActivity extends Activity {
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_character);
-
- AnalyticsManager.initializeAnalyticsTracker(this);
- AnalyticsManager.sendScreenView(R.string.analytics_screen_dasher_charselect);
- }
-
- public void onCharacterClick(View view) {
- int characterId = -1;
- if (view.getId() == R.id.btn_character_santa) {
- characterId = DasherDancerActivity.CHARACTER_ID_SANTA;
- } else if (view.getId() == R.id.btn_character_elf) {
- characterId = DasherDancerActivity.CHARACTER_ID_ELF;
- } else if (view.getId() == R.id.btn_character_reindeer) {
- characterId = DasherDancerActivity.CHARACTER_ID_REINDEER;
- } else if (view.getId() == R.id.btn_character_snowman) {
- characterId = DasherDancerActivity.CHARACTER_ID_SNOWMAN;
- }
- Intent result = new Intent();
- result.putExtra(DasherDancerActivity.EXTRA_CHARACTER_ID, characterId);
- setResult(Activity.RESULT_OK, result);
- finish();
- }
-
-}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterActivity.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterActivity.kt
new file mode 100644
index 000000000..3d3dc1416
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterActivity.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import com.google.android.apps.santatracker.util.MeasurementManager
+import com.google.firebase.analytics.FirebaseAnalytics
+
+class CharacterActivity : Activity() {
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_character)
+
+ MeasurementManager.recordScreenView(
+ FirebaseAnalytics.getInstance(this),
+ getString(R.string.analytics_screen_dasher_charselect))
+ }
+
+ fun onCharacterClick(view: View) {
+ var characterId = -1
+ when (view.id) {
+ R.id.btn_character_santa -> characterId = DasherDancerActivity.CHARACTER_ID_SANTA
+ R.id.btn_character_elf -> characterId = DasherDancerActivity.CHARACTER_ID_ELF
+ R.id.btn_character_reindeer -> characterId = DasherDancerActivity.CHARACTER_ID_REINDEER
+ R.id.btn_character_snowman -> characterId = DasherDancerActivity.CHARACTER_ID_SNOWMAN
+ }
+ val result = Intent()
+ result.putExtra(DasherDancerActivity.EXTRA_CHARACTER_ID, characterId)
+ setResult(Activity.RESULT_OK, result)
+ finish()
+ }
+}
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
deleted file mode 100644
index 5be82df09..000000000
--- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterAdapter.java
+++ /dev/null
@@ -1,104 +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.apps.santatracker.dasherdancer;
-
-
-import android.support.v4.view.PagerAdapter;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.ImageView;
-
-import java.lang.*;
-
-public class CharacterAdapter extends PagerAdapter {
-
- private static final String LOG_TAG = CharacterAdapter.class.getSimpleName();
-
- private static final int[] mBackgrounds = new int[]{
- R.color.bg_blue,R.color.bg_pink,R.color.bg_purple,
- R.color.bg_green,R.color.bg_red,R.color.bg_orange,
- R.color.bg_yellow
- };
-
- private SparseArray mViews;
- private Character[] mCharacters;
-
- public CharacterAdapter(Character[] characters) {
- mCharacters = characters;
- mViews = new SparseArray();
- }
-
- @Override
- public void destroyItem(ViewGroup container, int position, Object object) {
- if (position < mCharacters.length) {
- View view = mViews.get(position);
- if ((view == null) && (object != null)) {
- try {
- view = (ImageView)object;
- } catch (ClassCastException e) {
- Log.e(LOG_TAG, "Wrong type of object supplied to destroyItem.");
- }
- }
-
- if (view != null) {
- container.removeView(view);
- }
-
- mViews.remove(position);
- }
- }
-
- @Override
- public int getCount() {
- if(mCharacters != null) {
- return mCharacters.length;
- }
- return 0;
- }
-
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- ImageView view = null;
-
- if (position < mCharacters.length) {
- if (mViews.get(position) != null) {
- view = mViews.get(position);
- } else {
- view = new FrameAnimationView(container.getContext());
- view.setScaleType(ImageView.ScaleType.CENTER_CROP);
- //Load the first idle frame.
- view.setBackgroundResource(mBackgrounds[position]);
- view.setTag(position);
- mViews.put(position, view);
- }
-
- LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
- container.addView(view, lp);
- }
-
- return view;
- }
-
- @Override
- public boolean isViewFromObject(View arg0, Object arg1) {
- return arg0 == arg1;
- }
-
-}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterAdapter.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterAdapter.kt
new file mode 100644
index 000000000..33daa7265
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/CharacterAdapter.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.util.SparseArray
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams
+import android.widget.ImageView
+import androidx.viewpager.widget.PagerAdapter
+import com.google.android.apps.santatracker.util.SantaLog
+
+class CharacterAdapter(private val characters: Array) : PagerAdapter() {
+
+ private val views: SparseArray = SparseArray()
+
+ override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
+ if (position < characters.size) {
+ var view: View? = views.get(position)
+ if (view == null) {
+ try {
+ view = `object` as ImageView
+ } catch (e: ClassCastException) {
+ SantaLog.e(LOG_TAG, "Wrong type of object supplied to destroyItem.")
+ }
+ }
+
+ if (view != null) {
+ container.removeView(view)
+ }
+
+ views.remove(position)
+ }
+ }
+
+ override fun getCount(): Int {
+ return characters.size
+ }
+
+ override fun instantiateItem(container: ViewGroup, position: Int): Any {
+ var view: ImageView? = null
+
+ if (position < characters.size) {
+ if (views.get(position) != null) {
+ view = views.get(position)
+ } else {
+ view = FrameAnimationView(container.context)
+ view.scaleType = ImageView.ScaleType.MATRIX
+ // Load the first idle frame.
+ view.setBackgroundResource(mBackgrounds[position])
+ view.tag = position
+ views.put(position, view)
+ }
+
+ val lp = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
+ container.addView(view, lp)
+ }
+
+ return view!!
+ }
+
+ override fun isViewFromObject(arg0: View, arg1: Any): Boolean {
+ return arg0 === arg1
+ }
+
+ companion object {
+
+ private val LOG_TAG = CharacterAdapter::class.java.simpleName
+
+ private val mBackgrounds = intArrayOf(R.color.bg_blue, R.color.bg_pink, R.color.bg_purple, R.color.bg_green, R.color.bg_red, R.color.bg_orange, R.color.bg_yellow)
+ }
+}
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
deleted file mode 100644
index b64a15d8d..000000000
--- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/DasherDancerActivity.java
+++ /dev/null
@@ -1,904 +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.apps.santatracker.dasherdancer;
-
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.ObjectAnimator;
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-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.v4.app.FragmentActivity;
-import android.support.v4.view.ViewPager.OnPageChangeListener;
-import android.util.LruCache;
-import android.view.GestureDetector.OnGestureListener;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.ScaleGestureDetector.OnScaleGestureListener;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.google.android.apps.santatracker.games.PlayGamesFragment;
-import com.google.android.apps.santatracker.games.SignInListener;
-import com.google.android.apps.santatracker.util.AnalyticsManager;
-import com.google.android.apps.santatracker.util.ImmersiveModeHelper;
-import com.google.android.apps.santatracker.util.MeasurementManager;
-import com.google.android.gms.games.Games;
-import com.google.firebase.analytics.FirebaseAnalytics;
-import com.squareup.seismic.ShakeDetector;
-import com.squareup.seismic.ShakeDetector.Listener;
-
-import java.util.HashSet;
-
-public class DasherDancerActivity extends FragmentActivity implements
- OnGestureListener, OnScaleGestureListener, Handler.Callback, Listener, SensorEventListener,
- AnimatorListener, OnPageChangeListener, SignInListener {
-
- /**
- * Extra key used to pass back the character id that should be selected, set by the CharacterActivity.
- */
- public static final String EXTRA_CHARACTER_ID = "extra_character_id";
-
- //Character ids, which are also indices in the sCharacters array.
- public static final int CHARACTER_ID_SANTA = 0;
- public static final int CHARACTER_ID_ELF = 1;
- public static final int CHARACTER_ID_REINDEER = 2;
- public static final int CHARACTER_ID_SNOWMAN = 3;
-
- /**
- * Request code for calling CharacterActivity for result.
- */
- private static final int sCharacterRequestCode = 1;
-
- /**
- * Our array of playable characters. Add more characters here an create new CHARACTER_ID_* static variables.
- */
- private static final Character[] sCharacters = new Character[]{
- new Santa(), new Elf(), new Reindeer(), new Snowman()
- };
-
- private boolean[] mCharacterInitialized = new boolean[] {
- false, false, false, false
- };
-
- private int[][] mSoundIds = new int[][]{
- {-1,-1,-1,-1,-1,-1,-1,-1,-1}, //santa
- {-1,-1,-1,-1,-1,-1,-1,-1,-1}, //elf
- {-1,-1,-1,-1,-1,-1,-1,-1,-1}, //reindeer
- {-1,-1,-1,-1,-1,-1,-1,-1,-1} //snowman
- };
-
- private LruCache mMemoryCache;
- private NoSwipeViewPager mPager;
- private Handler mHandler;
- private ShakeDetector mDetector;
- private LoadBitmapsTask mLoadBitmapsTask;
- private LoadAllBitmapsTask mLoadAllBitmapsTask;
- private ObjectAnimator mAnimator;
- private boolean mPlayingRest = false;
- private boolean mAnimCanceled = false;
- private boolean mAnimPlaying = false;
- private boolean mScaling = false;
- private boolean mInitialized = false;
- private SoundPool mSoundPool;
- private int mSoundId = -1;
- private boolean mCanTouch = false;
- private ObjectAnimator mProgressAnimator;
- private ActivityManager mActivityManager;
- private FirebaseAnalytics mMeasurement;
-
- private PlayGamesFragment mGamesFragment;
-
- // For achievements
- private HashSet[] mAchievements;
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_dasher_dancer);
-
- mMeasurement = FirebaseAnalytics.getInstance(this);
- MeasurementManager.recordScreenView(mMeasurement,
- getString(R.string.analytics_screen_dasher));
-
- AnalyticsManager.initializeAnalyticsTracker(this);
- AnalyticsManager.sendScreenView(R.string.analytics_screen_dasher);
-
- mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
-
- mMemoryCache = new LruCache(240) {
- protected void entryRemoved(boolean evicted, Integer key, Bitmap oldValue, Bitmap newValue) {
- if ((oldValue != null) && (oldValue != newValue)) {
- oldValue.recycle();
- oldValue = null;
- }
- }
- };
-
- CharacterAdapter adapter = new CharacterAdapter(sCharacters);
- mPager = (NoSwipeViewPager) findViewById(R.id.character_pager);
- mPager.setAdapter(adapter);
- mPager.setGestureDetectorListeners(this, this, this);
- mPager.setOnPageChangeListener(this);
-
- mHandler = new Handler(getMainLooper(), this);
-
- 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();
- mAchievements[1] = new HashSet();
- mAchievements[2] = new HashSet();
- mAchievements[3] = new HashSet();
-
- mProgressAnimator = ObjectAnimator.ofFloat(findViewById(R.id.progress),"rotation",360f);
- mProgressAnimator.setDuration(4000);
- mProgressAnimator.start();
-
- mGamesFragment = PlayGamesFragment.getInstance(this, this);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- ImmersiveModeHelper.setImmersiveSticky(getWindow());
- ImmersiveModeHelper.installSystemUiVisibilityChangeListener(getWindow());
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- SensorManager manager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
- Sensor accel = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- manager.registerListener(this, accel, SensorManager.SENSOR_DELAY_NORMAL);
- mDetector.start(manager);
-
- if(mInitialized) {
- //Start the animation for the first character.
- mPager.postDelayed(new Runnable() {
-
- @Override
- public void run() {
- loadAnimation(true,
- sCharacters[mPager.getCurrentItem()].getDuration(Character.ANIM_IDLE),
- sCharacters[mPager.getCurrentItem()].getFrameIndices(Character.ANIM_IDLE),
- sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_IDLE));
- }
-
- }, 300);
- }
- else {
- if(mLoadAllBitmapsTask != null) {
- mLoadAllBitmapsTask.cancel(true);
- }
- mLoadAllBitmapsTask = new LoadAllBitmapsTask();
- mLoadAllBitmapsTask.execute(sCharacters[mPager.getCurrentItem()]);
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- mDetector.stop();
-
- SensorManager manager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
- manager.unregisterListener(this);;
-
- if(mAnimator != null) {
- mAnimator.cancel();
- }
- FrameAnimationView character = (FrameAnimationView) mPager.findViewWithTag(mPager.getCurrentItem());
- if (character != null) {
- character.setImageDrawable(null);
- }
- }
-
- /**
- * Finishes the activity.
- * @param view
- */
- public void onNavClick(View view) {
- if(mLoadBitmapsTask != null) {
- mLoadBitmapsTask.cancel(true);
- }
- if(mAnimator != null) {
- mAnimator.cancel();
- }
- finish();
- }
-
- /**
- * Starts the CharacterActivity for result. That result is an integer that corresponds to
- * the index of an entry in sCharacters.
- * @param view
- */
- public void onChangeClick(View view) {
- if(mLoadBitmapsTask != null) {
- mLoadBitmapsTask.cancel(true);
- }
- if(mLoadAllBitmapsTask != null) {
- mLoadAllBitmapsTask.cancel(true);
- }
- if(mAnimator != null) {
- mAnimator.cancel();
- }
- FrameAnimationView character = (FrameAnimationView) mPager.findViewWithTag(mPager.getCurrentItem());
- character.setImageDrawable(null);
- character.setFrames(null, null);
- character.invalidate();
- Intent intent = new Intent(this, CharacterActivity.class);
- startActivityForResult(intent, sCharacterRequestCode);
- }
-
- /**
- * Moves the view pager to the next character to the left of the current position.
- */
- public void onLeftClick(View view) {
- final int currentPosition = mPager.getCurrentItem();
- if(currentPosition != 0) {
- characterSelectedHelper(currentPosition - 1, true);
- }
- }
-
- /**
- * Moves the view pager to the next character to the right of the current position.
- */
- public void onRightClick(View view) {
- final int currentPosition = mPager.getCurrentItem();
- if(currentPosition != mPager.getAdapter().getCount()-1) {
- characterSelectedHelper(currentPosition + 1, true);
- }
- }
-
- @Override
- public boolean onDown(MotionEvent e) {
- return true;
- }
-
- @Override
- public void onShowPress(MotionEvent e) {
- //Ignore this.
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- if(!mAnimPlaying) {
- mSoundId = mSoundIds[mPager.getCurrentItem()][Character.ANIM_TAP];
- }
-
- AnalyticsManager.sendEvent(getString(R.string.analytics_category_interaction),
- sCharacters[mPager.getCurrentItem()].getCharacterName(),
- getString(R.string.analytics_action_tap));
-
- updateGestureAchievements(Character.ANIM_TAP);
- loadAnimation(false,
- sCharacters[mPager.getCurrentItem()].getDuration(Character.ANIM_TAP),
- sCharacters[mPager.getCurrentItem()].getFrameIndices(Character.ANIM_TAP),
- sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_TAP));
- return true;
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY) {
- return false;
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- //Ignore
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- float xDelta = Math.abs(e1.getX() - e2.getX());
- float yDelta = Math.abs(e1.getY() - e2.getY());
- if(xDelta > yDelta) {
- //Moving side to side.
- if(e1.getX() > e2.getX()) {
- //Moving left.
- if(!mAnimPlaying) {
- mSoundId = mSoundIds[mPager.getCurrentItem()][Character.ANIM_SWIPE_LEFT];
- }
- AnalyticsManager.sendEvent(getString(R.string.analytics_category_interaction),
- sCharacters[mPager.getCurrentItem()].getCharacterName(),
- getString(R.string.analytics_action_swipe_left));
- updateGestureAchievements(Character.ANIM_SWIPE_LEFT);
- loadAnimation(false,
- sCharacters[mPager.getCurrentItem()].getDuration(Character.ANIM_SWIPE_LEFT),
- sCharacters[mPager.getCurrentItem()].getFrameIndices(Character.ANIM_SWIPE_LEFT),
- sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_SWIPE_LEFT));
- }
- else if(e2.getX() > e1.getX()) {
- //Moving right.
- if(!mAnimPlaying) {
- mSoundId = mSoundIds[mPager.getCurrentItem()][Character.ANIM_SWIPE_RIGHT];
- }
- AnalyticsManager.sendEvent(getString(R.string.analytics_category_interaction),
- sCharacters[mPager.getCurrentItem()].getCharacterName(),
- getString(R.string.analytics_action_swipe_right));
- updateGestureAchievements(Character.ANIM_SWIPE_RIGHT);
- loadAnimation(false,
- sCharacters[mPager.getCurrentItem()].getDuration(Character.ANIM_SWIPE_RIGHT),
- sCharacters[mPager.getCurrentItem()].getFrameIndices(Character.ANIM_SWIPE_RIGHT),
- sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_SWIPE_RIGHT));
- }
- }
- else {
- //We are moving up and down
- if(e1.getY() > e2.getY()) {
- //Moving up.
- if(!mAnimPlaying) {
- mSoundId = mSoundIds[mPager.getCurrentItem()][Character.ANIM_SWIPE_UP];
- }
- AnalyticsManager.sendEvent(getString(R.string.analytics_category_interaction),
- sCharacters[mPager.getCurrentItem()].getCharacterName(),
- getString(R.string.analytics_action_swipe_up));
- updateGestureAchievements(Character.ANIM_SWIPE_UP);
- loadAnimation(false,
- sCharacters[mPager.getCurrentItem()].getDuration(Character.ANIM_SWIPE_UP),
- sCharacters[mPager.getCurrentItem()].getFrameIndices(Character.ANIM_SWIPE_UP),
- sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_SWIPE_UP));
- }
- else if(e2.getY() > e1.getY()) {
- //Moving down.
- if(!mAnimPlaying) {
- mSoundId = mSoundIds[mPager.getCurrentItem()][Character.ANIM_SWIPE_DOWN];
- }
- AnalyticsManager.sendEvent(getString(R.string.analytics_category_interaction),
- sCharacters[mPager.getCurrentItem()].getCharacterName(),
- getString(R.string.analytics_action_swipe_down));
- updateGestureAchievements(Character.ANIM_SWIPE_DOWN);
- loadAnimation(false,
- sCharacters[mPager.getCurrentItem()].getDuration(Character.ANIM_SWIPE_DOWN),
- sCharacters[mPager.getCurrentItem()].getFrameIndices(Character.ANIM_SWIPE_DOWN),
- sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_SWIPE_DOWN));
- }
- }
- return false;
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- loadAnimation(true,
- sCharacters[mPager.getCurrentItem()].getDuration(Character.ANIM_IDLE),
- sCharacters[mPager.getCurrentItem()].getFrameIndices(Character.ANIM_IDLE),
- sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_IDLE));
- return true;
- }
-
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
-
- return false;
- }
-
- @Override
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- mScaling = true;
- return true;
- }
-
- @Override
- public void onScaleEnd(ScaleGestureDetector detector) {
- mScaling = false;
- if(detector.getScaleFactor() > 1) {
- //Pinch in
- if(!mAnimPlaying) {
- mSoundId = mSoundIds[mPager.getCurrentItem()][Character.ANIM_PINCH_IN];
- }
- AnalyticsManager.sendEvent(getString(R.string.analytics_category_interaction),
- sCharacters[mPager.getCurrentItem()].getCharacterName(),
- getString(R.string.analytics_action_pinch_in));
- updateGestureAchievements(Character.ANIM_PINCH_IN);
- loadAnimation(false,
- sCharacters[mPager.getCurrentItem()].getDuration(Character.ANIM_PINCH_IN),
- sCharacters[mPager.getCurrentItem()].getFrameIndices(Character.ANIM_PINCH_IN),
- sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_PINCH_IN));
- }
- else if(detector.getScaleFactor() < 1) {
- //Pinch out
- if(!mAnimPlaying) {
- mSoundId = mSoundIds[mPager.getCurrentItem()][Character.ANIM_PINCH_OUT];
- }
- AnalyticsManager.sendEvent(getString(R.string.analytics_category_interaction),
- sCharacters[mPager.getCurrentItem()].getCharacterName(),
- getString(R.string.analytics_action_pinch_out));
- updateGestureAchievements(Character.ANIM_PINCH_OUT);
- loadAnimation(false,
- sCharacters[mPager.getCurrentItem()].getDuration(Character.ANIM_PINCH_OUT),
- sCharacters[mPager.getCurrentItem()].getFrameIndices(Character.ANIM_PINCH_OUT),
- sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_PINCH_OUT));
- }
- }
-
- @Override
- public void onSensorChanged(SensorEvent event) {
- //Ignore this.
- }
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- //Ignore this.
- }
-
- @Override
- public void hearShake() {
- if(!mAnimPlaying) {
- mSoundId = mSoundIds[mPager.getCurrentItem()][Character.ANIM_SHAKE];
- }
- AnalyticsManager.sendEvent(getString(R.string.analytics_category_interaction),
- sCharacters[mPager.getCurrentItem()].getCharacterName(),
- getString(R.string.analytics_action_shake));
- updateGestureAchievements(Character.ANIM_SHAKE);
- loadAnimation(false,
- sCharacters[mPager.getCurrentItem()].getDuration(Character.ANIM_SHAKE),
- sCharacters[mPager.getCurrentItem()].getFrameIndices(Character.ANIM_SHAKE),
- sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_SHAKE));
- }
-
- /**
- * Helper method to load and start animations. Takes care of canceling any ongoing animations,
- * and will return without executing anything if mAnimPlaying is true or mScaling is true.
- * @param playingRest
- * @param animationTime
- * @param frameIndices
- * @param frameResourceIds
- */
- private void loadAnimation(boolean playingRest, long animationTime, int[] frameIndices, int[] frameResourceIds) {
- if((!playingRest && (mAnimPlaying || mScaling)) || !mCanTouch) {
- return;
- }
- if(playingRest) {
- mAnimPlaying = false;
- }
- else {
- mAnimPlaying = true;
- }
- mPlayingRest = playingRest;
- if(mLoadBitmapsTask != null) {
- mLoadBitmapsTask.cancel(true);
- mAnimator.cancel();
- }
- LoadBitmapsTask task = new LoadBitmapsTask(animationTime, frameIndices, frameResourceIds);
- task.execute();
- }
-
- @Override
- public void onSignInFailed() {
-
- }
-
- @Override
- public void onSignInSucceeded() {
-
- }
-
- private class LoadAllBitmapsTask extends AsyncTask {
-
- final BitmapFactory.Options mOptions = new BitmapFactory.Options();
-
- @Override
- protected Void doInBackground(Character... 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;
- }
- }
-
- 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()) {
- break;
- }
- loadBitmapHelper(resourceId);
- }
-
- return null;
- }
-
- 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);
- }
- }
- }
- }
- }
-
- @Override
- public void onPostExecute(Void result) {
- if(isCancelled()) {
- return;
- }
-
- findViewById(R.id.progress).setVisibility(View.GONE);
-
- Bitmap[] frames = new Bitmap[sCharacters[mPager.getCurrentItem()].getFrames(Character.ANIM_IDLE).length];
- for(int i=0; i {
-
- private int[] mFrames;
- private int[] mFrameIndices;
- private long mDuration;
-
- public LoadBitmapsTask(long duration, int[] frameIndices, int[] frames) {
- mFrameIndices = frameIndices;
- mDuration = duration;
- 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;
- }
- }
-
- for(int i=0; i
+ private lateinit var pager: NoSwipeViewPager
+ private lateinit var handler: Handler
+ private var loadBitmapsTask: LoadBitmapsTask? = null
+ private var loadCharacterTask: LoadCharacterResourcesTask? = null
+ private var animator: ObjectAnimator? = null
+ private var playingRest = false
+ private var animCanceled = false
+ private var animPlaying = false
+ private var scaling = false
+ private var initialized = false
+ private var soundId = -1
+ private var canTouch = false
+
+ private lateinit var muteButton: CheckableImageButton
+ private lateinit var santaPreferences: SantaPreferences
+
+ // Bitmap downsampling options
+ private lateinit var options: BitmapFactory.Options
+ private var downSamplingAttempts: Int = 0
+
+ private var gamesFragment: PlayGamesFragment? = null
+
+ // For achievements
+ private lateinit var achievements: Array>
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(R.layout.activity_dasher_dancer)
+
+ santaPreferences = SantaPreferences(this)
+
+ muteButton = findViewById(R.id.mute_button)
+ muteButton.isChecked = !santaPreferences.isMuted
+ muteButton.setOnClickListener {
+ // Toggle the state
+ santaPreferences.toggleMuted()
+ // Now update the vie
+ muteButton.isChecked = !santaPreferences.isMuted
+ onMuteChanged(santaPreferences.isMuted)
+ }
+
+ firebaseAnalytics = FirebaseAnalytics.getInstance(this)
+ MeasurementManager.recordScreenView(
+ firebaseAnalytics, getString(R.string.analytics_screen_dasher))
+
+ activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
+
+ memoryCache = object : LruCache(240) {
+ override fun entryRemoved(
+ evicted: Boolean,
+ key: Int?,
+ oldValue: Drawable?,
+ newValue: Drawable?
+ ) {
+ if (oldValue != null && oldValue !== newValue) {
+ if (oldValue is InsetDrawableCompat) {
+ val drawable = oldValue.drawable
+ if (drawable is BitmapDrawable) {
+ drawable.bitmap.recycle()
+ }
+ }
+ }
+ }
+ }
+
+ // Initialize default Bitmap options
+ options = BitmapFactory.Options().apply {
+ inPreferredConfig = Bitmap.Config.RGB_565
+ inSampleSize = resources.getInteger(R.integer.res)
+ if (activityManager.isLowRamDevice) {
+ SantaLog.w(TAG, "isLowRamDevice: downsampling default bitmap options")
+ inSampleSize *= 2
+ }
+ }
+
+ val adapter = CharacterAdapter(characters)
+ pager = findViewById(R.id.character_pager) as NoSwipeViewPager
+ pager.let {
+ it.adapter = adapter
+ it.setGestureDetectorListeners(this, this, this)
+ it.setOnPageChangeListener(this)
+ }
+
+ handler = Handler(mainLooper, this)
+ detector = ShakeDetector(this)
+ soundPool = SoundPool(4, AudioManager.STREAM_MUSIC, 0)
+ achievements = arrayOf(HashSet(), HashSet(), HashSet(), HashSet())
+ progressAnimator =
+ ObjectAnimator.ofFloat(findViewById(R.id.progress), "rotation", 360f).apply {
+ duration = 4000
+ start()
+ }
+ gamesFragment = PlayGamesFragment.getInstance(this, this)
+ ImmersiveModeHelper.setImmersiveSticky(window)
+ ImmersiveModeHelper.installSystemUiVisibilityChangeListener(window)
+ }
+
+ public override fun onResume() {
+ super.onResume()
+ val manager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
+ val accel = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
+ manager.registerListener(this, accel, SensorManager.SENSOR_DELAY_NORMAL)
+ detector.start(manager)
+
+ if (initialized) {
+ // Start the animation for the first character.
+ pager.postDelayed(300) {
+ loadAnimation(true,
+ characters[pager.currentItem].getDuration(Character.ANIM_IDLE),
+ characters[pager.currentItem].getFrameIndices(Character.ANIM_IDLE),
+ characters[pager.currentItem].getFrames(Character.ANIM_IDLE))
+ }
+ } else {
+ loadCharacterTask?.cancel(true)
+ loadCharacterTask = LoadCharacterResourcesTask(pager.currentItem)
+ loadCharacterTask?.execute()
+ }
+ }
+
+ public override fun onPause() {
+ super.onPause()
+
+ detector.stop()
+
+ val manager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
+ manager.unregisterListener(this)
+
+ animator?.cancel()
+ val character = pager.findViewWithTag(pager.currentItem)
+ character?.setImageDrawable(null)
+ }
+
+ /**
+ * Finishes the activity.
+ *
+ * @param view
+ */
+ fun onNavClick(view: View) {
+ loadBitmapsTask?.cancel(true)
+ animator?.cancel()
+ finish()
+ }
+
+ /**
+ * Starts the CharacterActivity for result. That result is an integer that corresponds to the
+ * index of an entry in characters.
+ *
+ * @param view
+ */
+ fun onChangeClick(view: View) {
+ loadBitmapsTask?.cancel(true)
+ loadCharacterTask?.cancel(true)
+ animator?.cancel()
+ val character = pager.findViewWithTag(pager.currentItem)
+ character.setImageDrawable(null)
+ character.setFrames(null, null)
+ character.invalidate()
+ val intent = Intent(this, CharacterActivity::class.java)
+ startActivityForResult(intent, sCharacterRequestCode)
+ }
+
+ /** Moves the view pager to the next character to the left of the current position. */
+ fun onLeftClick(view: View) {
+ val currentPosition = pager.currentItem
+ if (currentPosition != 0) {
+ characterSelectedHelper(currentPosition - 1, true)
+ }
+ }
+
+ /** Moves the view pager to the next character to the right of the current position. */
+ fun onRightClick(view: View) {
+ val currentPosition = pager.currentItem
+ if (currentPosition != pager.adapter!!.count - 1) {
+ characterSelectedHelper(currentPosition + 1, true)
+ }
+ }
+
+ override fun onDown(e: MotionEvent): Boolean {
+ return true
+ }
+
+ override fun onShowPress(e: MotionEvent) {
+ // Ignore this.
+ }
+
+ override fun onSingleTapUp(e: MotionEvent): Boolean {
+ if (!animPlaying) {
+ soundId = soundIds[pager.currentItem][Character.ANIM_TAP]
+ }
+
+ MeasurementManager.recordCustomEvent(
+ firebaseAnalytics,
+ getString(R.string.analytics_category_interaction),
+ characters[pager.currentItem].characterName,
+ getString(R.string.analytics_action_tap))
+
+ updateGestureAchievements(Character.ANIM_TAP)
+ loadAnimation(
+ false,
+ characters[pager.currentItem].getDuration(Character.ANIM_TAP),
+ characters[pager.currentItem].getFrameIndices(Character.ANIM_TAP),
+ characters[pager.currentItem].getFrames(Character.ANIM_TAP))
+ return true
+ }
+
+ override fun onScroll(
+ e1: MotionEvent,
+ e2: MotionEvent,
+ distanceX: Float,
+ distanceY: Float
+ ): Boolean {
+ return false
+ }
+
+ override fun onLongPress(e: MotionEvent) {
+ // Ignore
+ }
+
+ override fun onFling(
+ e1: MotionEvent,
+ e2: MotionEvent,
+ velocityX: Float,
+ velocityY: Float
+ ): Boolean {
+ val xDelta = Math.abs(e1.x - e2.x)
+ val yDelta = Math.abs(e1.y - e2.y)
+ if (xDelta > yDelta) {
+ // Moving side to side.
+ if (e1.x > e2.x) {
+ // Moving left.
+ if (!animPlaying) {
+ soundId = soundIds[pager.currentItem][Character.ANIM_SWIPE_LEFT]
+ }
+ MeasurementManager.recordCustomEvent(
+ firebaseAnalytics,
+ getString(R.string.analytics_category_interaction),
+ characters[pager.currentItem].characterName,
+ getString(R.string.analytics_action_swipe_left))
+ updateGestureAchievements(Character.ANIM_SWIPE_LEFT)
+ loadAnimation(
+ false,
+ characters[pager.currentItem].getDuration(Character.ANIM_SWIPE_LEFT),
+ characters[pager.currentItem].getFrameIndices(
+ Character.ANIM_SWIPE_LEFT),
+ characters[pager.currentItem].getFrames(Character.ANIM_SWIPE_LEFT))
+ } else if (e2.x > e1.x) {
+ // Moving right.
+ if (!animPlaying) {
+ soundId = soundIds[pager.currentItem][Character.ANIM_SWIPE_RIGHT]
+ }
+ MeasurementManager.recordCustomEvent(
+ firebaseAnalytics,
+ getString(R.string.analytics_category_interaction),
+ characters[pager.currentItem].characterName,
+ getString(R.string.analytics_action_swipe_right))
+ updateGestureAchievements(Character.ANIM_SWIPE_RIGHT)
+ loadAnimation(
+ false,
+ characters[pager.currentItem].getDuration(
+ Character.ANIM_SWIPE_RIGHT),
+ characters[pager.currentItem].getFrameIndices(
+ Character.ANIM_SWIPE_RIGHT),
+ characters[pager.currentItem].getFrames(Character.ANIM_SWIPE_RIGHT))
+ }
+ } else {
+ // We are moving up and down
+ if (e1.y > e2.y) {
+ // Moving up.
+ if (!animPlaying) {
+ soundId = soundIds[pager.currentItem][Character.ANIM_SWIPE_UP]
+ }
+ MeasurementManager.recordCustomEvent(
+ firebaseAnalytics,
+ getString(R.string.analytics_category_interaction),
+ characters[pager.currentItem].characterName,
+ getString(R.string.analytics_action_swipe_up))
+ updateGestureAchievements(Character.ANIM_SWIPE_UP)
+ loadAnimation(
+ false,
+ characters[pager.currentItem].getDuration(Character.ANIM_SWIPE_UP),
+ characters[pager.currentItem].getFrameIndices(
+ Character.ANIM_SWIPE_UP),
+ characters[pager.currentItem].getFrames(Character.ANIM_SWIPE_UP))
+ } else if (e2.y > e1.y) {
+ // Moving down.
+ if (!animPlaying) {
+ soundId = soundIds[pager.currentItem][Character.ANIM_SWIPE_DOWN]
+ }
+ MeasurementManager.recordCustomEvent(
+ firebaseAnalytics,
+ getString(R.string.analytics_category_interaction),
+ characters[pager.currentItem].characterName,
+ getString(R.string.analytics_action_swipe_down))
+ updateGestureAchievements(Character.ANIM_SWIPE_DOWN)
+ loadAnimation(
+ false,
+ characters[pager.currentItem].getDuration(Character.ANIM_SWIPE_DOWN),
+ characters[pager.currentItem].getFrameIndices(
+ Character.ANIM_SWIPE_DOWN),
+ characters[pager.currentItem].getFrames(Character.ANIM_SWIPE_DOWN))
+ }
+ }
+ return false
+ }
+
+ override fun handleMessage(msg: Message): Boolean {
+ loadAnimation(
+ true,
+ characters[pager.currentItem].getDuration(Character.ANIM_IDLE),
+ characters[pager.currentItem].getFrameIndices(Character.ANIM_IDLE),
+ characters[pager.currentItem].getFrames(Character.ANIM_IDLE))
+ return true
+ }
+
+ override fun onScale(detector: ScaleGestureDetector): Boolean {
+
+ return false
+ }
+
+ override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
+ scaling = true
+ return true
+ }
+
+ override fun onScaleEnd(detector: ScaleGestureDetector) {
+ scaling = false
+ if (detector.scaleFactor > 1) {
+ // Pinch in
+ if (!animPlaying) {
+ soundId = soundIds[pager.currentItem][Character.ANIM_PINCH_IN]
+ }
+ MeasurementManager.recordCustomEvent(
+ firebaseAnalytics,
+ getString(R.string.analytics_category_interaction),
+ characters[pager.currentItem].characterName,
+ getString(R.string.analytics_action_pinch_in))
+ updateGestureAchievements(Character.ANIM_PINCH_IN)
+ loadAnimation(
+ false,
+ characters[pager.currentItem].getDuration(Character.ANIM_PINCH_IN),
+ characters[pager.currentItem].getFrameIndices(Character.ANIM_PINCH_IN),
+ characters[pager.currentItem].getFrames(Character.ANIM_PINCH_IN))
+ } else if (detector.scaleFactor < 1) {
+ // Pinch out
+ if (!animPlaying) {
+ soundId = soundIds[pager.currentItem][Character.ANIM_PINCH_OUT]
+ }
+ MeasurementManager.recordCustomEvent(
+ firebaseAnalytics,
+ getString(R.string.analytics_category_interaction),
+ characters[pager.currentItem].characterName,
+ getString(R.string.analytics_action_pinch_out))
+ updateGestureAchievements(Character.ANIM_PINCH_OUT)
+ loadAnimation(
+ false,
+ characters[pager.currentItem].getDuration(Character.ANIM_PINCH_OUT),
+ characters[pager.currentItem].getFrameIndices(Character.ANIM_PINCH_OUT),
+ characters[pager.currentItem].getFrames(Character.ANIM_PINCH_OUT))
+ }
+ }
+
+ override fun onSensorChanged(event: SensorEvent) {
+ // Ignore this.
+ }
+
+ override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
+ // Ignore this.
+ }
+
+ override fun hearShake() {
+ if (!animPlaying) {
+ soundId = soundIds[pager.currentItem][Character.ANIM_SHAKE]
+ }
+ MeasurementManager.recordCustomEvent(
+ firebaseAnalytics,
+ getString(R.string.analytics_category_interaction),
+ characters[pager.currentItem].characterName,
+ getString(R.string.analytics_action_shake))
+ updateGestureAchievements(Character.ANIM_SHAKE)
+ loadAnimation(
+ false,
+ characters[pager.currentItem].getDuration(Character.ANIM_SHAKE),
+ characters[pager.currentItem].getFrameIndices(Character.ANIM_SHAKE),
+ characters[pager.currentItem].getFrames(Character.ANIM_SHAKE))
+ }
+
+ private fun onMuteChanged(isMuted: Boolean) {
+ if (isMuted) {
+ soundPool.autoPause()
+ } else {
+ soundPool.autoResume()
+ }
+ }
+
+ /**
+ * Helper method to load and start animations. Takes care of canceling any ongoing animations,
+ * and will return without executing anything if animPlaying is true or scaling is true.
+ *
+ * @param playingRest
+ * @param animationTime
+ * @param frameIndices
+ * @param frameResourceIds
+ */
+ private fun loadAnimation(
+ playingRest: Boolean,
+ animationTime: Long,
+ frameIndices: IntArray,
+ frameResourceIds: IntArray
+ ) {
+ if (!playingRest && (animPlaying || scaling) || !canTouch) {
+ return
+ }
+ animPlaying = !playingRest
+ this.playingRest = playingRest
+ if (loadBitmapsTask != null) {
+ loadBitmapsTask?.cancel(true)
+ animator?.cancel()
+ }
+
+ loadBitmapsTask = LoadBitmapsTask(animationTime, frameIndices, frameResourceIds)
+ loadBitmapsTask?.execute()
+ }
+
+ /**
+ * Load and cache all sounds for a given character.
+ *
+ * @param characterIndex index of the character in the array, like [.CHARACTER_ID_SANTA].
+ */
+ private fun loadSoundsForCharacter(characterIndex: Int) {
+ for (animationId in Character.ALL_ANIMS) {
+ // No need to load sounds twice
+ if (soundIds[characterIndex][animationId] != -1) {
+ continue
+ }
+
+ val soundResource = characters[characterIndex].getSoundResource(animationId)
+ if (soundResource != -1) {
+ soundIds[characterIndex][animationId] = soundPool.load(this, soundResource, 1)
+ }
+ }
+ }
+
+ override fun onSignInFailed() {}
+
+ override fun onSignInSucceeded() {}
+
+ @Throws(DasherDancerActivity.BitmapLoadException::class)
+ private fun tryLoadBitmap(@DrawableRes resourceId: Int): Drawable {
+ try {
+ BitmapFactory.decodeResource(resources, resourceId, options)?.let { bmp ->
+ val bitmapDrawable = BitmapDrawable(resources, bmp)
+ val p = ResourceOffsets.getOffsets(resourceId)
+ val x = Math.round(p.x / options.inSampleSize.toFloat())
+ val y = Math.round(p.y / options.inSampleSize.toFloat())
+ val w = Math.round(ResourceOffsets.ORIG_SIZE.x / options.inSampleSize.toFloat())
+ val h = Math.round(ResourceOffsets.ORIG_SIZE.y / options.inSampleSize.toFloat())
+ return InsetDrawableCompat(
+ bitmapDrawable, x, y, w - bmp.width - x, h - bmp.height - y)
+ }
+ } catch (oom: OutOfMemoryError) {
+ SantaLog.w(TAG, "Out of memory error, inSampleSize=" + options.inSampleSize)
+ if (downSamplingAttempts < MAX_DOWNSAMPLING_ATTEMPTS) {
+ options.inSampleSize *= 2
+ downSamplingAttempts++
+ }
+ }
+
+ throw 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 inner class LoadCharacterResourcesTask internal constructor(
+ private val characterIndex: Int
+ ) : RetryableAsyncTask() {
+
+ private val character: Character = characters[characterIndex]
+
+ override fun doInBackground(vararg params: Void?): Void? {
+ canTouch = false
+ // See if we can free up any memory before we allocate some ourselves.
+ // Request garbage collection.
+ System.gc()
+
+ // Load all sounds for this character
+ loadSoundsForCharacter(characterIndex)
+
+ // Load all animations types for this character
+ for (animation in Character.ALL_ANIMS) {
+ for (resourceId in character.getFrames(animation)) {
+ if (isCancelled) {
+ break
+ }
+
+ if (memoryCache.get(resourceId) == null) {
+ try {
+ val bitmap = tryLoadBitmap(resourceId)
+ memoryCache.put(resourceId, bitmap)
+ } catch (e: BitmapLoadException) {
+ SantaLog.e(TAG, "LoadCharacterResourcesTask: failed", e)
+
+ // Retry the task
+ return retrySelf(params as Array)
+ }
+
+ 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(memoryCache) {
+ if (memoryCache.get(resourceId) != null) {
+ memoryCache.remove(resourceId)
+ }
+ }
+ }
+ }
+ }
+ }
+ return null
+ }
+
+ override fun onPostExecute(result: Void?) {
+ if (isCancelled) {
+ return
+ }
+
+ findViewById(R.id.progress).visibility = View.GONE
+
+ val currentCharacter = characters[pager.currentItem]
+ val frames =
+ arrayOfNulls(currentCharacter.getFrames(Character.ANIM_IDLE).size)
+ for (i in frames.indices) {
+ frames[i] = memoryCache.get(currentCharacter.getFrames(Character.ANIM_IDLE)[i])
+ }
+
+ val characterView = pager.findViewWithTag(pager.currentItem)
+ characterView.setFrames(frames, currentCharacter.getFrameIndices(Character.ANIM_IDLE))
+
+ playingRest = true
+ animator = ObjectAnimator.ofInt(
+ characterView,
+ "frameIndex",
+ 0,
+ currentCharacter.getFrameIndices(Character.ANIM_IDLE).size - 1)
+ animator?.let {
+ it.duration = currentCharacter.getDuration(Character.ANIM_IDLE)
+ it.addListener(this@DasherDancerActivity)
+ it.start()
+ }
+ initialized = true
+ canTouch = true
+ }
+
+ public override fun shouldRetry(): Boolean {
+ return downSamplingAttempts < MAX_DOWNSAMPLING_ATTEMPTS
+ }
+
+ public override fun onPrepareForRetry() {
+ // Clear all frames for this character
+ for (animation in Character.ALL_ANIMS) {
+ for (resourceId in character.getFrames(animation)) {
+ memoryCache.remove(resourceId)
+ }
+ }
+
+ // Try to retry
+ System.gc()
+ }
+ }
+
+ /** AsyncTask that loads bitmaps for animation and starts the animation upon completion. */
+ private inner class LoadBitmapsTask(
+ private val mDuration: Long,
+ private val mFrameIndices: IntArray,
+ private val mFrames: IntArray
+ ) : RetryableAsyncTask>() {
+
+ override fun doInBackground(vararg params: Void?): Array? {
+ val bitmaps = arrayOfNulls(mFrames.size)
+ for (i in mFrames.indices) {
+ if (isCancelled) {
+ break
+ }
+
+ val id = mFrames[i]
+ if (memoryCache.get(id) == null) {
+ try {
+ bitmaps[i] = tryLoadBitmap(id)
+ } catch (e: BitmapLoadException) {
+ SantaLog.e(TAG, "LoadBitmapsTask: failed", e)
+ return retrySelf(params as Array)
+ }
+
+ memoryCache.put(id, bitmaps[i])
+ if (isCancelled) {
+ synchronized(memoryCache) {
+ if (memoryCache.get(id) != null) {
+ memoryCache.remove(id)
+ }
+ }
+ }
+ } else {
+ bitmaps[i] = memoryCache.get(mFrames[i])
+ }
+ }
+ return bitmaps
+ }
+
+ override fun onPostExecute(result: Array?) {
+ if (result == null || isCancelled) {
+ return
+ }
+
+ val character = pager.findViewWithTag(pager.currentItem)
+ character.setFrames(result, mFrameIndices)
+ animator?.cancel()
+ animator = ObjectAnimator.ofInt(character, "frameIndex", 0, mFrameIndices.size - 1)
+ animator?.let {
+ it.duration = mDuration
+ it.addListener(this@DasherDancerActivity)
+ it.start()
+ }
+ if (soundId != -1 && !santaPreferences.isMuted) {
+ soundPool.play(soundId)
+ soundId = -1
+ }
+ }
+
+ public override fun shouldRetry(): Boolean {
+ return downSamplingAttempts < MAX_DOWNSAMPLING_ATTEMPTS
+ }
+
+ public override fun onPrepareForRetry() {
+ // Remove all frames this task should load
+ for (id in mFrames) {
+ memoryCache.remove(id)
+ }
+
+ // See if we can now GC
+ System.gc()
+ }
+ }
+
+ override fun onAnimationStart(animation: Animator) {
+ animCanceled = false
+ if (!playingRest) {
+ animPlaying = true
+ }
+ }
+
+ override fun onAnimationEnd(animation: Animator) {
+ if (animCanceled) {
+ return
+ }
+ animPlaying = false // yoda
+ if (playingRest) {
+ // We are at rest, so play the idle animation again.
+ val character = pager.findViewWithTag(pager.currentItem) as FrameAnimationView
+ animator = ObjectAnimator.ofInt(
+ character,
+ "frameIndex",
+ 0,
+ characters[0].getFrameIndices(Character.ANIM_IDLE).size)
+ animator?.let {
+ it.duration = characters[0].getDuration(Character.ANIM_IDLE)
+ it.addListener(this@DasherDancerActivity)
+ it.start()
+ }
+ } else {
+ // We finished an animation triggered by a gesture, so start the idle animation again.
+ handler.sendEmptyMessage(1)
+ }
+ }
+
+ override fun onAnimationCancel(animation: Animator) {
+ animCanceled = true
+ animPlaying = false
+ }
+
+ override fun onAnimationRepeat(animation: Animator) {
+ // Ignore
+ }
+
+ override fun onPageScrollStateChanged(arg0: Int) {
+ // Ignore
+ }
+
+ override fun onPageScrolled(arg0: Int, arg1: Float, arg2: Int) {
+ // Ignore
+ }
+
+ override fun onPageSelected(arg0: Int) {}
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (requestCode == sCharacterRequestCode) {
+ if (resultCode == Activity.RESULT_OK) {
+ initialized = false
+ val character = pager.findViewWithTag(pager.currentItem) as FrameAnimationView
+ character.setImageDrawable(null)
+ data?.extras?.let {
+ val position = it.getInt(EXTRA_CHARACTER_ID)
+ characterSelectedHelper(position, false)
+ }
+ }
+ }
+ }
+
+ override fun onBackPressed() {
+ // If we are backing out of the game, clear the cache to free memory.
+ soundPool.release()
+ memoryCache.evictAll()
+ // Request garbage collection.
+ System.gc()
+ super.onBackPressed()
+ }
+
+ public override fun onDestroy() {
+ soundPool.release()
+ memoryCache.evictAll()
+ // Request garbage collection.
+ System.gc()
+ super.onDestroy()
+ }
+
+ private fun characterSelectedHelper(position: Int, smoothScroll: Boolean) {
+ loadBitmapsTask?.cancel(true)
+ loadCharacterTask?.cancel(true)
+ animator?.cancel()
+
+ when {
+ position == 0 -> {
+ findViewById(R.id.left_button).visibility = View.GONE
+ findViewById(R.id.right_button).visibility = View.VISIBLE
+ }
+ position + 1 == pager.adapter!!.count -> {
+ findViewById(R.id.right_button).visibility = View.GONE
+ findViewById(R.id.left_button).visibility = View.VISIBLE
+ }
+ else -> {
+ findViewById(R.id.left_button).visibility = View.VISIBLE
+ findViewById(R.id.right_button).visibility = View.VISIBLE
+ }
+ }
+
+ MeasurementManager.recordCustomEvent(
+ firebaseAnalytics,
+ getString(R.string.analytics_category_character),
+ getString(R.string.analytics_action_character_change),
+ characters[position].characterName)
+
+ pager.postDelayed(100) {
+ // Show progress
+ pager.setCurrentItem(position, smoothScroll)
+ findViewById(R.id.progress).visibility = View.VISIBLE
+ progressAnimator.start()
+ (pager.findViewWithTag(pager.currentItem) as ImageView)
+ .setImageDrawable(null)
+ memoryCache.evictAll()
+ // Request garbage collection.
+ System.gc()
+ loadCharacterTask?.cancel(true)
+
+ loadCharacterTask = LoadCharacterResourcesTask(position)
+ loadCharacterTask?.execute()
+ }
+ }
+
+ private fun updateGestureAchievements(type: Int) {
+ val character = pager.currentItem
+ achievements[character].add(type)
+ if (achievements[character].size == 8) {
+ if (gamesFragment!!.isSignedIn) {
+ when (character) {
+ CHARACTER_ID_SANTA -> {
+ Games.Achievements.unlock(
+ gamesFragment!!.gamesApiClient,
+ getString(R.string.achievement_santas_dance_party))
+ MeasurementManager.recordAchievement(
+ firebaseAnalytics,
+ getString(R.string.achievement_santas_dance_party),
+ getString(R.string.analytics_screen_dasher))
+ }
+ CHARACTER_ID_ELF -> {
+ Games.Achievements.unlock(
+ gamesFragment!!.gamesApiClient,
+ getString(R.string.achievement_elfs_dance_party))
+ MeasurementManager.recordAchievement(
+ firebaseAnalytics,
+ getString(R.string.achievement_elfs_dance_party),
+ getString(R.string.analytics_screen_dasher))
+ }
+ CHARACTER_ID_REINDEER -> {
+ Games.Achievements.unlock(
+ gamesFragment!!.gamesApiClient,
+ getString(R.string.achievement_rudolphs_dance_party))
+ MeasurementManager.recordAchievement(
+ firebaseAnalytics,
+ getString(R.string.achievement_rudolphs_dance_party),
+ getString(R.string.analytics_screen_dasher))
+ }
+ CHARACTER_ID_SNOWMAN -> {
+ Games.Achievements.unlock(
+ gamesFragment!!.gamesApiClient,
+ getString(R.string.achievement_snowmans_dance_party))
+ MeasurementManager.recordAchievement(
+ firebaseAnalytics,
+ getString(R.string.achievement_snowmans_dance_party),
+ getString(R.string.analytics_screen_dasher))
+ }
+ }
+ }
+ }
+ }
+
+ /** Convenience class for exception when loading Bitmaps. */
+ private class BitmapLoadException(msg: String) : Exception(msg)
+
+ companion object {
+
+ private const val TAG = "DasherDancer"
+
+ /**
+ * Extra key used to pass back the character id that should be selected, set by the
+ * CharacterActivity.
+ */
+ const val EXTRA_CHARACTER_ID = "extra_character_id"
+
+ // Character ids, which are also indices in the characters array.
+ const val CHARACTER_ID_SANTA = 0
+ const val CHARACTER_ID_ELF = 1
+ const val CHARACTER_ID_REINDEER = 2
+ const val CHARACTER_ID_SNOWMAN = 3
+
+ /** Number of times to try downsampling before giving up */
+ const val MAX_DOWNSAMPLING_ATTEMPTS = 3
+
+ /** Request code for calling CharacterActivity for result. */
+ private const val sCharacterRequestCode = 1
+
+ /**
+ * Our array of playable characters. Add more characters here an create new CHARACTER_ID_*
+ * static variables.
+ */
+ private val characters = arrayOf(Santa(), Elf(), Reindeer(), Snowman())
+ }
+}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Elf.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Elf.java
deleted file mode 100644
index 88f424b35..000000000
--- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Elf.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.apps.santatracker.dasherdancer;
-
-import java.lang.*;
-
-public class Elf implements Character {
-
- private static final long[] sDurations = new long[]{
- 1000, 1000, 1000, 1000, 1000,
- 1000, 1000, 1000, 1333
- };
-
- private static final int[][] sFrames = new int[][]{
- {
- R.drawable.elf_idle0001, R.drawable.elf_idle0002, R.drawable.elf_idle0003, R.drawable.elf_idle0004,
- R.drawable.elf_idle0005, R.drawable.elf_idle0006, R.drawable.elf_idle0007, R.drawable.elf_idle0008,
- R.drawable.elf_idle0009, R.drawable.elf_idle0010, R.drawable.elf_idle0011, R.drawable.elf_idle0012,
- R.drawable.elf_idle0013, R.drawable.elf_idle0014, R.drawable.elf_idle0015, R.drawable.elf_idle0016,
- R.drawable.elf_idle0017, R.drawable.elf_idle0018, R.drawable.elf_idle0019, R.drawable.elf_idle0020,
- R.drawable.elf_idle0021, R.drawable.elf_idle0022, R.drawable.elf_idle0023, R.drawable.elf_idle0024}, //idle
- {R.drawable.elf_tap0001, R.drawable.elf_tap0002, R.drawable.elf_tap0003, R.drawable.elf_tap0004,
- R.drawable.elf_tap0005, R.drawable.elf_tap0006, R.drawable.elf_tap0007, R.drawable.elf_tap0008,
- R.drawable.elf_tap0009, R.drawable.elf_tap0010, R.drawable.elf_tap0011, R.drawable.elf_tap0012,
- R.drawable.elf_tap0013, R.drawable.elf_tap0014, R.drawable.elf_tap0015, R.drawable.elf_tap0016,
- R.drawable.elf_tap0017, R.drawable.elf_tap0018, R.drawable.elf_tap0019, R.drawable.elf_tap0020,
- R.drawable.elf_tap0021, R.drawable.elf_tap0022, R.drawable.elf_tap0023, R.drawable.elf_tap0024},//tap
- {R.drawable.elf_shake0001, R.drawable.elf_shake0002, R.drawable.elf_shake0003, R.drawable.elf_shake0004,
- R.drawable.elf_shake0005, R.drawable.elf_shake0006, R.drawable.elf_shake0007, R.drawable.elf_shake0008,
- R.drawable.elf_shake0009, R.drawable.elf_shake0010, R.drawable.elf_shake0011, R.drawable.elf_shake0012,
- R.drawable.elf_shake0013, R.drawable.elf_shake0014, R.drawable.elf_shake0015, R.drawable.elf_shake0016,
- R.drawable.elf_shake0017, R.drawable.elf_shake0018, R.drawable.elf_shake0019, R.drawable.elf_shake0020,
- R.drawable.elf_shake0021, R.drawable.elf_shake0022, R.drawable.elf_shake0023, R.drawable.elf_shake0024},//shake
- {R.drawable.elf_swipedown0001,
- R.drawable.elf_swipedown0002,
- R.drawable.elf_swipedown0003,
- R.drawable.elf_swipedown0004,
- R.drawable.elf_swipedown0005,
- R.drawable.elf_swipedown0006,
- R.drawable.elf_swipedown0007,
- R.drawable.elf_swipedown0008,
- R.drawable.elf_swipedown0009,
- R.drawable.elf_swipedown0010,
- R.drawable.elf_swipedown0011,
- R.drawable.elf_swipedown0012,
- R.drawable.elf_swipedown0013,
- R.drawable.elf_swipedown0014,
- R.drawable.elf_swipedown0015,
- R.drawable.elf_swipedown0016,
- R.drawable.elf_swipedown0017,
- R.drawable.elf_swipedown0018,
- R.drawable.elf_swipedown0019,
- R.drawable.elf_swipedown0020,
- R.drawable.elf_swipedown0021,
- R.drawable.elf_swipedown0022,
- R.drawable.elf_swipedown0023,
- R.drawable.elf_swipedown0024},//swipe down
- {R.drawable.elf_swipeup0002,
- R.drawable.elf_swipeup0003,
- R.drawable.elf_swipeup0004,
- R.drawable.elf_swipeup0005,
- R.drawable.elf_swipeup0006,
- R.drawable.elf_swipeup0007,
- R.drawable.elf_swipeup0008,
- R.drawable.elf_swipeup0009,
- R.drawable.elf_swipeup0010,
- R.drawable.elf_swipeup0011,
- R.drawable.elf_swipeup0012,
- R.drawable.elf_swipeup0013,
- R.drawable.elf_swipeup0014,
- R.drawable.elf_swipeup0015,
- R.drawable.elf_swipeup0016,
- R.drawable.elf_swipeup0017,
- R.drawable.elf_swipeup0018,
- R.drawable.elf_swipeup0019,
- R.drawable.elf_swipeup0020,
- R.drawable.elf_swipeup0021,
- R.drawable.elf_swipeup0022,
- R.drawable.elf_swipeup0023,
- R.drawable.elf_swipeup0024},//swipe up
- {R.drawable.elf_swipeleft0001,
- R.drawable.elf_swipeleft0002,
- R.drawable.elf_swipeleft0003,
- R.drawable.elf_swipeleft0004,
- R.drawable.elf_swipeleft0005,
- R.drawable.elf_swipeleft0006,
- R.drawable.elf_swipeleft0007,
- R.drawable.elf_swipeleft0008,
- R.drawable.elf_swipeleft0009,
- R.drawable.elf_swipeleft0010,
- R.drawable.elf_swipeleft0011,
- R.drawable.elf_swipeleft0012,
- R.drawable.elf_swipeleft0013,
- R.drawable.elf_swipeleft0014,
- R.drawable.elf_swipeleft0015,
- R.drawable.elf_swipeleft0016,
- R.drawable.elf_swipeleft0017,
- R.drawable.elf_swipeleft0018,
- R.drawable.elf_swipeleft0019,
- R.drawable.elf_swipeleft0020,
- R.drawable.elf_swipeleft0021,
- R.drawable.elf_swipeleft0022,
- R.drawable.elf_swipeleft0023,
- R.drawable.elf_swipeleft0024},//swipe left
- {R.drawable.elf_swiperight0002,
- R.drawable.elf_swiperight0003,
- R.drawable.elf_swiperight0004,
- R.drawable.elf_swiperight0005,
- R.drawable.elf_swiperight0006,
- R.drawable.elf_swiperight0007,
- R.drawable.elf_swiperight0008,
- R.drawable.elf_swiperight0009,
- R.drawable.elf_swiperight0010,
- R.drawable.elf_swiperight0011,
- R.drawable.elf_swiperight0012,
- R.drawable.elf_swiperight0013,
- R.drawable.elf_swiperight0014,
- R.drawable.elf_swiperight0015,
- R.drawable.elf_swiperight0016,
- R.drawable.elf_swiperight0017,
- R.drawable.elf_swiperight0018,
- R.drawable.elf_swiperight0019,
- R.drawable.elf_swiperight0020,
- R.drawable.elf_swiperight0021,
- R.drawable.elf_swiperight0022,
- R.drawable.elf_swiperight0023,
- R.drawable.elf_swiperight0024},//swipe right
- {R.drawable.elf_pinchout0001,
- R.drawable.elf_pinchout0002,
- R.drawable.elf_pinchout0003,
- R.drawable.elf_pinchout0004,
- R.drawable.elf_pinchout0005,
- R.drawable.elf_pinchout0006,
- R.drawable.elf_pinchout0007,
- R.drawable.elf_pinchout0008,
- R.drawable.elf_pinchout0009,
- R.drawable.elf_pinchout0010,
- R.drawable.elf_pinchout0011,
- R.drawable.elf_pinchout0012,
- R.drawable.elf_pinchout0013,
- R.drawable.elf_pinchout0014,
- R.drawable.elf_pinchout0015,
- R.drawable.elf_pinchout0016,
- R.drawable.elf_pinchout0017,
- R.drawable.elf_pinchout0018,
- R.drawable.elf_pinchout0019,
- R.drawable.elf_pinchout0020,
- R.drawable.elf_pinchout0021,
- R.drawable.elf_pinchout0022,
- R.drawable.elf_pinchout0023,
- R.drawable.elf_pinchout0024},//pinch in
- {R.drawable.elf_pinchin_ball0001, R.drawable.elf_pinchin_ball0002, R.drawable.elf_pinchin_ball0003, R.drawable.elf_pinchin_ball0004,
- R.drawable.elf_pinchin_ball0005, R.drawable.elf_pinchin_ball0006, R.drawable.elf_pinchin_ball0007, R.drawable.elf_pinchin_ball0008,
- R.drawable.elf_pinchin_ball0009, R.drawable.elf_pinchin_ball0010, R.drawable.elf_pinchin_ball0011, R.drawable.elf_pinchin_ball0012,
- R.drawable.elf_pinchin_ball0013, R.drawable.elf_pinchin_ball0014, R.drawable.elf_pinchin_ball0015, R.drawable.elf_pinchin_ball0016,
- R.drawable.elf_pinchin_ball0017, R.drawable.elf_pinchin_ball0018, R.drawable.elf_pinchin_ball0019, R.drawable.elf_pinchin_ball0020,
- R.drawable.elf_pinchin_ball0021, R.drawable.elf_pinchin_ball0022, R.drawable.elf_pinchin_ball0023, R.drawable.elf_pinchin_ball0024,
- R.drawable.elf_pinchin_ball0025, R.drawable.elf_pinchin_ball0026, R.drawable.elf_pinchin_ball0027, R.drawable.elf_pinchin_ball0028,
- R.drawable.elf_pinchin_ball0029, R.drawable.elf_pinchin_ball0030, R.drawable.elf_pinchin_ball0031, R.drawable.elf_pinchin_ball0032}//pinch out
- };
-
- private static final int[][] sFrameIndices = new int[][]{
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//idle
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//tap
- {0, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23},//shake
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//swipe down
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22},//swipe up
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//swipe left
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22},//swipe right
- {0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23},//pinch in
- {0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}//pinch out
- };
-
- @Override
- public long getDuration(int animationKey) {
- return sDurations[animationKey];
- }
-
- @Override
- public int[] getFrameIndices(int animationKey) {
- return sFrameIndices[animationKey];
- }
-
- @Override
- public int[] getFrames(int animationKey) {
- return sFrames[animationKey];
- }
-
- @Override
- public String getCharacterName() {
- return "h";
- }
-}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Elf.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Elf.kt
new file mode 100644
index 000000000..3b16f2121
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Elf.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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
+
+class Elf : Character {
+
+ override val characterName: String
+ get() = "h"
+
+ override fun getDuration(animationKey: Int): Long {
+ return durations[animationKey]
+ }
+
+ override fun getFrameIndices(animationKey: Int): IntArray {
+ return frameIndices[animationKey]
+ }
+
+ override fun getFrames(animationKey: Int): IntArray {
+ return frames[animationKey]
+ }
+
+ override fun getSoundResource(animationid: Int): Int {
+ when (animationid) {
+ Character.ANIM_PINCH_IN -> return R.raw.elf_pinchin_ball
+ Character.ANIM_PINCH_OUT -> return R.raw.elf_pinchout
+ Character.ANIM_SHAKE -> return R.raw.elf_shake2
+ Character.ANIM_SWIPE_DOWN -> return R.raw.elf_swipedown2
+ Character.ANIM_SWIPE_UP -> return R.raw.elf_swipeup2
+ Character.ANIM_SWIPE_LEFT -> return R.raw.elf_swipeleft
+ Character.ANIM_SWIPE_RIGHT -> return R.raw.elf_swiperight
+ Character.ANIM_TAP -> return R.raw.elf_tap3
+ }
+
+ return -1
+ }
+
+ companion object {
+
+ private val durations = longArrayOf(1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1333)
+
+ private val frames = arrayOf(
+ intArrayOf(R.drawable.elf_idle_0001, R.drawable.elf_idle_0002,
+ R.drawable.elf_idle_0003, R.drawable.elf_idle_0004, R.drawable.elf_idle_0005,
+ R.drawable.elf_idle_0006, R.drawable.elf_idle_0007, R.drawable.elf_idle_0008,
+ R.drawable.elf_idle_0009, R.drawable.elf_idle_0010, R.drawable.elf_idle_0011,
+ R.drawable.elf_idle_0012, R.drawable.elf_idle_0011, R.drawable.elf_idle_0010,
+ R.drawable.elf_idle_0015, R.drawable.elf_idle_0009, R.drawable.elf_idle_0017,
+ R.drawable.elf_idle_0007, R.drawable.elf_idle_0019, R.drawable.elf_idle_0020,
+ R.drawable.elf_idle_0021, R.drawable.elf_idle_0022, R.drawable.elf_idle_0002,
+ R.drawable.elf_idle_0024), // idle
+ intArrayOf(R.drawable.elf_idle_0024, R.drawable.elf_tap_0002, R.drawable.elf_tap_0003,
+ R.drawable.elf_tap_0004, R.drawable.elf_tap_0005, R.drawable.elf_tap_0006,
+ R.drawable.elf_tap_0007, R.drawable.elf_tap_0008, R.drawable.elf_tap_0009,
+ R.drawable.elf_tap_0010, R.drawable.elf_tap_0011, R.drawable.elf_tap_0012,
+ R.drawable.elf_tap_0013, R.drawable.elf_tap_0014, R.drawable.elf_tap_0015,
+ R.drawable.elf_tap_0016, R.drawable.elf_tap_0017, R.drawable.elf_tap_0018,
+ R.drawable.elf_idle_0024, R.drawable.elf_idle_0024, R.drawable.elf_idle_0024,
+ R.drawable.elf_idle_0024, R.drawable.elf_idle_0024,
+ R.drawable.elf_idle_0024), // tap
+ intArrayOf(R.drawable.elf_shake_0001, R.drawable.elf_shake_0002,
+ R.drawable.elf_shake_0003, R.drawable.elf_shake_0004,
+ R.drawable.elf_shake_0005, R.drawable.elf_shake_0006,
+ R.drawable.elf_shake_0007, R.drawable.elf_shake_0008,
+ R.drawable.elf_shake_0009, R.drawable.elf_shake_0010,
+ R.drawable.elf_shake_0011, R.drawable.elf_shake_0012,
+ R.drawable.elf_shake_0013, R.drawable.elf_shake_0014,
+ R.drawable.elf_shake_0015, R.drawable.elf_shake_0016,
+ R.drawable.elf_shake_0017, R.drawable.elf_shake_0018,
+ R.drawable.elf_shake_0019, R.drawable.elf_shake_0020,
+ R.drawable.elf_shake_0021, R.drawable.elf_shake_0022,
+ R.drawable.elf_shake_0023, R.drawable.elf_shake_0001), // shake
+ intArrayOf(R.drawable.elf_swipedown_0001, R.drawable.elf_swipedown_0001,
+ R.drawable.elf_swipedown_0003, R.drawable.elf_swipedown_0004,
+ R.drawable.elf_swipedown_0005, R.drawable.elf_swipedown_0006,
+ R.drawable.elf_swipedown_0007, R.drawable.elf_swipedown_0008,
+ R.drawable.elf_swipedown_0009, R.drawable.elf_swipedown_0010,
+ R.drawable.elf_swipedown_0011, R.drawable.elf_swipedown_0012,
+ R.drawable.elf_swipedown_0013, R.drawable.elf_swipedown_0012,
+ R.drawable.elf_swipedown_0015, R.drawable.elf_swipedown_0016,
+ R.drawable.elf_swipedown_0017, R.drawable.elf_swipedown_0018,
+ R.drawable.elf_swipedown_0019, R.drawable.elf_swipedown_0020,
+ R.drawable.elf_swipedown_0021, R.drawable.elf_swipedown_0022,
+ R.drawable.elf_swipedown_0023, R.drawable.elf_swipedown_0001), // swipe down
+ intArrayOf(R.drawable.elf_swipeup_0002, R.drawable.elf_swipeup_0003,
+ R.drawable.elf_swipeup_0004, R.drawable.elf_swipeup_0005,
+ R.drawable.elf_swipeup_0006, R.drawable.elf_swipeup_0007,
+ R.drawable.elf_swipeup_0008, R.drawable.elf_swipeup_0009,
+ R.drawable.elf_swipeup_0010, R.drawable.elf_swipeup_0011,
+ R.drawable.elf_swipeup_0012, R.drawable.elf_swipeup_0013,
+ R.drawable.elf_swipeup_0014, R.drawable.elf_swipeup_0015,
+ R.drawable.elf_swipeup_0016, R.drawable.elf_swipeup_0017,
+ R.drawable.elf_swipeup_0018, R.drawable.elf_swipeup_0019,
+ R.drawable.elf_swipeup_0020, R.drawable.elf_swipeup_0021,
+ R.drawable.elf_swipeup_0022, R.drawable.elf_swipeup_0023,
+ R.drawable.elf_swipedown_0001), // swipe up
+ intArrayOf(R.drawable.elf_swipeleft_0001, R.drawable.elf_swipeleft_0002,
+ R.drawable.elf_swipeleft_0003, R.drawable.elf_swipeleft_0004,
+ R.drawable.elf_swipeleft_0005, R.drawable.elf_swipeleft_0006,
+ R.drawable.elf_swipeleft_0007, R.drawable.elf_swipeleft_0008,
+ R.drawable.elf_swipeleft_0009, R.drawable.elf_swipeleft_0010,
+ R.drawable.elf_swipeleft_0011, R.drawable.elf_swipeleft_0012,
+ R.drawable.elf_swipeleft_0013, R.drawable.elf_swipeleft_0014,
+ R.drawable.elf_swipeleft_0015, R.drawable.elf_swipeleft_0016,
+ R.drawable.elf_swipeleft_0017, R.drawable.elf_swipeleft_0018,
+ R.drawable.elf_swipeleft_0019, R.drawable.elf_swipeleft_0020,
+ R.drawable.elf_swipeleft_0021, R.drawable.elf_swipeleft_0022,
+ R.drawable.elf_swipeleft_0023, R.drawable.elf_swipeleft_0024), // swipe left
+ intArrayOf(R.drawable.elf_swiperight_0002, R.drawable.elf_swiperight_0003,
+ R.drawable.elf_swiperight_0004, R.drawable.elf_swiperight_0005,
+ R.drawable.elf_swiperight_0006, R.drawable.elf_swiperight_0007,
+ R.drawable.elf_swiperight_0008, R.drawable.elf_swiperight_0009,
+ R.drawable.elf_swiperight_0010, R.drawable.elf_swiperight_0011,
+ R.drawable.elf_swiperight_0012, R.drawable.elf_swiperight_0013,
+ R.drawable.elf_swiperight_0014, R.drawable.elf_swiperight_0015,
+ R.drawable.elf_swiperight_0016, R.drawable.elf_swiperight_0017,
+ R.drawable.elf_swiperight_0018, R.drawable.elf_swiperight_0019,
+ R.drawable.elf_swiperight_0020, R.drawable.elf_swiperight_0021,
+ R.drawable.elf_swiperight_0022, R.drawable.elf_swiperight_0023,
+ R.drawable.elf_swipedown_0001), // swipe right
+ intArrayOf(R.drawable.elf_pinchout_0001, R.drawable.elf_pinchout_0002,
+ R.drawable.elf_pinchout_0003, R.drawable.elf_pinchout_0004,
+ R.drawable.elf_pinchout_0005, R.drawable.elf_pinchout_0006,
+ R.drawable.elf_pinchout_0007, R.drawable.elf_pinchout_0007,
+ R.drawable.elf_pinchout_0007, R.drawable.elf_pinchout_0007,
+ R.drawable.elf_pinchout_0007, R.drawable.elf_pinchout_0007,
+ R.drawable.elf_pinchout_0007, R.drawable.elf_pinchout_0007,
+ R.drawable.elf_pinchout_0007, R.drawable.elf_pinchout_0007,
+ R.drawable.elf_pinchout_0007, R.drawable.elf_pinchout_0007,
+ R.drawable.elf_pinchout_0019, R.drawable.elf_pinchout_0020,
+ R.drawable.elf_pinchout_0021, R.drawable.elf_pinchout_0022,
+ R.drawable.elf_pinchout_0023, R.drawable.elf_pinchout_0024), // pinch in
+ intArrayOf(R.drawable.elf_pinchin_0001, R.drawable.elf_pinchin_0002,
+ R.drawable.elf_pinchin_0003, R.drawable.elf_pinchin_0004,
+ R.drawable.elf_pinchin_0005, R.drawable.elf_pinchin_0006,
+ R.drawable.elf_pinchin_0007, R.drawable.elf_pinchin_0008,
+ R.drawable.elf_pinchin_0009, R.drawable.elf_pinchin_0010,
+ R.drawable.elf_pinchin_0011, R.drawable.elf_pinchin_0012,
+ R.drawable.elf_pinchin_0013, R.drawable.elf_pinchin_0014,
+ R.drawable.elf_pinchin_0015, R.drawable.elf_pinchin_0016,
+ R.drawable.elf_pinchin_0017, R.drawable.elf_pinchin_0018,
+ R.drawable.elf_pinchin_0019, R.drawable.elf_pinchin_0020,
+ R.drawable.elf_pinchin_0021, R.drawable.elf_pinchin_0022,
+ R.drawable.elf_pinchin_0023, R.drawable.elf_pinchin_0024,
+ R.drawable.elf_pinchin_0025, R.drawable.elf_pinchin_0026,
+ R.drawable.elf_pinchin_0027, R.drawable.elf_pinchin_0028,
+ R.drawable.elf_pinchin_0029, R.drawable.elf_pinchin_0030,
+ R.drawable.elf_pinchin_0031,
+ R.drawable.elf_pinchin_0032) // pinch out
+ )
+
+ private val frameIndices =
+ arrayOf(intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // idle
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // tap
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // shake
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // swipe down
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22), // swipe up
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // swipe left
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22), // swipe right
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // pinch in
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31) // pinch out
+ )
+ }
+}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/FrameAnimationView.java b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/FrameAnimationView.java
deleted file mode 100644
index 8044b0328..000000000
--- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/FrameAnimationView.java
+++ /dev/null
@@ -1,92 +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.apps.santatracker.dasherdancer;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.drawable.BitmapDrawable;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-public class FrameAnimationView extends ImageView {
-
- private Bitmap[] mFrames;
- private int[] mFrameIndices;
- private int mFrameIndex;
- private final Paint mPaint = new Paint();
-
- 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);
- }
-
- /**
- * Will attempt to recycle the old frames before setting the new frames.
- * @param frames
- * @param frameIndices
- */
- public void setFrames(Bitmap[] 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 && !mFrames[mFrameIndices[mFrameIndex]].isRecycled()) {
- 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;
- }
- if(((BitmapDrawable)getDrawable()).getBitmap() == null
- || ((BitmapDrawable)getDrawable()).getBitmap().isRecycled()) {
- return;
- }
- super.onDraw(c);
- }
-}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/FrameAnimationView.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/FrameAnimationView.kt
new file mode 100644
index 000000000..f250dfb8e
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/FrameAnimationView.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.content.Context
+import android.graphics.Canvas
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import androidx.appcompat.widget.AppCompatImageView
+
+class FrameAnimationView : AppCompatImageView {
+
+ private var frames: Array? = null
+
+ private var frameIndices: IntArray? = null
+ var frameIndex: Int = 0
+ set(frameIndex) {
+ field = frameIndex
+ val frames = frames ?: return
+ val frameIndices = frameIndices ?: return
+ if (this.frameIndex >= 0 &&
+ this.frameIndex < frameIndices.size &&
+ frames[frameIndices[this.frameIndex]] != null &&
+ !isBitmapRecycled(frames[frameIndices[this.frameIndex]])) {
+ invalidate()
+ }
+ }
+ private val paint = Paint()
+ private val insetDrawable: InsetDrawableCompat? = null
+
+ internal var matrix = Matrix()
+
+ constructor(context: Context) : super(context) {
+ init()
+ }
+
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+ init()
+ }
+
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
+ init()
+ }
+
+ private fun init() {
+ paint.isAntiAlias = true
+ setImageDrawable(insetDrawable)
+ }
+
+ /**
+ * Will attempt to recycle the old frames before setting the new frames.
+ *
+ * @param frames
+ * @param frameIndices
+ */
+ fun setFrames(frames: Array?, frameIndices: IntArray?) {
+ if (this.frames != null) {
+ this.frames = null
+ }
+ this.frames = frames
+ this.frameIndices = frameIndices
+ }
+
+ private fun isBitmapRecycled(drawable: Drawable?): Boolean {
+ var drawable = drawable
+ if (drawable != null && drawable is InsetDrawableCompat) {
+ drawable = drawable.drawable
+ }
+ if (drawable != null && drawable is BitmapDrawable) {
+ val bmp = drawable.bitmap
+ if (bmp != null) {
+ return bmp.isRecycled
+ }
+ }
+ return true
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ recalculateMatrix(w, h)
+ }
+
+ private fun recalculateMatrix(vwidth: Int, vheight: Int) {
+ val frames = frames ?: return
+ val frameIndices = frameIndices ?: return
+ if (frameIndex >= 0 && frameIndex < frameIndices.size) {
+ val insetDrawableCompat = frames[frameIndices[frameIndex]] as InsetDrawableCompat
+
+ if (isBitmapRecycled(insetDrawableCompat)) {
+ return
+ }
+
+ matrix.reset()
+ val scale: Float
+ var dx = 0f
+ var dy = 0f
+
+ val dwidth = (insetDrawableCompat.drawable!!.intrinsicWidth +
+ insetDrawableCompat.left +
+ insetDrawableCompat.right)
+ val dheight = (insetDrawableCompat.drawable!!.intrinsicHeight +
+ insetDrawableCompat.top +
+ insetDrawableCompat.bottom)
+
+ if (dwidth * vheight > vwidth * dheight) {
+ scale = vheight.toFloat() / dheight.toFloat()
+ dx = (vwidth - dwidth * scale) * 0.5f
+ } else {
+ scale = vwidth.toFloat() / dwidth.toFloat()
+ dy = (vheight - dheight * scale) * 0.5f
+ }
+
+ matrix.setTranslate(insetDrawableCompat.left.toFloat(), insetDrawableCompat.top.toFloat())
+ matrix.postScale(scale, scale)
+ matrix.postTranslate(Math.round(dx).toFloat(), Math.round(dy).toFloat())
+ imageMatrix = matrix
+ }
+ }
+
+ public override fun onDraw(c: Canvas) {
+ val frames = frames ?: return
+ val frameIndices = frameIndices ?: return
+ if (frameIndex >= 0 && frameIndex < frameIndices.size) {
+ // 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(frames[frameIndices[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
+
+ val insetDrawableCompat = frames[frameIndices[frameIndex]] as InsetDrawableCompat
+ if (isBitmapRecycled(insetDrawableCompat)) {
+ return
+ }
+ val newBitmap = (insetDrawableCompat.drawable as BitmapDrawable).bitmap
+
+ val current = drawable
+ if (current == null || current is BitmapDrawable && newBitmap != current.bitmap) {
+ setImageBitmap(newBitmap)
+ recalculateMatrix(width, height)
+ }
+ }
+
+ if (isBitmapRecycled(drawable)) {
+ return
+ }
+ super.onDraw(c)
+ }
+}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/InsetDrawableCompat.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/InsetDrawableCompat.kt
new file mode 100644
index 000000000..f1176a1cd
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/InsetDrawableCompat.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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
+
+class InsetDrawableCompat : InsetDrawable {
+
+ private var inDrawable: Drawable? = null
+ var left: Int = 0
+ private set
+ var top: Int = 0
+ private set
+ var right: Int = 0
+ private set
+ var bottom: Int = 0
+ private set
+
+ override fun getDrawable(): Drawable? {
+ return inDrawable
+ }
+
+ constructor(
+ drawable: Drawable,
+ insetLeft: Int,
+ insetTop: Int,
+ insetRight: Int,
+ insetBottom: Int
+ ) : super(drawable, insetLeft, insetTop, insetRight, insetBottom) {
+ inDrawable = drawable
+ left = insetLeft
+ top = insetTop
+ right = insetRight
+ bottom = 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
deleted file mode 100644
index 3446d58da..000000000
--- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/NoSwipeViewPager.java
+++ /dev/null
@@ -1,60 +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.apps.santatracker.dasherdancer;
-
-import android.content.Context;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.GestureDetector.OnGestureListener;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.ScaleGestureDetector.OnScaleGestureListener;
-
-public class NoSwipeViewPager extends ViewPager {
-
- private GestureDetector mGestureDetector;
- private ScaleGestureDetector mScaleGestureDetector;
-
- public NoSwipeViewPager(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- //Take all events, as we are going to animate the current view based on touch events.
- return true;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- boolean retVal = false;
- if(ev.getPointerCount() > 1) {
- retVal = mScaleGestureDetector.onTouchEvent(ev);
- }
- if(!retVal && ev.getPointerCount() == 1) {
- retVal = mGestureDetector.onTouchEvent(ev) || retVal;
- }
- return retVal;
- }
-
- public void setGestureDetectorListeners(Context context,
- OnGestureListener listener, OnScaleGestureListener scaleListener) {
- mGestureDetector = new GestureDetector(context, listener);
- mScaleGestureDetector = new ScaleGestureDetector(context, scaleListener);
- }
-}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/NoSwipeViewPager.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/NoSwipeViewPager.kt
new file mode 100644
index 000000000..7f7a46aea
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/NoSwipeViewPager.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.content.Context
+import android.util.AttributeSet
+import android.view.GestureDetector
+import android.view.GestureDetector.OnGestureListener
+import android.view.MotionEvent
+import android.view.ScaleGestureDetector
+import android.view.ScaleGestureDetector.OnScaleGestureListener
+import androidx.viewpager.widget.ViewPager
+
+class NoSwipeViewPager(context: Context, attrs: AttributeSet) : ViewPager(context, attrs) {
+
+ private var gestureDetector: GestureDetector? = null
+ private var scaleGestureDetector: ScaleGestureDetector? = null
+
+ override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
+ // Take all events, as we are going to animate the current view based on touch events.
+ return true
+ }
+
+ override fun onTouchEvent(ev: MotionEvent): Boolean {
+ var retVal = false
+ if (ev.pointerCount > 1) {
+ retVal = scaleGestureDetector!!.onTouchEvent(ev)
+ }
+ if (!retVal && ev.pointerCount == 1) {
+ retVal = gestureDetector!!.onTouchEvent(ev) || retVal
+ }
+ return retVal
+ }
+
+ fun setGestureDetectorListeners(
+ context: Context,
+ listener: OnGestureListener,
+ scaleListener: OnScaleGestureListener
+ ) {
+ gestureDetector = GestureDetector(context, listener)
+ scaleGestureDetector = ScaleGestureDetector(context, scaleListener)
+ }
+}
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
deleted file mode 100644
index bcc951b75..000000000
--- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Reindeer.java
+++ /dev/null
@@ -1,233 +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.apps.santatracker.dasherdancer;
-
-public class Reindeer implements Character {
-
- private static final long[] sDurations = new long[]{
- 1000, 1000, 1000, 1000, 1000,
- 1000, 1000, 1000, 1000
- };
-
- private static final int[][] sFrames = new int[][]{
- {
- R.drawable.reindeer_tap0001}, //idle
- {R.drawable.reindeer_tap0001, R.drawable.reindeer_tap0002, R.drawable.reindeer_tap0003, R.drawable.reindeer_tap0004,
- R.drawable.reindeer_tap0005, R.drawable.reindeer_tap0006, R.drawable.reindeer_tap0007, R.drawable.reindeer_tap0008,
- R.drawable.reindeer_tap0009, R.drawable.reindeer_tap0010, R.drawable.reindeer_tap0011, R.drawable.reindeer_tap0012,
- R.drawable.reindeer_tap0013, R.drawable.reindeer_tap0014, R.drawable.reindeer_tap0015, R.drawable.reindeer_tap0016,
- R.drawable.reindeer_tap0017, R.drawable.reindeer_tap0018, R.drawable.reindeer_tap0019, R.drawable.reindeer_tap0020,
- R.drawable.reindeer_tap0021, R.drawable.reindeer_tap0022, R.drawable.reindeer_tap0023, R.drawable.reindeer_tap0024},//tap
- {R.drawable.reindeer_shake0001, R.drawable.reindeer_shake0002, R.drawable.reindeer_shake0003, R.drawable.reindeer_shake0004,
- R.drawable.reindeer_shake0005, R.drawable.reindeer_shake0006, R.drawable.reindeer_shake0007, R.drawable.reindeer_shake0008,
- R.drawable.reindeer_shake0009, R.drawable.reindeer_shake0010, R.drawable.reindeer_shake0011, R.drawable.reindeer_shake0012,
- R.drawable.reindeer_shake0013, R.drawable.reindeer_shake0014, R.drawable.reindeer_shake0015, R.drawable.reindeer_shake0016,
- R.drawable.reindeer_shake0017, R.drawable.reindeer_shake0018, R.drawable.reindeer_shake0019, R.drawable.reindeer_shake0020,
- R.drawable.reindeer_shake0021, R.drawable.reindeer_shake0022, R.drawable.reindeer_shake0023, R.drawable.reindeer_shake0024},//shake
- {R.drawable.reindeer_swipedown0001,
- R.drawable.reindeer_swipedown0002,
- R.drawable.reindeer_swipedown0003,
- R.drawable.reindeer_swipedown0004,
- R.drawable.reindeer_swipedown0005,
- R.drawable.reindeer_swipedown0006,
- R.drawable.reindeer_swipedown0007,
- R.drawable.reindeer_swipedown0008,
- R.drawable.reindeer_swipedown0009,
- R.drawable.reindeer_swipedown0010,
- R.drawable.reindeer_swipedown0011,
- R.drawable.reindeer_swipedown0012,
- R.drawable.reindeer_swipedown0013,
- R.drawable.reindeer_swipedown0014,
- R.drawable.reindeer_swipedown0015,
- R.drawable.reindeer_swipedown0016,
- R.drawable.reindeer_swipedown0017,
- R.drawable.reindeer_swipedown0018,
- R.drawable.reindeer_swipedown0019,
- R.drawable.reindeer_swipedown0020,
- R.drawable.reindeer_swipedown0021,
- R.drawable.reindeer_swipedown0022,
- R.drawable.reindeer_swipedown0023,
- R.drawable.reindeer_swipedown0024},//swipe down
- {R.drawable.reindeer_swipeup0002,
- R.drawable.reindeer_swipeup0003,
- R.drawable.reindeer_swipeup0004,
- R.drawable.reindeer_swipeup0005,
- R.drawable.reindeer_swipeup0006,
- R.drawable.reindeer_swipeup0007,
- R.drawable.reindeer_swipeup0008,
- R.drawable.reindeer_swipeup0009,
- R.drawable.reindeer_swipeup0010,
- R.drawable.reindeer_swipeup0011,
- R.drawable.reindeer_swipeup0012,
- R.drawable.reindeer_swipeup0013,
- R.drawable.reindeer_swipeup0014,
- R.drawable.reindeer_swipeup0015,
- R.drawable.reindeer_swipeup0016,
- R.drawable.reindeer_swipeup0017,
- R.drawable.reindeer_swipeup0018,
- R.drawable.reindeer_swipeup0019,
- R.drawable.reindeer_swipeup0020,
- R.drawable.reindeer_swipeup0021,
- R.drawable.reindeer_swipeup0022,
- R.drawable.reindeer_swipeup0023,
- R.drawable.reindeer_swipeup0024},//swipe up
- {R.drawable.reindeer_swipeleft0001,
- R.drawable.reindeer_swipeleft0002,
- R.drawable.reindeer_swipeleft0003,
- R.drawable.reindeer_swipeleft0004,
- R.drawable.reindeer_swipeleft0005,
- R.drawable.reindeer_swipeleft0006,
- R.drawable.reindeer_swipeleft0007,
- R.drawable.reindeer_swipeleft0008,
- R.drawable.reindeer_swipeleft0009,
- R.drawable.reindeer_swipeleft0010,
- R.drawable.reindeer_swipeleft0011,
- R.drawable.reindeer_swipeleft0012,
- R.drawable.reindeer_swipeleft0013,
- R.drawable.reindeer_swipeleft0014,
- R.drawable.reindeer_swipeleft0015,
- R.drawable.reindeer_swipeleft0016,
- R.drawable.reindeer_swipeleft0017,
- R.drawable.reindeer_swipeleft0018,
- R.drawable.reindeer_swipeleft0019,
- R.drawable.reindeer_swipeleft0020,
- R.drawable.reindeer_swipeleft0021,
- R.drawable.reindeer_swipeleft0022,
- R.drawable.reindeer_swipeleft0023,
- R.drawable.reindeer_swipeleft0024},//swipe left
- {R.drawable.reindeer_swiperight0002,
- R.drawable.reindeer_swiperight0003,
- R.drawable.reindeer_swiperight0004,
- R.drawable.reindeer_swiperight0005,
- R.drawable.reindeer_swiperight0006,
- R.drawable.reindeer_swiperight0007,
- R.drawable.reindeer_swiperight0008,
- R.drawable.reindeer_swiperight0009,
- R.drawable.reindeer_swiperight0010,
- R.drawable.reindeer_swiperight0011,
- R.drawable.reindeer_swiperight0012,
- R.drawable.reindeer_swiperight0013,
- R.drawable.reindeer_swiperight0014,
- R.drawable.reindeer_swiperight0015,
- R.drawable.reindeer_swiperight0016,
- R.drawable.reindeer_swiperight0017,
- R.drawable.reindeer_swiperight0018,
- R.drawable.reindeer_swiperight0019,
- R.drawable.reindeer_swiperight0020,
- R.drawable.reindeer_swiperight0021,
- R.drawable.reindeer_swiperight0022,
- R.drawable.reindeer_swiperight0023,
- R.drawable.reindeer_swiperight0024},//swipe right
- {R.drawable.reindeer_pinchout0001,
- R.drawable.reindeer_pinchout0002,
- R.drawable.reindeer_pinchout0003,
- R.drawable.reindeer_pinchout0004,
- R.drawable.reindeer_pinchout0005,
- R.drawable.reindeer_pinchout0006,
- R.drawable.reindeer_pinchout0007,
- R.drawable.reindeer_pinchout0008,
- R.drawable.reindeer_pinchout0009,
- R.drawable.reindeer_pinchout0010,
- R.drawable.reindeer_pinchout0011,
- R.drawable.reindeer_pinchout0012,
- R.drawable.reindeer_pinchout0013,
- R.drawable.reindeer_pinchout0014,
- R.drawable.reindeer_pinchout0015,
- R.drawable.reindeer_pinchout0016,
- R.drawable.reindeer_pinchout0017,
- R.drawable.reindeer_pinchout0018,
- R.drawable.reindeer_pinchout0019,
- R.drawable.reindeer_pinchout0020,
- R.drawable.reindeer_pinchout0021,
- R.drawable.reindeer_pinchout0022,
- R.drawable.reindeer_pinchout0023,
- R.drawable.reindeer_pinchout0024},//pinch in
- {R.drawable.reindeer_pinchin0001,
- R.drawable.reindeer_pinchin0002,
- R.drawable.reindeer_pinchin0003,
- R.drawable.reindeer_pinchin0004,
- R.drawable.reindeer_pinchin0005,
- R.drawable.reindeer_pinchin0006,
- R.drawable.reindeer_pinchin0007,
- R.drawable.reindeer_pinchin0008,
- R.drawable.reindeer_pinchin0009,
- R.drawable.reindeer_pinchin0010,
- R.drawable.reindeer_pinchin0011,
- R.drawable.reindeer_pinchin0012,
- R.drawable.reindeer_pinchin0013,
- R.drawable.reindeer_pinchin0014,
- R.drawable.reindeer_pinchin0015,
- R.drawable.reindeer_pinchin0016,
- R.drawable.reindeer_pinchin0017,
- R.drawable.reindeer_pinchin0018,
- R.drawable.reindeer_pinchin0019,
- R.drawable.reindeer_pinchin0020,
- R.drawable.reindeer_pinchin0021,
- R.drawable.reindeer_pinchin0022,
- R.drawable.reindeer_pinchin0023,
- R.drawable.reindeer_pinchin0024}//pinch in
- };
-
- private static final int[][] sFrameIndices = new int[][]{
- {0},//idle
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//tap
- {0, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23},//shake
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//swipe down
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22},//swipe up
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//swipe left
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22},//swipe right
- {0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23},//pinch in
- {0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23}//pinch out
- };
-
- @Override
- public long getDuration(int animationKey) {
- return sDurations[animationKey];
- }
-
- @Override
- public int[] getFrameIndices(int animationKey) {
- return sFrameIndices[animationKey];
- }
-
- @Override
- public int[] getFrames(int animationKey) {
- return sFrames[animationKey];
- }
-
- @Override
- public String getCharacterName() {
- return "r";
- }
-
-}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Reindeer.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Reindeer.kt
new file mode 100644
index 000000000..05c854663
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Reindeer.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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
+
+class Reindeer : Character {
+
+ override val characterName: String
+ get() = "r"
+
+ override fun getDuration(animationKey: Int): Long {
+ return durations[animationKey]
+ }
+
+ override fun getFrameIndices(animationKey: Int): IntArray {
+ return frameIndices[animationKey]
+ }
+
+ override fun getFrames(animationKey: Int): IntArray {
+ return frames[animationKey]
+ }
+
+ override fun getSoundResource(animationid: Int): Int {
+ when (animationid) {
+ Character.ANIM_PINCH_IN -> return R.raw.reindeer_pinchin
+ Character.ANIM_PINCH_OUT -> return R.raw.reindeer_pinchout
+ Character.ANIM_SHAKE -> return R.raw.reindeer_shake
+ Character.ANIM_SWIPE_UP -> return R.raw.reindeer_swipeup
+ Character.ANIM_SWIPE_DOWN -> return R.raw.reindeer_swipedown
+ Character.ANIM_SWIPE_LEFT -> return R.raw.reindeer_swipeleft
+ Character.ANIM_SWIPE_RIGHT -> return R.raw.reindeer_swiperight
+ Character.ANIM_TAP -> return R.raw.reindeer_tap2
+ }
+
+ return -1
+ }
+
+ companion object {
+
+ private val durations = longArrayOf(1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000)
+
+ private val frames = arrayOf(
+ intArrayOf(R.drawable.reindeer_tap0001), // idle
+ intArrayOf(R.drawable.reindeer_tap0001, R.drawable.reindeer_tap0002,
+ R.drawable.reindeer_tap0003, R.drawable.reindeer_tap0004,
+ R.drawable.reindeer_tap0005, R.drawable.reindeer_tap0006,
+ R.drawable.reindeer_tap0007, R.drawable.reindeer_tap0008,
+ R.drawable.reindeer_tap0009, R.drawable.reindeer_tap0010,
+ R.drawable.reindeer_tap0010, R.drawable.reindeer_tap0010,
+ R.drawable.reindeer_tap0010, R.drawable.reindeer_tap0010,
+ R.drawable.reindeer_tap0010, R.drawable.reindeer_tap0010,
+ R.drawable.reindeer_tap0010, R.drawable.reindeer_tap0010,
+ R.drawable.reindeer_tap0019, R.drawable.reindeer_tap0020,
+ R.drawable.reindeer_tap0021, R.drawable.reindeer_tap0022,
+ R.drawable.reindeer_tap0005, R.drawable.reindeer_tap0005), // tap
+ intArrayOf(R.drawable.reindeer_pinchout0001, R.drawable.reindeer_shake0002,
+ R.drawable.reindeer_shake0003, R.drawable.reindeer_shake0004,
+ R.drawable.reindeer_shake0005, R.drawable.reindeer_shake0006,
+ R.drawable.reindeer_shake0007, R.drawable.reindeer_shake0008,
+ R.drawable.reindeer_shake0009, R.drawable.reindeer_shake0010,
+ R.drawable.reindeer_shake0011, R.drawable.reindeer_shake0012,
+ R.drawable.reindeer_shake0013, R.drawable.reindeer_shake0014,
+ R.drawable.reindeer_shake0015, R.drawable.reindeer_shake0016,
+ R.drawable.reindeer_shake0017, R.drawable.reindeer_shake0018,
+ R.drawable.reindeer_shake0019, R.drawable.reindeer_shake0020,
+ R.drawable.reindeer_shake0021, R.drawable.reindeer_shake0022,
+ R.drawable.reindeer_shake0023, R.drawable.reindeer_shake0024), // shake
+ intArrayOf(R.drawable.reindeer_swipedown0001, R.drawable.reindeer_swipedown0002,
+ R.drawable.reindeer_swipedown0003, R.drawable.reindeer_swipedown0004,
+ R.drawable.reindeer_swipedown0005, R.drawable.reindeer_swipedown0006,
+ R.drawable.reindeer_swipedown0007, R.drawable.reindeer_swipedown0008,
+ R.drawable.reindeer_swipedown0009, R.drawable.reindeer_swipedown0010,
+ R.drawable.reindeer_swipedown0011, R.drawable.reindeer_swipedown0012,
+ R.drawable.reindeer_swipedown0013, R.drawable.reindeer_swipedown0014,
+ R.drawable.reindeer_swipedown0015, R.drawable.reindeer_swipedown0016,
+ R.drawable.reindeer_swipedown0017, R.drawable.reindeer_swipedown0018,
+ R.drawable.reindeer_swipedown0019, R.drawable.reindeer_swipedown0020,
+ R.drawable.reindeer_swipedown0021, R.drawable.reindeer_swipedown0022,
+ R.drawable.reindeer_swipedown0023,
+ R.drawable.reindeer_swipedown0001), // swipe down
+ intArrayOf(R.drawable.reindeer_swipeup0002, R.drawable.reindeer_swipeup0003,
+ R.drawable.reindeer_swipeup0004, R.drawable.reindeer_swipeup0005,
+ R.drawable.reindeer_swipeup0006, R.drawable.reindeer_swipeup0007,
+ R.drawable.reindeer_swipeup0008, R.drawable.reindeer_swipeup0009,
+ R.drawable.reindeer_swipeup0010, R.drawable.reindeer_swipeup0011,
+ R.drawable.reindeer_swipeup0012, R.drawable.reindeer_swipeup0013,
+ R.drawable.reindeer_swipeup0014, R.drawable.reindeer_swipeup0015,
+ R.drawable.reindeer_swipeup0016, R.drawable.reindeer_swipeup0017,
+ R.drawable.reindeer_swipeup0018, R.drawable.reindeer_swipeup0019,
+ R.drawable.reindeer_swipeup0020, R.drawable.reindeer_swipeup0021,
+ R.drawable.reindeer_swipeup0022, R.drawable.reindeer_swipeup0023,
+ R.drawable.reindeer_swipeup0001), // swipe up
+ intArrayOf(R.drawable.reindeer_swipeleft0001, R.drawable.reindeer_swipeleft0002,
+ R.drawable.reindeer_swipeleft0003, R.drawable.reindeer_swipeleft0004,
+ R.drawable.reindeer_swipeleft0005, R.drawable.reindeer_swipeleft0006,
+ R.drawable.reindeer_swipeleft0007, R.drawable.reindeer_swipeleft0008,
+ R.drawable.reindeer_swipeleft0009, R.drawable.reindeer_swipeleft0010,
+ R.drawable.reindeer_swipeleft0011, R.drawable.reindeer_swipeleft0012,
+ R.drawable.reindeer_swipeleft0013, R.drawable.reindeer_swipeleft0014,
+ R.drawable.reindeer_swipeleft0015, R.drawable.reindeer_swipeleft0016,
+ R.drawable.reindeer_swipeleft0017, R.drawable.reindeer_swipeleft0018,
+ R.drawable.reindeer_swipeleft0019, R.drawable.reindeer_swipeleft0020,
+ R.drawable.reindeer_swipeleft0021, R.drawable.reindeer_swipeleft0022,
+ R.drawable.reindeer_swipeleft0023,
+ R.drawable.reindeer_swipeleft0024), // swipe left
+ intArrayOf(R.drawable.reindeer_swiperight0002, R.drawable.reindeer_swiperight0003,
+ R.drawable.reindeer_swiperight0004, R.drawable.reindeer_swiperight0005,
+ R.drawable.reindeer_swiperight0006, R.drawable.reindeer_swiperight0007,
+ R.drawable.reindeer_swiperight0008, R.drawable.reindeer_swiperight0009,
+ R.drawable.reindeer_swiperight0010, R.drawable.reindeer_swiperight0011,
+ R.drawable.reindeer_swiperight0012, R.drawable.reindeer_swiperight0013,
+ R.drawable.reindeer_swiperight0014, R.drawable.reindeer_swiperight0015,
+ R.drawable.reindeer_swiperight0016, R.drawable.reindeer_swiperight0017,
+ R.drawable.reindeer_swiperight0018, R.drawable.reindeer_swiperight0019,
+ R.drawable.reindeer_swiperight0020, R.drawable.reindeer_swiperight0021,
+ R.drawable.reindeer_swiperight0022, R.drawable.reindeer_swiperight0023,
+ R.drawable.reindeer_swiperight0024), // swipe right
+ intArrayOf(R.drawable.reindeer_pinchout0001, R.drawable.reindeer_pinchout0002,
+ R.drawable.reindeer_pinchout0003, R.drawable.reindeer_pinchout0004,
+ R.drawable.reindeer_pinchout0005, R.drawable.reindeer_pinchout0006,
+ R.drawable.reindeer_pinchout0007, R.drawable.reindeer_pinchout0008,
+ R.drawable.reindeer_pinchout0009, R.drawable.reindeer_pinchout0010,
+ R.drawable.reindeer_pinchout0011, R.drawable.reindeer_pinchout0012,
+ R.drawable.reindeer_pinchout0013, R.drawable.reindeer_pinchout0014,
+ R.drawable.reindeer_pinchout0015, R.drawable.reindeer_pinchout0016,
+ R.drawable.reindeer_pinchout0017, R.drawable.reindeer_pinchout0018,
+ R.drawable.reindeer_pinchout0019, R.drawable.reindeer_pinchout0020,
+ R.drawable.reindeer_pinchout0021, R.drawable.reindeer_pinchout0022,
+ R.drawable.reindeer_pinchout0023,
+ R.drawable.reindeer_pinchout0024), // pinch in
+ intArrayOf(R.drawable.reindeer_pinchin0001, R.drawable.reindeer_pinchin0002,
+ R.drawable.reindeer_pinchin0003, R.drawable.reindeer_pinchin0004,
+ R.drawable.reindeer_pinchin0005, R.drawable.reindeer_pinchin0006,
+ R.drawable.reindeer_pinchin0007, R.drawable.reindeer_pinchin0007,
+ R.drawable.reindeer_pinchin0007, R.drawable.reindeer_pinchin0007,
+ R.drawable.reindeer_pinchin0007, R.drawable.reindeer_pinchin0007,
+ R.drawable.reindeer_pinchin0007, R.drawable.reindeer_pinchin0007,
+ R.drawable.reindeer_pinchin0007, R.drawable.reindeer_pinchin0007,
+ R.drawable.reindeer_pinchin0007, R.drawable.reindeer_pinchin0018,
+ R.drawable.reindeer_pinchin0019, R.drawable.reindeer_pinchin0020,
+ R.drawable.reindeer_pinchin0021, R.drawable.reindeer_pinchin0022,
+ R.drawable.reindeer_pinchin0023,
+ R.drawable.reindeer_pinchin0001) // pinch in
+ )
+
+ private val frameIndices = arrayOf(intArrayOf(0), // idle
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23), // tap
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23), // shake
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23), // swipe down
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22), // swipe up
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23), // swipe left
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22), // swipe right
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23), // pinch in
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23) // pinch out
+ )
+ }
+}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/ResourceOffsets.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/ResourceOffsets.kt
new file mode 100644
index 000000000..30d2e9eef
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/ResourceOffsets.kt
@@ -0,0 +1,810 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.annotation.SuppressLint
+import android.graphics.Point
+import androidx.annotation.DrawableRes
+import java.util.HashMap
+
+class ResourceOffsets {
+
+ companion object {
+
+ @SuppressLint("UseSparseArrays")
+ private val offsets = HashMap()
+
+ init {
+ offsets[R.drawable.elf_pinchout_0006] = Point(0, 0)
+ offsets[R.drawable.snowman_swiperight0015] = Point(429, 221)
+ offsets[R.drawable.reindeer_swipedown0018] = Point(365, 709)
+ offsets[R.drawable.elf_shake_0006] = Point(318, 230)
+ offsets[R.drawable.reindeer_swipeleft0002] = Point(341, 331)
+ offsets[R.drawable.reindeer_pinchout0024] = Point(342, 337)
+ offsets[R.drawable.snowman_swipeup0023] = Point(429, 220)
+ offsets[R.drawable.snowman_pinchout0001] = Point(429, 221)
+ offsets[R.drawable.snowman_pinchout0022] = Point(334, 310)
+ offsets[R.drawable.reindeer_swipedown0008] = Point(365, 705)
+ offsets[R.drawable.santa_pinchin0007] = Point(136, 218)
+ offsets[R.drawable.snowman_swipedown0021] = Point(429, 250)
+ offsets[R.drawable.santa_idle0021] = Point(415, 434)
+ offsets[R.drawable.santa_pinchout20001] = Point(0, 0)
+ offsets[R.drawable.reindeer_swipedown0009] = Point(376, 709)
+ offsets[R.drawable.snowman_pinchin0001] = Point(429, 221)
+ offsets[R.drawable.snowman_pinchout0005] = Point(360, 434)
+ offsets[R.drawable.santa_swipeleft0017] = Point(147, 628)
+ offsets[R.drawable.reindeer_swipeup0013] = Point(210, 37)
+ offsets[R.drawable.snowman_pinchin0012] = Point(90, 806)
+ offsets[R.drawable.santa_swipeleft0009] = Point(94, 606)
+ offsets[R.drawable.snowman_swipeleft0007] = Point(429, 221)
+ offsets[R.drawable.santa_idle0027] = Point(415, 432)
+ offsets[R.drawable.snowman_tap0017] = Point(94, 221)
+ offsets[R.drawable.santa_temp_tap01] = Point(415, 435)
+ offsets[R.drawable.elf_swipeleft_0023] = Point(435, 358)
+ offsets[R.drawable.reindeer_swipeleft0019] = Point(384, 347)
+ offsets[R.drawable.snowman_pinchin0009] = Point(90, 422)
+ offsets[R.drawable.elf_idle_0007] = Point(435, 437)
+ offsets[R.drawable.snowman_idle0002] = Point(429, 220)
+ offsets[R.drawable.reindeer_tap0008] = Point(342, 337)
+ offsets[R.drawable.santa_swipe_right20005] = Point(350, 423)
+ offsets[R.drawable.snowman_pinchout0003] = Point(395, 339)
+ offsets[R.drawable.reindeer_pinchout0018] = Point(98, 37)
+ offsets[R.drawable.snowman_swipeleft0004] = Point(429, 221)
+ offsets[R.drawable.santa_idle0007] = Point(416, 430)
+ offsets[R.drawable.snowman_swipeup0022] = Point(429, 219)
+ offsets[R.drawable.santa_shake0005] = Point(229, 475)
+ offsets[R.drawable.santa_swipeup0016] = Point(253, 221)
+ offsets[R.drawable.snowman_tap0019] = Point(102, 221)
+ offsets[R.drawable.santa_swipeup0023] = Point(427, 427)
+ offsets[R.drawable.reindeer_pinchin0023] = Point(0, 0)
+ offsets[R.drawable.snowman_swiperight0005] = Point(314, 221)
+ offsets[R.drawable.elf_shake_0016] = Point(285, 309)
+ offsets[R.drawable.reindeer_swipeup0016] = Point(240, 73)
+ offsets[R.drawable.reindeer_swipedown0023] = Point(344, 351)
+ offsets[R.drawable.reindeer_swipeup0010] = Point(210, 34)
+ offsets[R.drawable.reindeer_swipedown0007] = Point(375, 595)
+ offsets[R.drawable.reindeer_pinchin0003] = Point(0, 0)
+ offsets[R.drawable.santa_shake0010] = Point(241, 468)
+ offsets[R.drawable.snowman_swipeleft0011] = Point(429, 221)
+ offsets[R.drawable.elf_tap_0018] = Point(435, 440)
+ offsets[R.drawable.santa_swipeup0001] = Point(415, 435)
+ offsets[R.drawable.elf_idle_0012] = Point(435, 436)
+ offsets[R.drawable.snowman_swiperight0008] = Point(271, 221)
+ offsets[R.drawable.elf_idle_0002] = Point(435, 440)
+ offsets[R.drawable.snowman_pinchin0010] = Point(90, 513)
+ offsets[R.drawable.elf_swiperight_0011] = Point(1073, 707)
+ offsets[R.drawable.santa_shake0003] = Point(279, 476)
+ offsets[R.drawable.elf_swipeleft_0012] = Point(294, 460)
+ offsets[R.drawable.elf_tap_0017] = Point(429, 436)
+ offsets[R.drawable.elf_pinchin_0008] = Point(520, 914)
+ offsets[R.drawable.snowman_swipeup0003] = Point(429, 182)
+ offsets[R.drawable.santa_swipeleft0013] = Point(429, 608)
+ offsets[R.drawable.snowman_pinchout0020] = Point(237, 580)
+ offsets[R.drawable.reindeer_shake0018] = Point(384, 13)
+ offsets[R.drawable.snowman_swipeleft0001] = Point(429, 221)
+ offsets[R.drawable.reindeer_swipedown0005] = Point(381, 451)
+ offsets[R.drawable.reindeer_shake0021] = Point(384, 206)
+ offsets[R.drawable.snowman_idle0020] = Point(429, 218)
+ offsets[R.drawable.reindeer_tap0022] = Point(342, 337)
+ offsets[R.drawable.snowman_swipedown0020] = Point(429, 279)
+ offsets[R.drawable.snowman_shake0005] = Point(115, 0)
+ offsets[R.drawable.snowman_swipeup0012] = Point(429, 21)
+ offsets[R.drawable.santa_shake0013] = Point(363, 426)
+ offsets[R.drawable.elf_pinchin_0001] = Point(435, 440)
+ offsets[R.drawable.snowman_idle0022] = Point(429, 219)
+ offsets[R.drawable.reindeer_swipeleft0021] = Point(370, 339)
+ offsets[R.drawable.santa_pinchin0017] = Point(270, 435)
+ offsets[R.drawable.elf_swiperight_0020] = Point(252, 504)
+ offsets[R.drawable.elf_tap_0005] = Point(347, 380)
+ offsets[R.drawable.snowman_pinchin0008] = Point(90, 367)
+ offsets[R.drawable.snowman_idle0011] = Point(429, 217)
+ offsets[R.drawable.reindeer_pinchin0018] = Point(0, 0)
+ offsets[R.drawable.reindeer_swipeup0015] = Point(218, 46)
+ offsets[R.drawable.santa_idle0032] = Point(416, 429)
+ offsets[R.drawable.elf_pinchout_0020] = Point(106, 0)
+ offsets[R.drawable.snowman_swipeup0007] = Point(427, 21)
+ offsets[R.drawable.snowman_swipedown0013] = Point(429, 442)
+ offsets[R.drawable.snowman_swipedown0018] = Point(429, 212)
+ offsets[R.drawable.santa_pinchin0009] = Point(96, 154)
+ offsets[R.drawable.snowman_pinchin0005] = Point(55, 0)
+ offsets[R.drawable.santa_idle0017] = Point(415, 432)
+ offsets[R.drawable.santa_swipeleft0007] = Point(165, 589)
+ offsets[R.drawable.santa_idle0011] = Point(416, 429)
+ offsets[R.drawable.reindeer_swipeleft0010] = Point(282, 280)
+ offsets[R.drawable.reindeer_shake0013] = Point(383, 20)
+ offsets[R.drawable.elf_shake_0023] = Point(435, 471)
+ offsets[R.drawable.snowman_swipeup0008] = Point(429, 21)
+ offsets[R.drawable.santa_swipedown0007] = Point(429, 635)
+ offsets[R.drawable.reindeer_swipeleft0003] = Point(338, 311)
+ offsets[R.drawable.santa_pinchout20004] = Point(0, 0)
+ offsets[R.drawable.elf_swipeup_0011] = Point(378, 6)
+ offsets[R.drawable.reindeer_tap0003] = Point(350, 341)
+ offsets[R.drawable.santa_swipeleft0004] = Point(314, 530)
+ offsets[R.drawable.elf_idle_0001] = Point(435, 440)
+ offsets[R.drawable.elf_idle_0006] = Point(435, 437)
+ offsets[R.drawable.elf_shake_0002] = Point(319, 369)
+ offsets[R.drawable.elf_tap_0010] = Point(100, 262)
+ offsets[R.drawable.reindeer_tap0020] = Point(342, 337)
+ offsets[R.drawable.santa_tap0008] = Point(270, 596)
+ offsets[R.drawable.reindeer_swipedown0013] = Point(360, 709)
+ offsets[R.drawable.reindeer_swipeup0020] = Point(334, 368)
+ offsets[R.drawable.snowman_swiperight0009] = Point(139, 221)
+ offsets[R.drawable.elf_pinchin_0016] = Point(515, 127)
+ offsets[R.drawable.reindeer_swiperight0012] = Point(0, 1069)
+ offsets[R.drawable.reindeer_swipedown0017] = Point(363, 709)
+ offsets[R.drawable.reindeer_swipeup0007] = Point(327, 105)
+ offsets[R.drawable.elf_swipedown_0005] = Point(435, 454)
+ offsets[R.drawable.reindeer_swiperight0008] = Point(205, 660)
+ offsets[R.drawable.reindeer_shake0016] = Point(383, 17)
+ offsets[R.drawable.reindeer_shake0008] = Point(384, 23)
+ offsets[R.drawable.elf_swipeleft_0024] = Point(435, 363)
+ offsets[R.drawable.santa_shake0015] = Point(332, 421)
+ offsets[R.drawable.reindeer_swiperight0016] = Point(211, 335)
+ offsets[R.drawable.santa_shake0014] = Point(367, 422)
+ offsets[R.drawable.elf_swipeup_0003] = Point(386, 360)
+ offsets[R.drawable.elf_tap_0011] = Point(81, 270)
+ offsets[R.drawable.santa_temp_left01] = Point(415, 435)
+ offsets[R.drawable.elf_swipedown_0018] = Point(435, 469)
+ offsets[R.drawable.santa_idle0031] = Point(416, 430)
+ offsets[R.drawable.elf_swipeup_0006] = Point(476, 165)
+ offsets[R.drawable.elf_swiperight_0022] = Point(435, 459)
+ offsets[R.drawable.snowman_swipeleft0003] = Point(429, 221)
+ offsets[R.drawable.elf_swipeup_0005] = Point(475, 262)
+ offsets[R.drawable.snowman_pinchout0006] = Point(342, 473)
+ offsets[R.drawable.elf_swipeleft_0022] = Point(435, 352)
+ offsets[R.drawable.elf_idle_0021] = Point(435, 438)
+ offsets[R.drawable.santa_swipeup0003] = Point(423, 402)
+ offsets[R.drawable.snowman_shake0001] = Point(393, 221)
+ offsets[R.drawable.reindeer_swipeleft0007] = Point(301, 225)
+ offsets[R.drawable.snowman_swipeleft0024] = Point(429, 221)
+ offsets[R.drawable.snowman_tap0013] = Point(79, 221)
+ offsets[R.drawable.santa_idle0029] = Point(415, 431)
+ offsets[R.drawable.santa_idle0041] = Point(415, 433)
+ offsets[R.drawable.snowman_swiperight0006] = Point(139, 221)
+ offsets[R.drawable.reindeer_swipedown0010] = Point(383, 709)
+ offsets[R.drawable.santa_shake0023] = Point(351, 426)
+ offsets[R.drawable.santa_swipedown0021] = Point(0, 159)
+ offsets[R.drawable.snowman_idle0018] = Point(429, 218)
+ offsets[R.drawable.reindeer_swipeleft0013] = Point(301, 324)
+ offsets[R.drawable.reindeer_pinchout0004] = Point(331, 324)
+ offsets[R.drawable.elf_pinchin_0014] = Point(520, 134)
+ offsets[R.drawable.snowman_pinchin0006] = Point(35, 64)
+ offsets[R.drawable.santa_swipedown0023] = Point(0, 435)
+ offsets[R.drawable.santa_shake0021] = Point(344, 421)
+ offsets[R.drawable.santa_swipe_right20020] = Point(401, 435)
+ offsets[R.drawable.snowman_shake0010] = Point(100, 0)
+ offsets[R.drawable.elf_swipedown_0012] = Point(396, 611)
+ offsets[R.drawable.elf_swipedown_0009] = Point(400, 535)
+ offsets[R.drawable.reindeer_pinchout0015] = Point(84, 20)
+ offsets[R.drawable.reindeer_shake0014] = Point(384, 30)
+ offsets[R.drawable.elf_swipeleft_0013] = Point(269, 460)
+ offsets[R.drawable.reindeer_shake0002] = Point(357, 301)
+ offsets[R.drawable.snowman_swipeup0013] = Point(415, 21)
+ offsets[R.drawable.santa_shake0022] = Point(279, 422)
+ offsets[R.drawable.santa_shake0017] = Point(377, 420)
+ offsets[R.drawable.santa_pinchin0005] = Point(215, 347)
+ offsets[R.drawable.snowman_swipeleft0005] = Point(429, 221)
+ offsets[R.drawable.elf_swipeup_0012] = Point(378, 119)
+ offsets[R.drawable.santa_tap0011] = Point(270, 443)
+ offsets[R.drawable.snowman_idle0009] = Point(429, 217)
+ offsets[R.drawable.santa_tap0012] = Point(269, 443)
+ offsets[R.drawable.snowman_swipeleft0006] = Point(429, 221)
+ offsets[R.drawable.snowman_shake0002] = Point(130, 0)
+ offsets[R.drawable.reindeer_swiperight0018] = Point(363, 338)
+ offsets[R.drawable.santa_shake0019] = Point(341, 420)
+ offsets[R.drawable.elf_shake_0021] = Point(228, 236)
+ offsets[R.drawable.snowman_idle0017] = Point(429, 217)
+ offsets[R.drawable.snowman_swiperight0007] = Point(191, 221)
+ offsets[R.drawable.santa_swipedown0018] = Point(0, 0)
+ offsets[R.drawable.snowman_tap0022] = Point(118, 221)
+ offsets[R.drawable.snowman_swiperight0003] = Point(224, 221)
+ offsets[R.drawable.elf_swipedown_0003] = Point(435, 414)
+ offsets[R.drawable.snowman_swipeup0005] = Point(429, 70)
+ offsets[R.drawable.snowman_swipedown0006] = Point(253, 447)
+ offsets[R.drawable.snowman_pinchin0004] = Point(22, 0)
+ offsets[R.drawable.snowman_swiperight0001] = Point(429, 221)
+ offsets[R.drawable.santa_swipedown0010] = Point(429, 635)
+ offsets[R.drawable.reindeer_swiperight0003] = Point(344, 337)
+ offsets[R.drawable.elf_tap_0008] = Point(175, 254)
+ offsets[R.drawable.snowman_swipeup0011] = Point(429, 21)
+ offsets[R.drawable.santa_swipedown0006] = Point(429, 635)
+ offsets[R.drawable.santa_idle0036] = Point(416, 429)
+ offsets[R.drawable.snowman_swiperight0017] = Point(429, 221)
+ offsets[R.drawable.snowman_swipedown0012] = Point(425, 350)
+ offsets[R.drawable.santa_swipedown0005] = Point(429, 610)
+ offsets[R.drawable.santa_idle0016] = Point(415, 432)
+ offsets[R.drawable.snowman_shake0017] = Point(72, 0)
+ offsets[R.drawable.elf_pinchin_0024] = Point(520, 518)
+ offsets[R.drawable.snowman_swipedown0007] = Point(226, 419)
+ offsets[R.drawable.reindeer_pinchout0021] = Point(183, 142)
+ offsets[R.drawable.reindeer_pinchin0022] = Point(0, 0)
+ offsets[R.drawable.santa_swipedown0008] = Point(429, 635)
+ offsets[R.drawable.elf_tap_0015] = Point(382, 398)
+ offsets[R.drawable.reindeer_pinchout0003] = Point(339, 334)
+ offsets[R.drawable.reindeer_swipeleft0022] = Point(353, 338)
+ offsets[R.drawable.elf_shake_0011] = Point(343, 183)
+ offsets[R.drawable.elf_swiperight_0002] = Point(423, 441)
+ offsets[R.drawable.reindeer_swipeup0006] = Point(353, 154)
+ offsets[R.drawable.elf_tap_0016] = Point(412, 422)
+ offsets[R.drawable.santa_temp_shake01] = Point(415, 435)
+ offsets[R.drawable.elf_swipeup_0021] = Point(435, 480)
+ offsets[R.drawable.elf_idle_0009] = Point(435, 437)
+ offsets[R.drawable.elf_swipedown_0016] = Point(433, 561)
+ offsets[R.drawable.santa_pinchout20006] = Point(0, 0)
+ offsets[R.drawable.santa_pinchout20020] = Point(0, 0)
+ offsets[R.drawable.reindeer_pinchout0007] = Point(276, 255)
+ offsets[R.drawable.snowman_idle0003] = Point(429, 219)
+ offsets[R.drawable.elf_swipeleft_0019] = Point(432, 393)
+ offsets[R.drawable.reindeer_pinchout0016] = Point(82, 17)
+ offsets[R.drawable.santa_idle0040] = Point(415, 432)
+ offsets[R.drawable.elf_swiperight_0017] = Point(0, 606)
+ offsets[R.drawable.snowman_swiperight0011] = Point(330, 221)
+ offsets[R.drawable.santa_idle0001] = Point(415, 435)
+ offsets[R.drawable.snowman_tap0004] = Point(245, 227)
+ offsets[R.drawable.elf_tap_0013] = Point(286, 324)
+ offsets[R.drawable.elf_shake_0012] = Point(318, 233)
+ offsets[R.drawable.snowman_swipedown0016] = Point(422, 13)
+ offsets[R.drawable.reindeer_pinchin0004] = Point(0, 0)
+ offsets[R.drawable.santa_swipeup0005] = Point(429, 375)
+ offsets[R.drawable.snowman_shake0003] = Point(126, 21)
+ offsets[R.drawable.elf_pinchout_0004] = Point(0, 0)
+ offsets[R.drawable.reindeer_swipedown0004] = Point(364, 401)
+ offsets[R.drawable.reindeer_pinchout0023] = Point(281, 262)
+ offsets[R.drawable.santa_swipeleft0018] = Point(216, 579)
+ offsets[R.drawable.reindeer_shake0004] = Point(383, 13)
+ offsets[R.drawable.santa_swipe_right20001] = Point(415, 435)
+ offsets[R.drawable.santa_swipe_right20021] = Point(389, 435)
+ offsets[R.drawable.santa_swipeleft0014] = Point(429, 508)
+ offsets[R.drawable.elf_shake_0018] = Point(279, 233)
+ offsets[R.drawable.santa_idle0003] = Point(415, 433)
+ offsets[R.drawable.santa_swipeup0018] = Point(317, 317)
+ offsets[R.drawable.elf_idle_0010] = Point(435, 436)
+ offsets[R.drawable.snowman_pinchin0024] = Point(401, 220)
+ offsets[R.drawable.snowman_swiperight0016] = Point(429, 221)
+ offsets[R.drawable.snowman_pinchin0007] = Point(35, 64)
+ offsets[R.drawable.reindeer_pinchin0020] = Point(0, 0)
+ offsets[R.drawable.elf_swipedown_0015] = Point(400, 605)
+ offsets[R.drawable.elf_tap_0014] = Point(337, 366)
+ offsets[R.drawable.elf_tap_0006] = Point(290, 333)
+ offsets[R.drawable.elf_swiperight_0023] = Point(423, 440)
+ offsets[R.drawable.santa_swipe_right20023] = Point(415, 435)
+ offsets[R.drawable.snowman_tap0002] = Point(381, 227)
+ offsets[R.drawable.santa_swipedown0022] = Point(0, 414)
+ offsets[R.drawable.santa_swipe_right20017] = Point(415, 385)
+ offsets[R.drawable.elf_pinchin_0012] = Point(519, 270)
+ offsets[R.drawable.santa_idle0008] = Point(416, 430)
+ offsets[R.drawable.snowman_idle0001] = Point(429, 221)
+ offsets[R.drawable.reindeer_pinchout0010] = Point(177, 135)
+ offsets[R.drawable.reindeer_swipeup0019] = Point(349, 266)
+ offsets[R.drawable.santa_tap0022] = Point(358, 435)
+ offsets[R.drawable.santa_swipeup0012] = Point(417, 213)
+ offsets[R.drawable.snowman_idle0019] = Point(429, 218)
+ offsets[R.drawable.elf_swipedown_0023] = Point(435, 460)
+ offsets[R.drawable.elf_pinchin_0025] = Point(476, 280)
+ offsets[R.drawable.santa_swipe_right20009] = Point(332, 416)
+ offsets[R.drawable.santa_idle0038] = Point(415, 431)
+ offsets[R.drawable.snowman_pinchout0021] = Point(285, 423)
+ offsets[R.drawable.santa_swipeup0022] = Point(420, 438)
+ offsets[R.drawable.elf_pinchin_0007] = Point(497, 828)
+ offsets[R.drawable.reindeer_shake0023] = Point(342, 346)
+ offsets[R.drawable.snowman_idle0023] = Point(429, 220)
+ offsets[R.drawable.snowman_swiperight0012] = Point(399, 221)
+ offsets[R.drawable.reindeer_pinchout0017] = Point(86, 22)
+ offsets[R.drawable.reindeer_swipedown0001] = Point(342, 337)
+ offsets[R.drawable.snowman_pinchin0021] = Point(182, 191)
+ offsets[R.drawable.snowman_swipeup0020] = Point(429, 221)
+ offsets[R.drawable.reindeer_shake0019] = Point(384, 34)
+ offsets[R.drawable.elf_swipeleft_0009] = Point(391, 460)
+ offsets[R.drawable.snowman_tap0016] = Point(90, 221)
+ offsets[R.drawable.elf_shake_0004] = Point(228, 236)
+ offsets[R.drawable.snowman_tap0020] = Point(105, 221)
+ offsets[R.drawable.elf_pinchout_0022] = Point(464, 489)
+ offsets[R.drawable.santa_swipedown0011] = Point(345, 613)
+ offsets[R.drawable.elf_pinchin_0029] = Point(404, 450)
+ offsets[R.drawable.elf_shake_0013] = Point(201, 285)
+ offsets[R.drawable.santa_swipeup0007] = Point(429, 304)
+ offsets[R.drawable.snowman_idle0016] = Point(429, 217)
+ offsets[R.drawable.santa_swipe_right20010] = Point(312, 437)
+ offsets[R.drawable.reindeer_swipeup0018] = Point(329, 183)
+ offsets[R.drawable.reindeer_tap0010] = Point(342, 337)
+ offsets[R.drawable.elf_swipedown_0001] = Point(435, 440)
+ offsets[R.drawable.elf_swipeup_0020] = Point(404, 450)
+ offsets[R.drawable.elf_pinchout_0023] = Point(459, 480)
+ offsets[R.drawable.santa_pinchin0018] = Point(235, 505)
+ offsets[R.drawable.reindeer_pinchin0019] = Point(0, 0)
+ offsets[R.drawable.santa_shake0006] = Point(245, 474)
+ offsets[R.drawable.snowman_shake0019] = Point(74, 0)
+ offsets[R.drawable.santa_idle0019] = Point(415, 434)
+ offsets[R.drawable.snowman_swipedown0011] = Point(394, 381)
+ offsets[R.drawable.snowman_pinchin0020] = Point(167, 189)
+ offsets[R.drawable.santa_idle0043] = Point(415, 434)
+ offsets[R.drawable.snowman_swipeleft0013] = Point(415, 221)
+ offsets[R.drawable.reindeer_swipeup0023] = Point(193, 338)
+ offsets[R.drawable.elf_swiperight_0003] = Point(435, 425)
+ offsets[R.drawable.reindeer_swipedown0014] = Point(343, 709)
+ offsets[R.drawable.santa_swipeleft0020] = Point(351, 467)
+ offsets[R.drawable.snowman_swipeleft0023] = Point(429, 221)
+ offsets[R.drawable.reindeer_swipeup0021] = Point(268, 354)
+ offsets[R.drawable.snowman_tap0009] = Point(79, 221)
+ offsets[R.drawable.elf_shake_0009] = Point(201, 285)
+ offsets[R.drawable.santa_swipeleft0003] = Point(374, 516)
+ offsets[R.drawable.snowman_swipeleft0022] = Point(429, 221)
+ offsets[R.drawable.santa_tap0015] = Point(270, 412)
+ offsets[R.drawable.snowman_pinchout0002] = Point(412, 283)
+ offsets[R.drawable.elf_swipedown_0010] = Point(397, 556)
+ offsets[R.drawable.elf_pinchin_0011] = Point(521, 426)
+ offsets[R.drawable.reindeer_swipedown0012] = Point(378, 709)
+ offsets[R.drawable.santa_pinchin0002] = Point(358, 435)
+ offsets[R.drawable.reindeer_tap0004] = Point(346, 339)
+ offsets[R.drawable.snowman_shake0015] = Point(83, 0)
+ offsets[R.drawable.santa_shake0016] = Point(322, 420)
+ offsets[R.drawable.snowman_pinchin0014] = Point(90, 1245)
+ offsets[R.drawable.reindeer_swiperight0023] = Point(330, 341)
+ offsets[R.drawable.santa_pinchin0019] = Point(224, 529)
+ offsets[R.drawable.reindeer_swipeleft0018] = Point(384, 355)
+ offsets[R.drawable.reindeer_shake0015] = Point(384, 23)
+ offsets[R.drawable.snowman_pinchin0011] = Point(90, 641)
+ offsets[R.drawable.santa_swipe_right20011] = Point(412, 394)
+ offsets[R.drawable.santa_pinchin0004] = Point(270, 435)
+ offsets[R.drawable.snowman_shake0021] = Point(68, 11)
+ offsets[R.drawable.reindeer_swipeleft0012] = Point(291, 300)
+ offsets[R.drawable.santa_swipeup0006] = Point(429, 334)
+ offsets[R.drawable.reindeer_pinchout0006] = Point(299, 285)
+ offsets[R.drawable.santa_pinchin0001] = Point(415, 435)
+ offsets[R.drawable.santa_swipeup0020] = Point(425, 462)
+ offsets[R.drawable.elf_swipeleft_0007] = Point(362, 460)
+ offsets[R.drawable.snowman_tap0015] = Point(87, 221)
+ offsets[R.drawable.elf_swiperight_0007] = Point(506, 517)
+ offsets[R.drawable.elf_swipeup_0016] = Point(476, 200)
+ offsets[R.drawable.elf_swipeleft_0020] = Point(435, 389)
+ offsets[R.drawable.santa_swipedown0009] = Point(429, 635)
+ offsets[R.drawable.santa_swipe_right20002] = Point(420, 435)
+ offsets[R.drawable.elf_swipeleft_0015] = Point(369, 460)
+ offsets[R.drawable.elf_swipeleft_0002] = Point(414, 441)
+ offsets[R.drawable.elf_swipeleft_0008] = Point(393, 460)
+ offsets[R.drawable.santa_tap0019] = Point(270, 423)
+ offsets[R.drawable.elf_pinchout_0007] = Point(0, 0)
+ offsets[R.drawable.snowman_swiperight0018] = Point(429, 221)
+ offsets[R.drawable.elf_pinchin_0006] = Point(487, 762)
+ offsets[R.drawable.snowman_pinchout0011] = Point(255, 577)
+ offsets[R.drawable.snowman_swiperight0022] = Point(417, 221)
+ offsets[R.drawable.reindeer_swiperight0021] = Point(325, 361)
+ offsets[R.drawable.snowman_idle0007] = Point(429, 217)
+ offsets[R.drawable.santa_swipedown0013] = Point(266, 0)
+ offsets[R.drawable.santa_pinchout20002] = Point(0, 0)
+ offsets[R.drawable.santa_swipeup0019] = Point(422, 428)
+ offsets[R.drawable.snowman_swipeleft0016] = Point(429, 221)
+ offsets[R.drawable.elf_swipeup_0004] = Point(435, 200)
+ offsets[R.drawable.santa_swipeleft0006] = Point(209, 565)
+ offsets[R.drawable.santa_idle0005] = Point(415, 431)
+ offsets[R.drawable.reindeer_swipeup0014] = Point(210, 37)
+ offsets[R.drawable.elf_shake_0010] = Point(285, 309)
+ offsets[R.drawable.reindeer_swipeleft0008] = Point(290, 260)
+ offsets[R.drawable.snowman_swipeup0016] = Point(219, 21)
+ offsets[R.drawable.reindeer_swipeup0003] = Point(342, 275)
+ offsets[R.drawable.reindeer_swiperight0009] = Point(121, 685)
+ offsets[R.drawable.reindeer_swiperight0017] = Point(249, 332)
+ offsets[R.drawable.elf_swipeup_0015] = Point(476, 311)
+ offsets[R.drawable.elf_swipeup_0013] = Point(397, 259)
+ offsets[R.drawable.santa_shake0024] = Point(355, 435)
+ offsets[R.drawable.santa_shake0002] = Point(328, 456)
+ offsets[R.drawable.reindeer_swipeleft0004] = Point(333, 279)
+ offsets[R.drawable.snowman_shake0016] = Point(76, 0)
+ offsets[R.drawable.santa_swipedown0014] = Point(262, 0)
+ offsets[R.drawable.reindeer_swipedown0019] = Point(384, 601)
+ offsets[R.drawable.elf_pinchin_0031] = Point(435, 458)
+ offsets[R.drawable.santa_idle0046] = Point(415, 435)
+ offsets[R.drawable.elf_pinchin_0020] = Point(520, 898)
+ offsets[R.drawable.santa_tap0005] = Point(270, 509)
+ offsets[R.drawable.santa_idle0009] = Point(416, 429)
+ offsets[R.drawable.santa_temp_down01] = Point(415, 435)
+ offsets[R.drawable.elf_pinchout_0019] = Point(50, 0)
+ offsets[R.drawable.snowman_tap0006] = Point(146, 221)
+ offsets[R.drawable.elf_swiperight_0021] = Point(427, 451)
+ offsets[R.drawable.santa_swipeup0021] = Point(399, 471)
+ offsets[R.drawable.elf_idle_0019] = Point(435, 438)
+ offsets[R.drawable.elf_swiperight_0010] = Point(888, 568)
+ offsets[R.drawable.reindeer_swipedown0021] = Point(371, 437)
+ offsets[R.drawable.snowman_swipeleft0019] = Point(429, 221)
+ offsets[R.drawable.reindeer_shake0020] = Point(384, 99)
+ offsets[R.drawable.snowman_tap0008] = Point(79, 221)
+ offsets[R.drawable.santa_idle0020] = Point(415, 434)
+ offsets[R.drawable.snowman_tap0024] = Point(429, 221)
+ offsets[R.drawable.snowman_swipeup0004] = Point(429, 133)
+ offsets[R.drawable.reindeer_swipeleft0001] = Point(342, 337)
+ offsets[R.drawable.snowman_shake0007] = Point(108, 0)
+ offsets[R.drawable.santa_swipeleft0015] = Point(415, 416)
+ offsets[R.drawable.elf_tap_0012] = Point(221, 272)
+ offsets[R.drawable.elf_pinchout_0003] = Point(250, 0)
+ offsets[R.drawable.reindeer_shake0022] = Point(342, 357)
+ offsets[R.drawable.reindeer_shake0005] = Point(384, 13)
+ offsets[R.drawable.snowman_swipeleft0021] = Point(429, 221)
+ offsets[R.drawable.reindeer_swipedown0006] = Point(384, 516)
+ offsets[R.drawable.elf_swiperight_0018] = Point(0, 538)
+ offsets[R.drawable.elf_idle_0008] = Point(435, 437)
+ offsets[R.drawable.reindeer_swipeup0017] = Point(277, 119)
+ offsets[R.drawable.elf_pinchin_0022] = Point(513, 738)
+ offsets[R.drawable.elf_swipeup_0018] = Point(454, 400)
+ offsets[R.drawable.santa_swipeup0010] = Point(429, 266)
+ offsets[R.drawable.snowman_pinchout0009] = Point(290, 553)
+ offsets[R.drawable.elf_pinchin_0010] = Point(521, 653)
+ offsets[R.drawable.snowman_tap0011] = Point(79, 221)
+ offsets[R.drawable.elf_swipeleft_0006] = Point(330, 460)
+ offsets[R.drawable.elf_swipeleft_0004] = Point(372, 441)
+ offsets[R.drawable.snowman_swiperight0020] = Point(429, 221)
+ offsets[R.drawable.reindeer_swiperight0015] = Point(0, 335)
+ offsets[R.drawable.snowman_shake0008] = Point(110, 0)
+ offsets[R.drawable.elf_swipeup_0009] = Point(357, 152)
+ offsets[R.drawable.elf_swipeup_0002] = Point(386, 400)
+ offsets[R.drawable.snowman_swipedown0010] = Point(335, 435)
+ offsets[R.drawable.santa_swipe_right20015] = Point(415, 353)
+ offsets[R.drawable.reindeer_swipeleft0023] = Point(344, 337)
+ offsets[R.drawable.santa_pinchout20003] = Point(0, 0)
+ offsets[R.drawable.snowman_swiperight0013] = Point(429, 221)
+ offsets[R.drawable.snowman_swipedown0015] = Point(429, 261)
+ offsets[R.drawable.snowman_swipeup0014] = Point(346, 21)
+ offsets[R.drawable.snowman_swipedown0008] = Point(207, 344)
+ offsets[R.drawable.reindeer_pinchout0012] = Point(124, 69)
+ offsets[R.drawable.santa_temp_zoom_in01] = Point(415, 435)
+ offsets[R.drawable.reindeer_pinchin0021] = Point(0, 0)
+ offsets[R.drawable.santa_tap0017] = Point(270, 423)
+ offsets[R.drawable.snowman_shake0006] = Point(110, 0)
+ offsets[R.drawable.reindeer_tap0006] = Point(342, 337)
+ offsets[R.drawable.elf_idle_0024] = Point(435, 440)
+ offsets[R.drawable.santa_swipeleft0005] = Point(258, 546)
+ offsets[R.drawable.elf_pinchin_0027] = Point(459, 400)
+ offsets[R.drawable.reindeer_tap0005] = Point(342, 337)
+ offsets[R.drawable.elf_swipedown_0020] = Point(435, 470)
+ offsets[R.drawable.elf_idle_0011] = Point(435, 436)
+ offsets[R.drawable.santa_swipedown0001] = Point(415, 435)
+ offsets[R.drawable.elf_shake_0008] = Point(318, 362)
+ offsets[R.drawable.reindeer_pinchout0022] = Point(228, 197)
+ offsets[R.drawable.reindeer_pinchout0014] = Point(92, 30)
+ offsets[R.drawable.snowman_swipedown0002] = Point(400, 266)
+ offsets[R.drawable.reindeer_swiperight0001] = Point(342, 337)
+ offsets[R.drawable.santa_swipedown0019] = Point(0, 0)
+ offsets[R.drawable.santa_swipeleft0024] = Point(429, 424)
+ offsets[R.drawable.reindeer_swiperight0005] = Point(354, 337)
+ offsets[R.drawable.santa_pinchout20023] = Point(0, 0)
+ offsets[R.drawable.snowman_swipeup0002] = Point(429, 211)
+ offsets[R.drawable.santa_idle0022] = Point(415, 435)
+ offsets[R.drawable.elf_swipeleft_0010] = Point(317, 460)
+ offsets[R.drawable.snowman_tap0007] = Point(95, 221)
+ offsets[R.drawable.santa_swipedown0002] = Point(358, 435)
+ offsets[R.drawable.santa_idle0018] = Point(415, 433)
+ offsets[R.drawable.reindeer_shake0010] = Point(383, 13)
+ offsets[R.drawable.santa_tap0014] = Point(270, 320)
+ offsets[R.drawable.santa_shake0020] = Point(386, 420)
+ offsets[R.drawable.snowman_swipeup0017] = Point(231, 33)
+ offsets[R.drawable.elf_swipeup_0023] = Point(435, 445)
+ offsets[R.drawable.elf_tap_0007] = Point(221, 272)
+ offsets[R.drawable.snowman_idle0021] = Point(429, 219)
+ offsets[R.drawable.elf_pinchin_0013] = Point(519, 169)
+ offsets[R.drawable.elf_pinchin_0018] = Point(506, 385)
+ offsets[R.drawable.santa_pinchin0006] = Point(171, 275)
+ offsets[R.drawable.reindeer_swipedown0015] = Point(349, 709)
+ offsets[R.drawable.santa_swipe_right20007] = Point(341, 418)
+ offsets[R.drawable.reindeer_swiperight0022] = Point(304, 370)
+ offsets[R.drawable.santa_swipeleft0002] = Point(398, 476)
+ offsets[R.drawable.santa_swipedown0004] = Point(340, 535)
+ offsets[R.drawable.reindeer_swipedown0016] = Point(357, 709)
+ offsets[R.drawable.snowman_swipedown0005] = Point(285, 401)
+ offsets[R.drawable.reindeer_tap0009] = Point(342, 337)
+ offsets[R.drawable.snowman_swipeup0021] = Point(429, 220)
+ offsets[R.drawable.elf_swipedown_0006] = Point(435, 475)
+ offsets[R.drawable.reindeer_swipeleft0011] = Point(284, 285)
+ offsets[R.drawable.snowman_shake0014] = Point(87, 3)
+ offsets[R.drawable.snowman_idle0006] = Point(429, 218)
+ offsets[R.drawable.santa_swipe_right20004] = Point(350, 428)
+ offsets[R.drawable.reindeer_swipeleft0005] = Point(326, 235)
+ offsets[R.drawable.snowman_idle0004] = Point(429, 219)
+ offsets[R.drawable.elf_shake_0001] = Point(435, 440)
+ offsets[R.drawable.elf_swipedown_0022] = Point(435, 463)
+ offsets[R.drawable.elf_swipeup_0017] = Point(456, 380)
+ offsets[R.drawable.snowman_pinchout0013] = Point(237, 580)
+ offsets[R.drawable.santa_swipeleft0016] = Point(299, 540)
+ offsets[R.drawable.snowman_pinchout0010] = Point(272, 568)
+ offsets[R.drawable.snowman_tap0003] = Point(277, 248)
+ offsets[R.drawable.santa_shake0001] = Point(355, 435)
+ offsets[R.drawable.elf_swiperight_0009] = Point(769, 641)
+ offsets[R.drawable.santa_swipe_right20016] = Point(415, 370)
+ offsets[R.drawable.santa_idle0010] = Point(416, 429)
+ offsets[R.drawable.elf_swiperight_0006] = Point(441, 476)
+ offsets[R.drawable.elf_swipeup_0007] = Point(492, 165)
+ offsets[R.drawable.elf_idle_0017] = Point(435, 437)
+ offsets[R.drawable.santa_swipeleft0008] = Point(127, 618)
+ offsets[R.drawable.santa_pinchout20021] = Point(0, 0)
+ offsets[R.drawable.santa_idle0013] = Point(416, 429)
+ offsets[R.drawable.snowman_swipedown0009] = Point(266, 281)
+ offsets[R.drawable.snowman_swipedown0014] = Point(429, 411)
+ offsets[R.drawable.elf_tap_0003] = Point(427, 434)
+ offsets[R.drawable.snowman_pinchin0003] = Point(193, 109)
+ offsets[R.drawable.santa_swipeleft0012] = Point(429, 558)
+ offsets[R.drawable.snowman_idle0005] = Point(429, 218)
+ offsets[R.drawable.snowman_idle0010] = Point(429, 217)
+ offsets[R.drawable.santa_swipedown0016] = Point(429, 402)
+ offsets[R.drawable.reindeer_swiperight0010] = Point(61, 1026)
+ offsets[R.drawable.snowman_pinchout0012] = Point(237, 580)
+ offsets[R.drawable.elf_idle_0005] = Point(435, 438)
+ offsets[R.drawable.reindeer_tap0002] = Point(346, 339)
+ offsets[R.drawable.elf_tap_0004] = Point(401, 413)
+ offsets[R.drawable.santa_idle0030] = Point(416, 430)
+ offsets[R.drawable.elf_pinchin_0023] = Point(521, 583)
+ offsets[R.drawable.reindeer_pinchin0001] = Point(0, 0)
+ offsets[R.drawable.reindeer_pinchout0009] = Point(212, 177)
+ offsets[R.drawable.reindeer_pinchout0001] = Point(342, 337)
+ offsets[R.drawable.santa_swipeleft0022] = Point(398, 448)
+ offsets[R.drawable.reindeer_swiperight0006] = Point(363, 644)
+ offsets[R.drawable.snowman_tap0010] = Point(79, 221)
+ offsets[R.drawable.elf_pinchout_0024] = Point(444, 455)
+ offsets[R.drawable.elf_pinchout_0001] = Point(435, 440)
+ offsets[R.drawable.santa_swipe_right20003] = Point(347, 435)
+ offsets[R.drawable.snowman_swipeleft0020] = Point(429, 221)
+ offsets[R.drawable.reindeer_shake0024] = Point(342, 339)
+ offsets[R.drawable.snowman_pinchin0022] = Point(226, 197)
+ offsets[R.drawable.snowman_shake0020] = Point(73, 5)
+ offsets[R.drawable.santa_tap0013] = Point(270, 412)
+ offsets[R.drawable.elf_swipeleft_0003] = Point(393, 440)
+ offsets[R.drawable.snowman_shake0024] = Point(382, 216)
+ offsets[R.drawable.santa_tap0007] = Point(270, 586)
+ offsets[R.drawable.snowman_shake0013] = Point(88, 0)
+ offsets[R.drawable.snowman_tap0021] = Point(118, 221)
+ offsets[R.drawable.elf_swipeup_0010] = Point(378, 84)
+ offsets[R.drawable.elf_swipedown_0011] = Point(397, 560)
+ offsets[R.drawable.snowman_pinchin0023] = Point(299, 207)
+ offsets[R.drawable.elf_swiperight_0019] = Point(83, 515)
+ offsets[R.drawable.reindeer_swipeup0008] = Point(210, 47)
+ offsets[R.drawable.snowman_tap0012] = Point(79, 221)
+ offsets[R.drawable.reindeer_swipeleft0015] = Point(338, 400)
+ offsets[R.drawable.elf_swiperight_0013] = Point(0, 730)
+ offsets[R.drawable.santa_idle0028] = Point(415, 431)
+ offsets[R.drawable.santa_pinchin0010] = Point(91, 146)
+ offsets[R.drawable.snowman_pinchin0002] = Point(374, 193)
+ offsets[R.drawable.elf_swipeup_0014] = Point(468, 315)
+ offsets[R.drawable.reindeer_swipeleft0020] = Point(384, 342)
+ offsets[R.drawable.elf_pinchin_0003] = Point(460, 584)
+ offsets[R.drawable.elf_pinchin_0021] = Point(500, 990)
+ offsets[R.drawable.reindeer_swipeleft0014] = Point(317, 357)
+ offsets[R.drawable.reindeer_tap0019] = Point(342, 337)
+ offsets[R.drawable.reindeer_swipeleft0017] = Point(376, 371)
+ offsets[R.drawable.santa_tap0010] = Point(270, 536)
+ offsets[R.drawable.reindeer_swiperight0019] = Point(384, 389)
+ offsets[R.drawable.elf_shake_0019] = Point(231, 285)
+ offsets[R.drawable.snowman_pinchin0016] = Point(167, 913)
+ offsets[R.drawable.elf_swipeleft_0001] = Point(435, 440)
+ offsets[R.drawable.snowman_shake0022] = Point(64, 16)
+ offsets[R.drawable.santa_shake0012] = Point(355, 435)
+ offsets[R.drawable.santa_pinchin0013] = Point(136, 219)
+ offsets[R.drawable.elf_swipeleft_0014] = Point(395, 460)
+ offsets[R.drawable.santa_swipeup0002] = Point(418, 418)
+ offsets[R.drawable.elf_swipedown_0008] = Point(434, 515)
+ offsets[R.drawable.elf_swipedown_0007] = Point(435, 495)
+ offsets[R.drawable.snowman_tap0001] = Point(429, 221)
+ offsets[R.drawable.snowman_pinchout0007] = Point(325, 506)
+ offsets[R.drawable.santa_idle0037] = Point(416, 430)
+ offsets[R.drawable.santa_swipedown0012] = Point(265, 264)
+ offsets[R.drawable.santa_idle0015] = Point(415, 431)
+ offsets[R.drawable.santa_pinchout20019] = Point(0, 0)
+ offsets[R.drawable.reindeer_swiperight0014] = Point(0, 335)
+ offsets[R.drawable.reindeer_swipeleft0006] = Point(318, 177)
+ offsets[R.drawable.santa_swipe_right20022] = Point(415, 435)
+ offsets[R.drawable.santa_swipedown0020] = Point(0, 0)
+ offsets[R.drawable.reindeer_tap0001] = Point(342, 337)
+ offsets[R.drawable.santa_swipeup0013] = Point(312, 193)
+ offsets[R.drawable.reindeer_pinchout0005] = Point(318, 308)
+ offsets[R.drawable.santa_shake0008] = Point(255, 477)
+ offsets[R.drawable.reindeer_swipeleft0016] = Point(353, 389)
+ offsets[R.drawable.snowman_swipeup0006] = Point(429, 33)
+ offsets[R.drawable.snowman_shake0012] = Point(91, 0)
+ offsets[R.drawable.elf_shake_0017] = Point(201, 183)
+ offsets[R.drawable.reindeer_swipedown0020] = Point(384, 510)
+ offsets[R.drawable.santa_idle0042] = Point(415, 433)
+ offsets[R.drawable.reindeer_pinchout0002] = Point(342, 337)
+ offsets[R.drawable.santa_idle0044] = Point(415, 434)
+ offsets[R.drawable.santa_idle0006] = Point(415, 431)
+ offsets[R.drawable.santa_swipeleft0019] = Point(429, 428)
+ offsets[R.drawable.reindeer_swipedown0011] = Point(384, 709)
+ offsets[R.drawable.elf_shake_0005] = Point(201, 183)
+ offsets[R.drawable.snowman_swipeleft0010] = Point(429, 221)
+ offsets[R.drawable.reindeer_shake0006] = Point(384, 14)
+ offsets[R.drawable.santa_tap0006] = Point(270, 557)
+ offsets[R.drawable.elf_pinchin_0002] = Point(447, 512)
+ offsets[R.drawable.elf_swiperight_0005] = Point(407, 458)
+ offsets[R.drawable.santa_idle0039] = Point(415, 431)
+ offsets[R.drawable.elf_swipeup_0019] = Point(434, 440)
+ offsets[R.drawable.elf_swipeleft_0011] = Point(295, 460)
+ offsets[R.drawable.reindeer_pinchout0008] = Point(246, 219)
+ offsets[R.drawable.snowman_shake0023] = Point(382, 216)
+ offsets[R.drawable.snowman_swiperight0021] = Point(429, 221)
+ offsets[R.drawable.elf_pinchin_0019] = Point(520, 618)
+ offsets[R.drawable.snowman_shake0004] = Point(122, 0)
+ offsets[R.drawable.reindeer_pinchout0011] = Point(148, 99)
+ offsets[R.drawable.santa_swipe_right20014] = Point(416, 340)
+ offsets[R.drawable.elf_pinchin_0015] = Point(515, 95)
+ offsets[R.drawable.santa_idle0002] = Point(415, 434)
+ offsets[R.drawable.santa_pinchout20007] = Point(0, 0)
+ offsets[R.drawable.santa_pinchin0014] = Point(170, 275)
+ offsets[R.drawable.santa_swipedown0003] = Point(340, 460)
+ offsets[R.drawable.snowman_pinchout0024] = Point(429, 221)
+ offsets[R.drawable.santa_shake0009] = Point(243, 477)
+ offsets[R.drawable.elf_tap_0002] = Point(435, 440)
+ offsets[R.drawable.santa_swipeleft0023] = Point(429, 429)
+ offsets[R.drawable.elf_shake_0015] = Point(263, 285)
+ offsets[R.drawable.santa_swipe_right20008] = Point(336, 417)
+ offsets[R.drawable.elf_shake_0020] = Point(324, 362)
+ offsets[R.drawable.elf_shake_0003] = Point(176, 324)
+ offsets[R.drawable.reindeer_swipeup0011] = Point(210, 34)
+ offsets[R.drawable.santa_tap0016] = Point(270, 443)
+ offsets[R.drawable.elf_swipeleft_0005] = Point(351, 460)
+ offsets[R.drawable.elf_swipeup_0022] = Point(435, 458)
+ offsets[R.drawable.snowman_swipeleft0009] = Point(429, 221)
+ offsets[R.drawable.santa_swipeup0014] = Point(311, 178)
+ offsets[R.drawable.elf_pinchin_0026] = Point(467, 340)
+ offsets[R.drawable.elf_swipedown_0017] = Point(435, 470)
+ offsets[R.drawable.santa_idle0012] = Point(416, 429)
+ offsets[R.drawable.reindeer_swipedown0003] = Point(352, 366)
+ offsets[R.drawable.santa_swipeleft0021] = Point(270, 462)
+ offsets[R.drawable.santa_pinchout20018] = Point(0, 0)
+ offsets[R.drawable.reindeer_swipeup0022] = Point(221, 344)
+ offsets[R.drawable.snowman_swiperight0019] = Point(429, 221)
+ offsets[R.drawable.reindeer_pinchout0013] = Point(106, 46)
+ offsets[R.drawable.snowman_swipedown0003] = Point(359, 311)
+ offsets[R.drawable.elf_swiperight_0014] = Point(0, 768)
+ offsets[R.drawable.snowman_tap0005] = Point(213, 221)
+ offsets[R.drawable.snowman_swiperight0023] = Point(429, 221)
+ offsets[R.drawable.reindeer_shake0007] = Point(383, 15)
+ offsets[R.drawable.elf_swiperight_0012] = Point(1280 / 2, 1280 / 2)
+ offsets[R.drawable.snowman_pinchin0018] = Point(167, 370)
+ offsets[R.drawable.santa_idle0045] = Point(415, 434)
+ offsets[R.drawable.santa_swipeup0004] = Point(426, 385)
+ offsets[R.drawable.elf_swipeleft_0021] = Point(435, 375)
+ offsets[R.drawable.reindeer_swiperight0013] = Point(0, 569)
+ offsets[R.drawable.reindeer_swiperight0024] = Point(342, 337)
+ offsets[R.drawable.reindeer_swipeleft0024] = Point(342, 337)
+ offsets[R.drawable.elf_idle_0004] = Point(435, 438)
+ offsets[R.drawable.snowman_tap0014] = Point(83, 221)
+ offsets[R.drawable.reindeer_pinchin0005] = Point(0, 0)
+ offsets[R.drawable.santa_shake0011] = Point(326, 453)
+ offsets[R.drawable.santa_swipedown0015] = Point(257, 0)
+ offsets[R.drawable.reindeer_swipeup0012] = Point(210, 35)
+ offsets[R.drawable.snowman_swipedown0004] = Point(320, 356)
+ offsets[R.drawable.reindeer_pinchin0002] = Point(0, 0)
+ offsets[R.drawable.santa_idle0033] = Point(416, 429)
+ offsets[R.drawable.elf_pinchout_0002] = Point(376, 324)
+ offsets[R.drawable.reindeer_pinchin0006] = Point(0, 0)
+ offsets[R.drawable.elf_pinchin_0009] = Point(500, 990)
+ offsets[R.drawable.santa_swipeup0015] = Point(267, 203)
+ offsets[R.drawable.snowman_swipeleft0018] = Point(429, 221)
+ offsets[R.drawable.reindeer_swipeup0005] = Point(344, 186)
+ offsets[R.drawable.reindeer_swipeup0001] = Point(342, 337)
+ offsets[R.drawable.santa_tap0003] = Point(270, 435)
+ offsets[R.drawable.elf_idle_0020] = Point(435, 438)
+ offsets[R.drawable.elf_swipeleft_0018] = Point(435, 441)
+ offsets[R.drawable.santa_swipedown0024] = Point(0, 435)
+ offsets[R.drawable.snowman_shake0009] = Point(107, 0)
+ offsets[R.drawable.santa_pinchout20017] = Point(0, 0)
+ offsets[R.drawable.elf_idle_0003] = Point(435, 439)
+ offsets[R.drawable.snowman_shake0018] = Point(72, 0)
+ offsets[R.drawable.elf_swipeup_0008] = Point(378, 188)
+ offsets[R.drawable.reindeer_pinchout0019] = Point(118, 62)
+ offsets[R.drawable.snowman_swipeup0019] = Point(376, 133)
+ offsets[R.drawable.elf_swiperight_0004] = Point(395, 453)
+ offsets[R.drawable.elf_shake_0014] = Point(318, 362)
+ offsets[R.drawable.elf_swiperight_0015] = Point(0, 572)
+ offsets[R.drawable.snowman_pinchout0008] = Point(307, 532)
+ offsets[R.drawable.elf_swiperight_0016] = Point(0, 623)
+ offsets[R.drawable.reindeer_swiperight0002] = Point(342, 337)
+ offsets[R.drawable.elf_pinchin_0004] = Point(472, 655)
+ offsets[R.drawable.elf_swipeleft_0016] = Point(444, 441)
+ offsets[R.drawable.snowman_swiperight0002] = Point(139, 221)
+ offsets[R.drawable.snowman_swiperight0004] = Point(224, 221)
+ offsets[R.drawable.santa_swipe_right20024] = Point(415, 435)
+ offsets[R.drawable.reindeer_pinchout0020] = Point(147, 97)
+ offsets[R.drawable.santa_swipeup0008] = Point(429, 283)
+ offsets[R.drawable.elf_pinchin_0030] = Point(435, 480)
+ offsets[R.drawable.snowman_swipeup0015] = Point(253, 21)
+ offsets[R.drawable.santa_swipedown0017] = Point(0, 0)
+ offsets[R.drawable.elf_pinchin_0032] = Point(435, 445)
+ offsets[R.drawable.snowman_swipedown0017] = Point(429, 129)
+ offsets[R.drawable.santa_pinchout20005] = Point(0, 0)
+ offsets[R.drawable.snowman_swipeleft0014] = Point(429, 221)
+ offsets[R.drawable.reindeer_swiperight0011] = Point(26, 1021)
+ offsets[R.drawable.reindeer_shake0009] = Point(384, 15)
+ offsets[R.drawable.reindeer_swiperight0007] = Point(313, 629)
+ offsets[R.drawable.santa_tap0004] = Point(270, 443)
+ offsets[R.drawable.reindeer_pinchin0007] = Point(0, 0)
+ offsets[R.drawable.santa_swipe_right20012] = Point(426, 350)
+ offsets[R.drawable.snowman_pinchin0019] = Point(167, 234)
+ offsets[R.drawable.reindeer_shake0017] = Point(384, 14)
+ offsets[R.drawable.santa_swipe_right20006] = Point(346, 420)
+ offsets[R.drawable.snowman_pinchout0023] = Point(382, 243)
+ offsets[R.drawable.elf_shake_0022] = Point(336, 324)
+ offsets[R.drawable.santa_swipe_right20018] = Point(415, 389)
+ offsets[R.drawable.snowman_swiperight0010] = Point(235, 221)
+ offsets[R.drawable.santa_swipe_right20013] = Point(420, 336)
+ offsets[R.drawable.snowman_swipeleft0015] = Point(429, 221)
+ offsets[R.drawable.elf_idle_0022] = Point(435, 439)
+ offsets[R.drawable.santa_shake0007] = Point(257, 475)
+ offsets[R.drawable.elf_swiperight_0008] = Point(611, 565)
+ offsets[R.drawable.santa_pinchin0020] = Point(235, 505)
+ offsets[R.drawable.snowman_swipeleft0017] = Point(429, 221)
+ offsets[R.drawable.elf_swipeleft_0017] = Point(422, 440)
+ offsets[R.drawable.santa_pinchin0003] = Point(268, 435)
+ offsets[R.drawable.snowman_pinchout0004] = Point(377, 390)
+ offsets[R.drawable.santa_tap0018] = Point(270, 404)
+ offsets[R.drawable.snowman_swipedown0019] = Point(429, 262)
+ offsets[R.drawable.santa_idle0004] = Point(415, 432)
+ offsets[R.drawable.reindeer_swipeup0004] = Point(342, 197)
+ offsets[R.drawable.reindeer_swiperight0020] = Point(383, 352)
+ offsets[R.drawable.santa_pinchin0022] = Point(270, 435)
+ offsets[R.drawable.snowman_swipeup0018] = Point(214, 71)
+ offsets[R.drawable.reindeer_swipeup0002] = Point(342, 321)
+ offsets[R.drawable.reindeer_swipeleft0009] = Point(284, 276)
+ offsets[R.drawable.santa_idle0047] = Point(415, 435)
+ offsets[R.drawable.snowman_swiperight0014] = Point(428, 221)
+ offsets[R.drawable.reindeer_shake0012] = Point(384, 14)
+ offsets[R.drawable.elf_pinchout_0021] = Point(184, 0)
+ offsets[R.drawable.snowman_pinchin0017] = Point(167, 596)
+ offsets[R.drawable.santa_swipe_right20019] = Point(415, 435)
+ offsets[R.drawable.reindeer_shake0011] = Point(383, 13)
+ offsets[R.drawable.santa_tap0009] = Point(269, 567)
+ offsets[R.drawable.elf_pinchin_0005] = Point(462, 727)
+ offsets[R.drawable.snowman_pinchin0013] = Point(90, 1008)
+ offsets[R.drawable.santa_swipeup0011] = Point(429, 221)
+ offsets[R.drawable.elf_swipedown_0019] = Point(435, 474)
+ offsets[R.drawable.snowman_tap0018] = Point(98, 221)
+ offsets[R.drawable.elf_shake_0007] = Point(244, 285)
+ offsets[R.drawable.elf_idle_0015] = Point(435, 436)
+ offsets[R.drawable.santa_pinchin0008] = Point(111, 178)
+ offsets[R.drawable.snowman_idle0008] = Point(429, 217)
+ offsets[R.drawable.reindeer_swipedown0022] = Point(354, 384)
+ offsets[R.drawable.reindeer_tap0007] = Point(342, 337)
+ offsets[R.drawable.elf_swipedown_0013] = Point(397, 628)
+ offsets[R.drawable.elf_pinchin_0028] = Point(434, 440)
+ offsets[R.drawable.snowman_swipeleft0008] = Point(429, 221)
+ offsets[R.drawable.snowman_tap0023] = Point(169, 221)
+ offsets[R.drawable.elf_tap_0009] = Point(132, 248)
+ offsets[R.drawable.elf_swipedown_0004] = Point(435, 434)
+ offsets[R.drawable.santa_shake0004] = Point(204, 478)
+ offsets[R.drawable.reindeer_swipedown0002] = Point(344, 344)
+ offsets[R.drawable.elf_pinchout_0005] = Point(0, 0)
+ offsets[R.drawable.snowman_swipeleft0002] = Point(429, 221)
+ offsets[R.drawable.elf_swipedown_0021] = Point(435, 467)
+ offsets[R.drawable.reindeer_tap0021] = Point(342, 337)
+ offsets[R.drawable.snowman_shake0011] = Point(95, 0)
+ offsets[R.drawable.elf_pinchin_0017] = Point(520, 222)
+ offsets[R.drawable.santa_shake0018] = Point(393, 420)
+ offsets[R.drawable.reindeer_swiperight0004] = Point(348, 337)
+ offsets[R.drawable.snowman_swipeleft0012] = Point(429, 221)
+ offsets[R.drawable.reindeer_swipeup0009] = Point(210, 38)
+ offsets[R.drawable.reindeer_shake0003] = Point(384, 193)
+ offsets[R.drawable.santa_swipeup0017] = Point(274, 245)
+ offsets[R.drawable.santa_swipeup0009] = Point(429, 271)
+ }
+
+ @JvmField
+ var ORIG_SIZE = Point(1280, 1280)
+
+ @JvmStatic
+ fun getOffsets(@DrawableRes drawableId: Int): Point {
+ val p = offsets[drawableId]
+ return p ?: EMPTY
+ }
+
+ private val EMPTY = Point(0, 0)
+ }
+}
\ No newline at end of file
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/RetryableAsyncTask.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/RetryableAsyncTask.kt
new file mode 100644
index 000000000..1d6c9a8d5
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/RetryableAsyncTask.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 com.google.android.apps.santatracker.util.SantaLog
+
+/** Async task that supports a full retry operation. */
+abstract class RetryableAsyncTask : AsyncTask () {
+
+ internal abstract fun shouldRetry(): Boolean
+
+ internal abstract fun onPrepareForRetry()
+
+ internal fun retrySelf(params: Array ): C? {
+ return if (shouldRetry()) {
+ onPrepareForRetry()
+ doInBackground(*params)
+ } else {
+ SantaLog.d(TAG, "Should not retry, canceling task")
+
+ cancel(true)
+ null
+ }
+ }
+
+ companion object {
+
+ private const val TAG = "RetryableAT"
+ }
+}
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
deleted file mode 100644
index 3f920a538..000000000
--- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Santa.java
+++ /dev/null
@@ -1,271 +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.apps.santatracker.dasherdancer;
-
-import java.lang.*;
-
-public class Santa implements Character {
-
- private static final long[] sDurations = new long[]{
- 2400, 1000, 1000, 1000, 1000,
- 1000, 1000, 1000, 1000
- };
-
- private static final int[][] sFrames = new int[][]{
- {R.drawable.santa_idle0001,
- R.drawable.santa_idle0002, R.drawable.santa_idle0003,
- R.drawable.santa_idle0004, R.drawable.santa_idle0005,
- R.drawable.santa_idle0006, R.drawable.santa_idle0007,
- R.drawable.santa_idle0008,
- R.drawable.santa_idle0009,
- R.drawable.santa_idle0010, // index is 9
- R.drawable.santa_idle0035, R.drawable.santa_idle0036,
- R.drawable.santa_idle0037, R.drawable.santa_idle0038},//idle
- {R.drawable.santa_tap0001, R.drawable.santa_tap0002, R.drawable.santa_tap0003,
- R.drawable.santa_tap0004, R.drawable.santa_tap0005, R.drawable.santa_tap0006,
- R.drawable.santa_tap0007, R.drawable.santa_tap0008, R.drawable.santa_tap0009,
- R.drawable.santa_tap0010, R.drawable.santa_tap0011, R.drawable.santa_tap0012,
- R.drawable.santa_tap0013, R.drawable.santa_tap0014, R.drawable.santa_tap0015,
- R.drawable.santa_tap0016, R.drawable.santa_tap0017, R.drawable.santa_tap0018,
- R.drawable.santa_tap0019, R.drawable.santa_tap0020, R.drawable.santa_tap0021,
- R.drawable.santa_tap0022, R.drawable.santa_tap0023, R.drawable.santa_tap0024},//tap
- {R.drawable.santa_shake0001,
- R.drawable.santa_shake0002,
- R.drawable.santa_shake0003,
- R.drawable.santa_shake0004,
- R.drawable.santa_shake0005,
- R.drawable.santa_shake0006,
- R.drawable.santa_shake0007,
- R.drawable.santa_shake0008,
- R.drawable.santa_shake0009,
- R.drawable.santa_shake0010,
- R.drawable.santa_shake0011,
- R.drawable.santa_shake0012,
- R.drawable.santa_shake0013,
- R.drawable.santa_shake0014,
- R.drawable.santa_shake0015,
- R.drawable.santa_shake0016,
- R.drawable.santa_shake0017,
- R.drawable.santa_shake0018,
- R.drawable.santa_shake0019,
- R.drawable.santa_shake0020,
- R.drawable.santa_shake0021,
- R.drawable.santa_shake0022,
- R.drawable.santa_shake0023,
- R.drawable.santa_shake0024,
- R.drawable.santa_idle0001},//shake
- {R.drawable.santa_swipedown0001,
- R.drawable.santa_swipedown0002,
- R.drawable.santa_swipedown0003,
- R.drawable.santa_swipedown0004,
- R.drawable.santa_swipedown0005,
- R.drawable.santa_swipedown0006,
- R.drawable.santa_swipedown0007,
- R.drawable.santa_swipedown0008,
- R.drawable.santa_swipedown0009,
- R.drawable.santa_swipedown0010,
- R.drawable.santa_swipedown0011,
- R.drawable.santa_swipedown0012,
- R.drawable.santa_swipedown0013,
- R.drawable.santa_swipedown0014,
- R.drawable.santa_swipedown0015,
- R.drawable.santa_swipedown0016,
- R.drawable.santa_swipedown0017,
- R.drawable.santa_swipedown0018,
- R.drawable.santa_swipedown0019,
- R.drawable.santa_swipedown0020,
- R.drawable.santa_swipedown0021,
- R.drawable.santa_swipedown0022,
- R.drawable.santa_swipedown0023,
- R.drawable.santa_swipedown0024,
- R.drawable.santa_idle0001},//swipe down
- {R.drawable.santa_swipeup0002,
- R.drawable.santa_swipeup0003,
- R.drawable.santa_swipeup0004,
- R.drawable.santa_swipeup0005,
- R.drawable.santa_swipeup0006,
- R.drawable.santa_swipeup0007,
- R.drawable.santa_swipeup0008,
- R.drawable.santa_swipeup0009,
- R.drawable.santa_swipeup0010,
- R.drawable.santa_swipeup0011,
- R.drawable.santa_swipeup0012,
- R.drawable.santa_swipeup0013,
- R.drawable.santa_swipeup0014,
- R.drawable.santa_swipeup0015,
- R.drawable.santa_swipeup0016,
- R.drawable.santa_swipeup0017,
- R.drawable.santa_swipeup0018,
- R.drawable.santa_swipeup0019,
- R.drawable.santa_swipeup0020,
- R.drawable.santa_swipeup0021,
- R.drawable.santa_swipeup0022,
- R.drawable.santa_swipeup0023,
- R.drawable.santa_swipeup0024,
- R.drawable.santa_idle0001},//swipe up
- {R.drawable.santa_swipeleft0001,
- R.drawable.santa_swipeleft0002,
- R.drawable.santa_swipeleft0003,
- R.drawable.santa_swipeleft0004,
- R.drawable.santa_swipeleft0005,
- R.drawable.santa_swipeleft0006,
- R.drawable.santa_swipeleft0007,
- R.drawable.santa_swipeleft0008,
- R.drawable.santa_swipeleft0009,
- R.drawable.santa_swipeleft0010,
- R.drawable.santa_swipeleft0011,
- R.drawable.santa_swipeleft0012,
- R.drawable.santa_swipeleft0013,
- R.drawable.santa_swipeleft0014,
- R.drawable.santa_swipeleft0015,
- R.drawable.santa_swipeleft0016,
- R.drawable.santa_swipeleft0017,
- R.drawable.santa_swipeleft0018,
- R.drawable.santa_swipeleft0019,
- R.drawable.santa_swipeleft0020,
- R.drawable.santa_swipeleft0021,
- R.drawable.santa_swipeleft0022,
- R.drawable.santa_swipeleft0023,
- R.drawable.santa_swipeleft0024,
- R.drawable.santa_idle0001},//swipe left
- {R.drawable.santa_swipe_right20002,
- R.drawable.santa_swipe_right20003,
- R.drawable.santa_swipe_right20004,
- R.drawable.santa_swipe_right20005,
- R.drawable.santa_swipe_right20006,
- R.drawable.santa_swipe_right20007,
- R.drawable.santa_swipe_right20008,
- R.drawable.santa_swipe_right20009,
- R.drawable.santa_swipe_right20010,
- R.drawable.santa_swipe_right20011,
- R.drawable.santa_swipe_right20012,
- R.drawable.santa_swipe_right20013,
- R.drawable.santa_swipe_right20014,
- R.drawable.santa_swipe_right20015,
- R.drawable.santa_swipe_right20016,
- R.drawable.santa_swipe_right20017,
- R.drawable.santa_swipe_right20018,
- R.drawable.santa_swipe_right20019,
- R.drawable.santa_swipe_right20020,
- R.drawable.santa_swipe_right20021,
- R.drawable.santa_swipe_right20022,
- R.drawable.santa_swipe_right20023,
- R.drawable.santa_swipe_right20024,
- R.drawable.santa_idle0001},//swipe right
- {R.drawable.santa_pinchout20001,
- R.drawable.santa_pinchout20002,
- R.drawable.santa_pinchout20003,
- R.drawable.santa_pinchout20004,
- R.drawable.santa_pinchout20005,
- R.drawable.santa_pinchout20006,
- R.drawable.santa_pinchout20007,
- R.drawable.santa_pinchout20008,
- R.drawable.santa_pinchout20009,
- R.drawable.santa_pinchout20010,
- R.drawable.santa_pinchout20011,
- R.drawable.santa_pinchout20012,
- R.drawable.santa_pinchout20013,
- R.drawable.santa_pinchout20014,
- R.drawable.santa_pinchout20015,
- R.drawable.santa_pinchout20016,
- R.drawable.santa_pinchout20017,
- R.drawable.santa_pinchout20018,
- R.drawable.santa_pinchout20019,
- R.drawable.santa_pinchout20020,
- R.drawable.santa_pinchout20021,
- R.drawable.santa_pinchout20022,
- R.drawable.santa_pinchout20023,
- R.drawable.santa_pinchout20024,
- R.drawable.santa_idle0001},//pinch in
- {R.drawable.santa_pinchin0001,
- R.drawable.santa_pinchin0002,
- R.drawable.santa_pinchin0003,
- R.drawable.santa_pinchin0004,
- R.drawable.santa_pinchin0005,
- R.drawable.santa_pinchin0006,
- R.drawable.santa_pinchin0007,
- R.drawable.santa_pinchin0008,
- R.drawable.santa_pinchin0009,
- R.drawable.santa_pinchin0010,
- R.drawable.santa_pinchin0011,
- R.drawable.santa_pinchin0012,
- R.drawable.santa_pinchin0013,
- R.drawable.santa_pinchin0014,
- R.drawable.santa_pinchin0015,
- R.drawable.santa_pinchin0016,
- R.drawable.santa_pinchin0017,
- R.drawable.santa_pinchin0018,
- R.drawable.santa_pinchin0019,
- R.drawable.santa_pinchin0020,
- R.drawable.santa_pinchin0021,
- R.drawable.santa_pinchin0022,
- R.drawable.santa_pinchin0023,
- R.drawable.santa_pinchin0024,
- R.drawable.santa_idle0001}//pinch out
- };
-
- private static final int[][] sFrameIndices = new int[][]{
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 8, 7, 6, 5, 4,
- 3, 2, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10,
- 11, 12, 13, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0},//idle
- {0, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23},//tap
- {0, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 24},//shake
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23, 24},//swipe down
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22, 23},//swipe up
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23,24},//swipe left
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//swipe right
- {0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24},//pinch in
- {0, 1,
- 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24}//pinch out
- };
-
- @Override
- public long getDuration(int animationKey) {
- return sDurations[animationKey];
- }
-
- @Override
- public int[] getFrameIndices(int animationKey) {
- return sFrameIndices[animationKey];
- }
-
- @Override
- public int[] getFrames(int animationKey) {
- return sFrames[animationKey];
- }
-
- @Override
- public String getCharacterName() {
- return "s";
- }
-
-}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Santa.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Santa.kt
new file mode 100644
index 000000000..c8c3736c3
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Santa.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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
+
+class Santa : Character {
+
+ override val characterName: String
+ get() = "s"
+
+ override fun getDuration(animationKey: Int): Long {
+ return durations[animationKey]
+ }
+
+ override fun getFrameIndices(animationKey: Int): IntArray {
+ return frameIndices[animationKey]
+ }
+
+ override fun getFrames(animationKey: Int): IntArray {
+ return frames[animationKey]
+ }
+
+ override fun getSoundResource(animationid: Int): Int {
+ when (animationid) {
+ Character.ANIM_PINCH_IN -> return R.raw.santa_pinchin
+ Character.ANIM_PINCH_OUT -> return R.raw.santa_pinchout
+ Character.ANIM_SHAKE -> return R.raw.santa_shake
+ Character.ANIM_SWIPE_UP -> return R.raw.santa_swipeup
+ Character.ANIM_SWIPE_LEFT -> return R.raw.santa_swipeleft
+ Character.ANIM_SWIPE_RIGHT -> return R.raw.santa_swiperight
+ Character.ANIM_SWIPE_DOWN -> return R.raw.santa_swipedown
+ Character.ANIM_TAP -> return R.raw.santa_tap
+ }
+
+ return -1
+ }
+
+ companion object {
+
+ private val durations = longArrayOf(2400, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000)
+
+ private val frames = arrayOf(
+ intArrayOf(
+ R.drawable.santa_idle0001, R.drawable.santa_idle0002,
+ R.drawable.santa_idle0003, R.drawable.santa_idle0004,
+ R.drawable.santa_idle0005, R.drawable.santa_idle0006,
+ R.drawable.santa_idle0007, R.drawable.santa_idle0008,
+ R.drawable.santa_idle0009, R.drawable.santa_idle0010, // index is 9
+ R.drawable.santa_idle0012, R.drawable.santa_idle0036,
+ R.drawable.santa_idle0037, R.drawable.santa_idle0038), // idle
+ intArrayOf(R.drawable.santa_pinchin0001, R.drawable.santa_pinchin0002,
+ R.drawable.santa_tap0003, R.drawable.santa_tap0004,
+ R.drawable.santa_tap0005, R.drawable.santa_tap0006,
+ R.drawable.santa_tap0007, R.drawable.santa_tap0008,
+ R.drawable.santa_tap0009, R.drawable.santa_tap0010,
+ R.drawable.santa_tap0011, R.drawable.santa_tap0012,
+ R.drawable.santa_tap0013, R.drawable.santa_tap0014,
+ R.drawable.santa_tap0015, R.drawable.santa_tap0016,
+ R.drawable.santa_tap0017, R.drawable.santa_tap0018,
+ R.drawable.santa_tap0019, R.drawable.santa_tap0016,
+ R.drawable.santa_tap0003, R.drawable.santa_tap0022,
+ R.drawable.santa_pinchin0001, R.drawable.santa_pinchin0001), // tap
+ intArrayOf(R.drawable.santa_shake0001, R.drawable.santa_shake0002,
+ R.drawable.santa_shake0003, R.drawable.santa_shake0004,
+ R.drawable.santa_shake0005, R.drawable.santa_shake0006,
+ R.drawable.santa_shake0007, R.drawable.santa_shake0008,
+ R.drawable.santa_shake0009, R.drawable.santa_shake0010,
+ R.drawable.santa_shake0011, R.drawable.santa_shake0012,
+ R.drawable.santa_shake0013, R.drawable.santa_shake0014,
+ R.drawable.santa_shake0015, R.drawable.santa_shake0016,
+ R.drawable.santa_shake0017, R.drawable.santa_shake0018,
+ R.drawable.santa_shake0019, R.drawable.santa_shake0020,
+ R.drawable.santa_shake0021, R.drawable.santa_shake0022,
+ R.drawable.santa_shake0023, R.drawable.santa_shake0024,
+ R.drawable.santa_idle0001), // shake
+ intArrayOf(R.drawable.santa_swipedown0001, R.drawable.santa_swipedown0002,
+ R.drawable.santa_swipedown0003, R.drawable.santa_swipedown0004,
+ R.drawable.santa_swipedown0005, R.drawable.santa_swipedown0006,
+ R.drawable.santa_swipedown0007, R.drawable.santa_swipedown0008,
+ R.drawable.santa_swipedown0009, R.drawable.santa_swipedown0010,
+ R.drawable.santa_swipedown0011, R.drawable.santa_swipedown0012,
+ R.drawable.santa_swipedown0013, R.drawable.santa_swipedown0014,
+ R.drawable.santa_swipedown0015, R.drawable.santa_swipedown0016,
+ R.drawable.santa_swipedown0017, R.drawable.santa_swipedown0018,
+ R.drawable.santa_swipedown0019, R.drawable.santa_swipedown0020,
+ R.drawable.santa_swipedown0021, R.drawable.santa_swipedown0022,
+ R.drawable.santa_swipedown0023, R.drawable.santa_swipedown0024,
+ R.drawable.santa_idle0001), // swipe down
+ intArrayOf(R.drawable.santa_swipeup0002, R.drawable.santa_swipeup0003,
+ R.drawable.santa_swipeup0004, R.drawable.santa_swipeup0005,
+ R.drawable.santa_swipeup0006, R.drawable.santa_swipeup0007,
+ R.drawable.santa_swipeup0008, R.drawable.santa_swipeup0009,
+ R.drawable.santa_swipeup0010, R.drawable.santa_swipeup0011,
+ R.drawable.santa_swipeup0012, R.drawable.santa_swipeup0013,
+ R.drawable.santa_swipeup0014, R.drawable.santa_swipeup0015,
+ R.drawable.santa_swipeup0016, R.drawable.santa_swipeup0017,
+ R.drawable.santa_swipeup0018, R.drawable.santa_swipeup0019,
+ R.drawable.santa_swipeup0020, R.drawable.santa_swipeup0021,
+ R.drawable.santa_swipeup0022, R.drawable.santa_swipeup0023,
+ R.drawable.santa_swipeup0001,
+ R.drawable.santa_idle0001), // swipe up
+ intArrayOf(R.drawable.santa_pinchin0001, R.drawable.santa_swipeleft0002,
+ R.drawable.santa_swipeleft0003, R.drawable.santa_swipeleft0004,
+ R.drawable.santa_swipeleft0005, R.drawable.santa_swipeleft0006,
+ R.drawable.santa_swipeleft0007, R.drawable.santa_swipeleft0008,
+ R.drawable.santa_swipeleft0009, R.drawable.santa_swipeleft0007,
+ R.drawable.santa_pinchin0001, R.drawable.santa_swipeleft0012,
+ R.drawable.santa_swipeleft0013, R.drawable.santa_swipeleft0014,
+ R.drawable.santa_swipeleft0015, R.drawable.santa_swipeleft0016,
+ R.drawable.santa_swipeleft0017, R.drawable.santa_swipeleft0018,
+ R.drawable.santa_swipeleft0019, R.drawable.santa_swipeleft0020,
+ R.drawable.santa_swipeleft0021, R.drawable.santa_swipeleft0022,
+ R.drawable.santa_swipeleft0023, R.drawable.santa_swipeleft0024,
+ R.drawable.santa_idle0001), // swipe left
+ intArrayOf(R.drawable.santa_swipe_right20002,
+ R.drawable.santa_swipe_right20003,
+ R.drawable.santa_swipe_right20004,
+ R.drawable.santa_swipe_right20005,
+ R.drawable.santa_swipe_right20006,
+ R.drawable.santa_swipe_right20007,
+ R.drawable.santa_swipe_right20008,
+ R.drawable.santa_swipe_right20009,
+ R.drawable.santa_swipe_right20010,
+ R.drawable.santa_swipe_right20011,
+ R.drawable.santa_swipe_right20012,
+ R.drawable.santa_swipe_right20013,
+ R.drawable.santa_swipe_right20014,
+ R.drawable.santa_swipe_right20015,
+ R.drawable.santa_swipe_right20016,
+ R.drawable.santa_swipe_right20017,
+ R.drawable.santa_swipe_right20018,
+ R.drawable.santa_swipe_right20019,
+ R.drawable.santa_swipe_right20020,
+ R.drawable.santa_swipe_right20021,
+ R.drawable.santa_swipe_right20022,
+ R.drawable.santa_swipe_right20023,
+ R.drawable.santa_swipe_right20024,
+ R.drawable.santa_idle0001), // swipe right
+ intArrayOf(R.drawable.santa_pinchout20001, R.drawable.santa_pinchout20002,
+ R.drawable.santa_pinchout20003, R.drawable.santa_pinchout20004,
+ R.drawable.santa_pinchout20005, R.drawable.santa_pinchout20006,
+ R.drawable.santa_pinchout20007, R.drawable.santa_pinchout20007,
+ R.drawable.santa_pinchout20007, R.drawable.santa_pinchout20007,
+ R.drawable.santa_pinchout20007, R.drawable.santa_pinchout20007,
+ R.drawable.santa_pinchout20007, R.drawable.santa_pinchout20007,
+ R.drawable.santa_pinchout20007, R.drawable.santa_pinchout20007,
+ R.drawable.santa_pinchout20017, R.drawable.santa_pinchout20018,
+ R.drawable.santa_pinchout20019, R.drawable.santa_pinchout20020,
+ R.drawable.santa_pinchout20021, R.drawable.santa_pinchout20001,
+ R.drawable.santa_pinchout20023, R.drawable.santa_pinchout20023,
+ R.drawable.santa_idle0001), // pinch in
+ intArrayOf(R.drawable.santa_pinchin0001, R.drawable.santa_pinchin0002,
+ R.drawable.santa_pinchin0003, R.drawable.santa_pinchin0004,
+ R.drawable.santa_pinchin0005, R.drawable.santa_pinchin0006,
+ R.drawable.santa_pinchin0007, R.drawable.santa_pinchin0008,
+ R.drawable.santa_pinchin0009, R.drawable.santa_pinchin0010,
+ R.drawable.santa_pinchin0009, R.drawable.santa_pinchin0008,
+ R.drawable.santa_pinchin0013, R.drawable.santa_pinchin0014,
+ R.drawable.santa_pinchin0005, R.drawable.santa_pinchin0004,
+ R.drawable.santa_pinchin0017, R.drawable.santa_pinchin0018,
+ R.drawable.santa_pinchin0019, R.drawable.santa_pinchin0020,
+ R.drawable.santa_pinchin0017, R.drawable.santa_pinchin0022,
+ R.drawable.santa_pinchin0002, R.drawable.santa_pinchin0001,
+ R.drawable.santa_idle0001) // pinch out
+ )
+
+ private val frameIndices =
+ arrayOf(intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 8, 7, 6, 5, 4, 3, 2, 1,
+ 0, 0), // idle
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // tap
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24), // shake
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24), // swipe down
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // swipe up
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24), // swipe left
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // swipe right
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24), // pinch in
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24) // pinch out
+ )
+ }
+}
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
deleted file mode 100644
index b80e793c1..000000000
--- a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Snowman.java
+++ /dev/null
@@ -1,221 +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.apps.santatracker.dasherdancer;
-
-public class Snowman implements Character {
-
- private static final long[] sDurations = new long[]{
- 1000, 1000, 1000, 960, 1000,
- 1000, 1000, 1000, 1000
- };
-
- private static final int[][] sFrames = new int[][]{
- {
- R.drawable.snowman_idle0001, R.drawable.snowman_idle0002, R.drawable.snowman_idle0003, R.drawable.snowman_idle0004,
- R.drawable.snowman_idle0005, R.drawable.snowman_idle0006, R.drawable.snowman_idle0007, R.drawable.snowman_idle0008,
- R.drawable.snowman_idle0009, R.drawable.snowman_idle0010, R.drawable.snowman_idle0011, R.drawable.snowman_idle0012,
- R.drawable.snowman_idle0013, R.drawable.snowman_idle0014, R.drawable.snowman_idle0015, R.drawable.snowman_idle0016,
- R.drawable.snowman_idle0017, R.drawable.snowman_idle0018, R.drawable.snowman_idle0019, R.drawable.snowman_idle0020,
- R.drawable.snowman_idle0021, R.drawable.snowman_idle0022, R.drawable.snowman_idle0023, R.drawable.snowman_idle0024}, //idle
- {R.drawable.snowman_tap0001, R.drawable.snowman_tap0002, R.drawable.snowman_tap0003, R.drawable.snowman_tap0004,
- R.drawable.snowman_tap0005, R.drawable.snowman_tap0006, R.drawable.snowman_tap0007, R.drawable.snowman_tap0008,
- R.drawable.snowman_tap0009, R.drawable.snowman_tap0010, R.drawable.snowman_tap0011, R.drawable.snowman_tap0012,
- R.drawable.snowman_tap0013, R.drawable.snowman_tap0014, R.drawable.snowman_tap0015, R.drawable.snowman_tap0016,
- R.drawable.snowman_tap0017, R.drawable.snowman_tap0018, R.drawable.snowman_tap0019, R.drawable.snowman_tap0020,
- R.drawable.snowman_tap0021, R.drawable.snowman_tap0022, R.drawable.snowman_tap0023, R.drawable.snowman_tap0024},//tap
- {R.drawable.snowman_shake0001, R.drawable.snowman_shake0002, R.drawable.snowman_shake0003, R.drawable.snowman_shake0004,
- R.drawable.snowman_shake0005, R.drawable.snowman_shake0006, R.drawable.snowman_shake0007, R.drawable.snowman_shake0008,
- R.drawable.snowman_shake0009, R.drawable.snowman_shake0010, R.drawable.snowman_shake0011, R.drawable.snowman_shake0012,
- R.drawable.snowman_shake0013, R.drawable.snowman_shake0014, R.drawable.snowman_shake0015, R.drawable.snowman_shake0016,
- R.drawable.snowman_shake0017, R.drawable.snowman_shake0018, R.drawable.snowman_shake0019, R.drawable.snowman_shake0020,
- R.drawable.snowman_shake0021, R.drawable.snowman_shake0022, R.drawable.snowman_shake0023, R.drawable.snowman_shake0024},//shake
- {R.drawable.snowman_swipedown0001,
- R.drawable.snowman_swipedown0002,
- R.drawable.snowman_swipedown0003,
- R.drawable.snowman_swipedown0004,
- R.drawable.snowman_swipedown0005,
- R.drawable.snowman_swipedown0006,
- R.drawable.snowman_swipedown0007,
- R.drawable.snowman_swipedown0008,
- R.drawable.snowman_swipedown0009,
- R.drawable.snowman_swipedown0010,
- R.drawable.snowman_swipedown0011,
- R.drawable.snowman_swipedown0012,
- R.drawable.snowman_swipedown0013,
- R.drawable.snowman_swipedown0014,
- R.drawable.snowman_swipedown0015,
- R.drawable.snowman_swipedown0016,
- R.drawable.snowman_swipedown0017,
- R.drawable.snowman_swipedown0018,
- R.drawable.snowman_swipedown0019,
- R.drawable.snowman_swipedown0020,
- R.drawable.snowman_swipedown0021,
- R.drawable.snowman_swipedown0022,
- R.drawable.snowman_swipedown0023},//swipe down
- {R.drawable.snowman_swipeup0002,
- R.drawable.snowman_swipeup0003,
- R.drawable.snowman_swipeup0004,
- R.drawable.snowman_swipeup0005,
- R.drawable.snowman_swipeup0006,
- R.drawable.snowman_swipeup0007,
- R.drawable.snowman_swipeup0008,
- R.drawable.snowman_swipeup0009,
- R.drawable.snowman_swipeup0010,
- R.drawable.snowman_swipeup0011,
- R.drawable.snowman_swipeup0012,
- R.drawable.snowman_swipeup0013,
- R.drawable.snowman_swipeup0014,
- R.drawable.snowman_swipeup0015,
- R.drawable.snowman_swipeup0016,
- R.drawable.snowman_swipeup0017,
- R.drawable.snowman_swipeup0018,
- R.drawable.snowman_swipeup0019,
- R.drawable.snowman_swipeup0020,
- R.drawable.snowman_swipeup0021,
- R.drawable.snowman_swipeup0022,
- R.drawable.snowman_swipeup0023,
- R.drawable.snowman_swipeup0024},//swipe up
- {R.drawable.snowman_swipeleft0001,
- R.drawable.snowman_swipeleft0002,
- R.drawable.snowman_swipeleft0003,
- R.drawable.snowman_swipeleft0004,
- R.drawable.snowman_swipeleft0005,
- R.drawable.snowman_swipeleft0006,
- R.drawable.snowman_swipeleft0007,
- R.drawable.snowman_swipeleft0008,
- R.drawable.snowman_swipeleft0009,
- R.drawable.snowman_swipeleft0010,
- R.drawable.snowman_swipeleft0011,
- R.drawable.snowman_swipeleft0012,
- R.drawable.snowman_swipeleft0013,
- R.drawable.snowman_swipeleft0014,
- R.drawable.snowman_swipeleft0015,
- R.drawable.snowman_swipeleft0016,
- R.drawable.snowman_swipeleft0017,
- R.drawable.snowman_swipeleft0018,
- R.drawable.snowman_swipeleft0019,
- R.drawable.snowman_swipeleft0020,
- R.drawable.snowman_swipeleft0021,
- R.drawable.snowman_swipeleft0022,
- R.drawable.snowman_swipeleft0023,
- R.drawable.snowman_swipeleft0024},//swipe left
- {R.drawable.snowman_swiperight0002,
- R.drawable.snowman_swiperight0003,
- R.drawable.snowman_swiperight0004,
- R.drawable.snowman_swiperight0005,
- R.drawable.snowman_swiperight0006,
- R.drawable.snowman_swiperight0007,
- R.drawable.snowman_swiperight0008,
- R.drawable.snowman_swiperight0009,
- R.drawable.snowman_swiperight0010,
- R.drawable.snowman_swiperight0011,
- R.drawable.snowman_swiperight0012,
- R.drawable.snowman_swiperight0013,
- R.drawable.snowman_swiperight0014,
- R.drawable.snowman_swiperight0015,
- R.drawable.snowman_swiperight0016,
- R.drawable.snowman_swiperight0017,
- R.drawable.snowman_swiperight0018,
- R.drawable.snowman_swiperight0019,
- R.drawable.snowman_swiperight0020,
- R.drawable.snowman_swiperight0021,
- R.drawable.snowman_swiperight0022,
- R.drawable.snowman_swiperight0023,
- R.drawable.snowman_swiperight0024},//swipe right
- {R.drawable.snowman_pinchin0001, R.drawable.snowman_pinchin0002, R.drawable.snowman_pinchin0003, R.drawable.snowman_pinchin0004,
- R.drawable.snowman_pinchin0005, R.drawable.snowman_pinchin0006, R.drawable.snowman_pinchin0007, R.drawable.snowman_pinchin0008,
- R.drawable.snowman_pinchin0009, R.drawable.snowman_pinchin0010, R.drawable.snowman_pinchin0011, R.drawable.snowman_pinchin0012,
- R.drawable.snowman_pinchin0013, R.drawable.snowman_pinchin0014, R.drawable.snowman_pinchin0015, R.drawable.snowman_pinchin0016,
- R.drawable.snowman_pinchin0017, R.drawable.snowman_pinchin0018, R.drawable.snowman_pinchin0019, R.drawable.snowman_pinchin0020,
- R.drawable.snowman_pinchin0021, R.drawable.snowman_pinchin0022, R.drawable.snowman_pinchin0023, R.drawable.snowman_pinchin0024},//pinch out
- {R.drawable.snowman_pinchout0001,
- R.drawable.snowman_pinchout0002,
- R.drawable.snowman_pinchout0003,
- R.drawable.snowman_pinchout0004,
- R.drawable.snowman_pinchout0005,
- R.drawable.snowman_pinchout0006,
- R.drawable.snowman_pinchout0007,
- R.drawable.snowman_pinchout0008,
- R.drawable.snowman_pinchout0009,
- R.drawable.snowman_pinchout0010,
- R.drawable.snowman_pinchout0011,
- R.drawable.snowman_pinchout0012,
- R.drawable.snowman_pinchout0013,
- R.drawable.snowman_pinchout0014,
- R.drawable.snowman_pinchout0015,
- R.drawable.snowman_pinchout0016,
- R.drawable.snowman_pinchout0017,
- R.drawable.snowman_pinchout0018,
- R.drawable.snowman_pinchout0019,
- R.drawable.snowman_pinchout0020,
- R.drawable.snowman_pinchout0021,
- R.drawable.snowman_pinchout0022,
- R.drawable.snowman_pinchout0023,
- R.drawable.snowman_pinchout0024}//pinch in
- };
-
- private static final int[][] sFrameIndices = new int[][]{
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//idle
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//tap
- {0, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23},//shake
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22},//swipe down
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22},//swipe up
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23},//swipe left
- {0,1,2,3,4,5,6,7,
- 8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22},//swipe right
- {0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23},//pinch in
- {0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23}//pinch out
- };
-
- @Override
- public long getDuration(int animationKey) {
- return sDurations[animationKey];
- }
-
- @Override
- public int[] getFrameIndices(int animationKey) {
- return sFrameIndices[animationKey];
- }
-
- @Override
- public int[] getFrames(int animationKey) {
- return sFrames[animationKey];
- }
-
- @Override
- public String getCharacterName() {
- return "t";
- }
-
-}
diff --git a/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Snowman.kt b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Snowman.kt
new file mode 100644
index 000000000..8bb2766fc
--- /dev/null
+++ b/dasherdancer/src/main/java/com/google/android/apps/santatracker/dasherdancer/Snowman.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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
+
+class Snowman : Character {
+
+ override val characterName: String
+ get() = "t"
+
+ override fun getDuration(animationKey: Int): Long {
+ return durations[animationKey]
+ }
+
+ override fun getFrameIndices(animationKey: Int): IntArray {
+ return frameIndices[animationKey]
+ }
+
+ override fun getFrames(animationKey: Int): IntArray {
+ return frames[animationKey]
+ }
+
+ override fun getSoundResource(animationid: Int): Int {
+ when (animationid) {
+ Character.ANIM_PINCH_IN -> return R.raw.snowman_pinchin
+ Character.ANIM_PINCH_OUT -> return R.raw.snowman_pinchout
+ Character.ANIM_SHAKE -> return R.raw.snowman_shake
+ Character.ANIM_SWIPE_UP -> return R.raw.snowman_swipeup
+ Character.ANIM_SWIPE_DOWN -> return R.raw.snowman_swipedown
+ Character.ANIM_SWIPE_LEFT -> return R.raw.snowman_swipeleft
+ Character.ANIM_SWIPE_RIGHT -> return R.raw.snowman_swiperight
+ Character.ANIM_TAP -> return R.raw.snowman_tap
+ }
+
+ return -1
+ }
+
+ companion object {
+
+ private val durations = longArrayOf(1000, 1000, 1000, 960, 1000, 1000, 1000, 1000, 1000)
+
+ private val frames = arrayOf(
+ intArrayOf(R.drawable.snowman_idle0001, R.drawable.snowman_idle0002,
+ R.drawable.snowman_idle0003, R.drawable.snowman_idle0004,
+ R.drawable.snowman_idle0005, R.drawable.snowman_idle0006,
+ R.drawable.snowman_idle0007, R.drawable.snowman_idle0008,
+ R.drawable.snowman_idle0009, R.drawable.snowman_idle0010,
+ R.drawable.snowman_idle0011, R.drawable.snowman_idle0011,
+ R.drawable.snowman_idle0011, R.drawable.snowman_idle0010,
+ R.drawable.snowman_idle0009, R.drawable.snowman_idle0016,
+ R.drawable.snowman_idle0017, R.drawable.snowman_idle0018,
+ R.drawable.snowman_idle0019, R.drawable.snowman_idle0020,
+ R.drawable.snowman_idle0021, R.drawable.snowman_idle0022,
+ R.drawable.snowman_idle0023, R.drawable.snowman_idle0001), // idle
+ intArrayOf(R.drawable.snowman_tap0001, R.drawable.snowman_tap0002,
+ R.drawable.snowman_tap0003, R.drawable.snowman_tap0004,
+ R.drawable.snowman_tap0005, R.drawable.snowman_tap0006,
+ R.drawable.snowman_tap0007, R.drawable.snowman_tap0008,
+ R.drawable.snowman_tap0009, R.drawable.snowman_tap0010,
+ R.drawable.snowman_tap0011, R.drawable.snowman_tap0012,
+ R.drawable.snowman_tap0013, R.drawable.snowman_tap0014,
+ R.drawable.snowman_tap0015, R.drawable.snowman_tap0016,
+ R.drawable.snowman_tap0017, R.drawable.snowman_tap0018,
+ R.drawable.snowman_tap0019, R.drawable.snowman_tap0020,
+ R.drawable.snowman_tap0021, R.drawable.snowman_tap0022,
+ R.drawable.snowman_tap0023, R.drawable.snowman_tap0024), // tap
+ intArrayOf(R.drawable.snowman_shake0001, R.drawable.snowman_shake0002,
+ R.drawable.snowman_shake0003, R.drawable.snowman_shake0004,
+ R.drawable.snowman_shake0005, R.drawable.snowman_shake0006,
+ R.drawable.snowman_shake0007, R.drawable.snowman_shake0008,
+ R.drawable.snowman_shake0009, R.drawable.snowman_shake0010,
+ R.drawable.snowman_shake0011, R.drawable.snowman_shake0012,
+ R.drawable.snowman_shake0013, R.drawable.snowman_shake0014,
+ R.drawable.snowman_shake0015, R.drawable.snowman_shake0016,
+ R.drawable.snowman_shake0017, R.drawable.snowman_shake0018,
+ R.drawable.snowman_shake0019, R.drawable.snowman_shake0020,
+ R.drawable.snowman_shake0021, R.drawable.snowman_shake0022,
+ R.drawable.snowman_shake0023,
+ R.drawable.snowman_shake0024), // shake
+ intArrayOf(R.drawable.snowman_idle0001, R.drawable.snowman_swipedown0002,
+ R.drawable.snowman_swipedown0003, R.drawable.snowman_swipedown0004,
+ R.drawable.snowman_swipedown0005, R.drawable.snowman_swipedown0006,
+ R.drawable.snowman_swipedown0007, R.drawable.snowman_swipedown0008,
+ R.drawable.snowman_swipedown0009, R.drawable.snowman_swipedown0010,
+ R.drawable.snowman_swipedown0011, R.drawable.snowman_swipedown0012,
+ R.drawable.snowman_swipedown0013, R.drawable.snowman_swipedown0014,
+ R.drawable.snowman_swipedown0015, R.drawable.snowman_swipedown0016,
+ R.drawable.snowman_swipedown0017, R.drawable.snowman_swipedown0018,
+ R.drawable.snowman_swipedown0019, R.drawable.snowman_swipedown0020,
+ R.drawable.snowman_swipedown0021, R.drawable.snowman_idle0001,
+ R.drawable.snowman_idle0001), // swipe down
+ intArrayOf(R.drawable.snowman_swipeup0002, R.drawable.snowman_swipeup0003,
+ R.drawable.snowman_swipeup0004, R.drawable.snowman_swipeup0005,
+ R.drawable.snowman_swipeup0006, R.drawable.snowman_swipeup0007,
+ R.drawable.snowman_swipeup0008, R.drawable.snowman_swipeup0008,
+ R.drawable.snowman_swipeup0008, R.drawable.snowman_swipeup0011,
+ R.drawable.snowman_swipeup0012, R.drawable.snowman_swipeup0013,
+ R.drawable.snowman_swipeup0014, R.drawable.snowman_swipeup0015,
+ R.drawable.snowman_swipeup0016, R.drawable.snowman_swipeup0017,
+ R.drawable.snowman_swipeup0018, R.drawable.snowman_swipeup0019,
+ R.drawable.snowman_swipeup0020, R.drawable.snowman_swipeup0021,
+ R.drawable.snowman_swipeup0022, R.drawable.snowman_swipeup0023,
+ R.drawable.snowman_idle0001), // swipe up
+ intArrayOf(R.drawable.snowman_swipeleft0001,
+ R.drawable.snowman_swipeleft0002, R.drawable.snowman_swipeleft0003,
+ R.drawable.snowman_swipeleft0004, R.drawable.snowman_swipeleft0005,
+ R.drawable.snowman_swipeleft0006, R.drawable.snowman_swipeleft0007,
+ R.drawable.snowman_swipeleft0008, R.drawable.snowman_swipeleft0009,
+ R.drawable.snowman_swipeleft0010, R.drawable.snowman_swipeleft0011,
+ R.drawable.snowman_swipeleft0012, R.drawable.snowman_swipeleft0013,
+ R.drawable.snowman_swipeleft0014, R.drawable.snowman_swipeleft0015,
+ R.drawable.snowman_swipeleft0016, R.drawable.snowman_swipeleft0017,
+ R.drawable.snowman_swipeleft0018, R.drawable.snowman_swipeleft0019,
+ R.drawable.snowman_swipeleft0020, R.drawable.snowman_swipeleft0021,
+ R.drawable.snowman_swipeleft0022, R.drawable.snowman_swipeleft0023,
+ R.drawable.snowman_swipeleft0024), // swipe left
+ intArrayOf(R.drawable.snowman_swiperight0002,
+ R.drawable.snowman_swiperight0003,
+ R.drawable.snowman_swiperight0004,
+ R.drawable.snowman_swiperight0005,
+ R.drawable.snowman_swiperight0006,
+ R.drawable.snowman_swiperight0007,
+ R.drawable.snowman_swiperight0008,
+ R.drawable.snowman_swiperight0009,
+ R.drawable.snowman_swiperight0010,
+ R.drawable.snowman_swiperight0011,
+ R.drawable.snowman_swiperight0012,
+ R.drawable.snowman_swiperight0013,
+ R.drawable.snowman_swiperight0014,
+ R.drawable.snowman_swiperight0015,
+ R.drawable.snowman_swiperight0016,
+ R.drawable.snowman_swiperight0017,
+ R.drawable.snowman_swiperight0018,
+ R.drawable.snowman_swiperight0019,
+ R.drawable.snowman_swiperight0020,
+ R.drawable.snowman_swiperight0021,
+ R.drawable.snowman_swiperight0022,
+ R.drawable.snowman_swiperight0023,
+ R.drawable.snowman_swiperight0001), // swipe right
+ intArrayOf(R.drawable.snowman_pinchin0001, R.drawable.snowman_pinchin0002,
+ R.drawable.snowman_pinchin0003, R.drawable.snowman_pinchin0004,
+ R.drawable.snowman_pinchin0005, R.drawable.snowman_pinchin0006,
+ R.drawable.snowman_pinchin0007, R.drawable.snowman_pinchin0008,
+ R.drawable.snowman_pinchin0009, R.drawable.snowman_pinchin0010,
+ R.drawable.snowman_pinchin0011, R.drawable.snowman_pinchin0012,
+ R.drawable.snowman_pinchin0013, R.drawable.snowman_pinchin0014,
+ R.drawable.snowman_pinchin0014, R.drawable.snowman_pinchin0016,
+ R.drawable.snowman_pinchin0017, R.drawable.snowman_pinchin0018,
+ R.drawable.snowman_pinchin0019, R.drawable.snowman_pinchin0020,
+ R.drawable.snowman_pinchin0021, R.drawable.snowman_pinchin0022,
+ R.drawable.snowman_pinchin0023,
+ R.drawable.snowman_pinchin0024), // pinch out
+ intArrayOf(R.drawable.snowman_pinchout0001, R.drawable.snowman_pinchout0002,
+ R.drawable.snowman_pinchout0003, R.drawable.snowman_pinchout0004,
+ R.drawable.snowman_pinchout0005, R.drawable.snowman_pinchout0006,
+ R.drawable.snowman_pinchout0007, R.drawable.snowman_pinchout0008,
+ R.drawable.snowman_pinchout0009, R.drawable.snowman_pinchout0010,
+ R.drawable.snowman_pinchout0011, R.drawable.snowman_pinchout0012,
+ R.drawable.snowman_pinchout0013, R.drawable.snowman_pinchout0013,
+ R.drawable.snowman_pinchout0013, R.drawable.snowman_pinchout0013,
+ R.drawable.snowman_pinchout0013, R.drawable.snowman_pinchout0013,
+ R.drawable.snowman_pinchout0013, R.drawable.snowman_pinchout0020,
+ R.drawable.snowman_pinchout0021, R.drawable.snowman_pinchout0022,
+ R.drawable.snowman_pinchout0023,
+ R.drawable.snowman_pinchout0024) // pinch in
+ )
+
+ private val frameIndices =
+ arrayOf(intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // idle
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // tap
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // shake
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22), // swipe down
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22), // swipe up
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // swipe left
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22), // swipe right
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23), // pinch in
+ intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23) // pinch out
+ )
+ }
+}
diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer.png b/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer.png
deleted file mode 100644
index 8adbd5a79..000000000
Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer.webp b/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer.webp
new file mode 100644
index 000000000..49d9a760e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer.webp 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
deleted file mode 100644
index b3287bd84..000000000
Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer_p.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer_p.webp b/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer_p.webp
new file mode 100644
index 000000000..e41f5de70
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-hdpi/btn_nav_drawer_p.webp 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
deleted file mode 100644
index ad9d15a74..000000000
Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_select_character.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_select_character.webp b/dasherdancer/src/main/res/drawable-hdpi/btn_select_character.webp
new file mode 100644
index 000000000..73d7aa8e8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-hdpi/btn_select_character.webp 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
deleted file mode 100644
index 3ac4e48b5..000000000
Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_select_character_pressed.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_select_character_pressed.webp b/dasherdancer/src/main/res/drawable-hdpi/btn_select_character_pressed.webp
new file mode 100644
index 000000000..5ed2f609d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-hdpi/btn_select_character_pressed.webp 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
deleted file mode 100644
index 0c07d16cb..000000000
Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_x_out.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_x_out.webp b/dasherdancer/src/main/res/drawable-hdpi/btn_x_out.webp
new file mode 100644
index 000000000..b9d36771f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-hdpi/btn_x_out.webp 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
deleted file mode 100644
index e8fbe8fe8..000000000
Binary files a/dasherdancer/src/main/res/drawable-hdpi/btn_x_out_pressed.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-hdpi/btn_x_out_pressed.webp b/dasherdancer/src/main/res/drawable-hdpi/btn_x_out_pressed.webp
new file mode 100644
index 000000000..8b96a739a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-hdpi/btn_x_out_pressed.webp differ
diff --git a/dasherdancer/src/main/res/drawable-hdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 63fddf6e5..000000000
Binary files a/dasherdancer/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null 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
deleted file mode 100644
index 36ba0582e..000000000
Binary files a/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_left.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_left.webp b/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_left.webp
new file mode 100644
index 000000000..ff40c2f53
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_left.webp 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
deleted file mode 100644
index 22e17faaa..000000000
Binary files a/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_right.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_right.webp b/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_right.webp
new file mode 100644
index 000000000..411d36695
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-hdpi/icn_arrow_right.webp 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
deleted file mode 100644
index ad10a84c1..000000000
Binary files a/dasherdancer/src/main/res/drawable-hdpi/img_mint_loading_spinner.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-hdpi/img_mint_loading_spinner.webp b/dasherdancer/src/main/res/drawable-hdpi/img_mint_loading_spinner.webp
new file mode 100644
index 000000000..33e2d127a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-hdpi/img_mint_loading_spinner.webp 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
deleted file mode 100644
index a8223660d..000000000
Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer.webp b/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer.webp
new file mode 100644
index 000000000..86a289616
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer.webp 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
deleted file mode 100644
index 012ec450c..000000000
Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer_p.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer_p.webp b/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer_p.webp
new file mode 100644
index 000000000..d26fb3ce4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-mdpi/btn_nav_drawer_p.webp 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
deleted file mode 100644
index 07c2b2425..000000000
Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_select_character.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_select_character.webp b/dasherdancer/src/main/res/drawable-mdpi/btn_select_character.webp
new file mode 100644
index 000000000..eedcfb366
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-mdpi/btn_select_character.webp 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
deleted file mode 100644
index d3007b335..000000000
Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_select_character_pressed.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_select_character_pressed.webp b/dasherdancer/src/main/res/drawable-mdpi/btn_select_character_pressed.webp
new file mode 100644
index 000000000..d125dd5d4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-mdpi/btn_select_character_pressed.webp 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
deleted file mode 100644
index 173dd9af4..000000000
Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_x_out.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_x_out.webp b/dasherdancer/src/main/res/drawable-mdpi/btn_x_out.webp
new file mode 100644
index 000000000..03a439d4a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-mdpi/btn_x_out.webp 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
deleted file mode 100644
index a3aa8a45f..000000000
Binary files a/dasherdancer/src/main/res/drawable-mdpi/btn_x_out_pressed.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-mdpi/btn_x_out_pressed.webp b/dasherdancer/src/main/res/drawable-mdpi/btn_x_out_pressed.webp
new file mode 100644
index 000000000..8ca6e5d29
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-mdpi/btn_x_out_pressed.webp differ
diff --git a/dasherdancer/src/main/res/drawable-mdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 69e443b8c..000000000
Binary files a/dasherdancer/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null 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
deleted file mode 100644
index cf2884ffb..000000000
Binary files a/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_left.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_left.webp b/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_left.webp
new file mode 100644
index 000000000..19f0de4dc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_left.webp 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
deleted file mode 100644
index 47e24e564..000000000
Binary files a/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_right.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_right.webp b/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_right.webp
new file mode 100644
index 000000000..074fc7f09
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-mdpi/icn_arrow_right.webp 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
deleted file mode 100644
index 45d0fdcfe..000000000
Binary files a/dasherdancer/src/main/res/drawable-mdpi/img_mint_loading_spinner.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-mdpi/img_mint_loading_spinner.webp b/dasherdancer/src/main/res/drawable-mdpi/img_mint_loading_spinner.webp
new file mode 100644
index 000000000..c68957b41
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-mdpi/img_mint_loading_spinner.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf.webp b/dasherdancer/src/main/res/drawable-nodpi/elf.webp
new file mode 100644
index 000000000..25448744b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0001.png
deleted file mode 100644
index 621bf3fe9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0002.png
deleted file mode 100644
index 5b032ba21..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0003.png
deleted file mode 100644
index 78df727b6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0004.png
deleted file mode 100644
index d06f5bb0c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0005.png
deleted file mode 100644
index 96a5b2cee..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0006.png
deleted file mode 100644
index ab93fb42c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0007.png
deleted file mode 100644
index a9cc24e3e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0008.png
deleted file mode 100644
index 28fe82578..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0009.png
deleted file mode 100644
index 92f75957d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0010.png
deleted file mode 100644
index 4035690fe..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0011.png
deleted file mode 100644
index 6be2ad95d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0012.png
deleted file mode 100644
index 4cb6b311a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0013.png
deleted file mode 100644
index 6be2ad95d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0014.png
deleted file mode 100644
index 4035690fe..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0015.png
deleted file mode 100644
index 3fb7ecafd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0016.png
deleted file mode 100644
index 92f75957d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0017.png
deleted file mode 100644
index bc91b74b8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0018.png
deleted file mode 100644
index a9cc24e3e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0019.png
deleted file mode 100644
index 3f1c99136..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0020.png
deleted file mode 100644
index b85944579..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0021.png
deleted file mode 100644
index 37464b038..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0022.png
deleted file mode 100644
index f93e3a806..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0023.png
deleted file mode 100644
index 5b032ba21..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_idle0024.png
deleted file mode 100644
index e0d068825..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_idle0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0001.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0001.webp
new file mode 100644
index 000000000..9033e0742
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0002.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0002.webp
new file mode 100644
index 000000000..b661da28f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0003.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0003.webp
new file mode 100644
index 000000000..d8d54b385
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0004.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0004.webp
new file mode 100644
index 000000000..882f2862e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0005.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0005.webp
new file mode 100644
index 000000000..02f724535
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0006.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0006.webp
new file mode 100644
index 000000000..efed03d5d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0007.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0007.webp
new file mode 100644
index 000000000..bea73e7dd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0008.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0008.webp
new file mode 100644
index 000000000..d77484279
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0009.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0009.webp
new file mode 100644
index 000000000..b3824e469
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0010.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0010.webp
new file mode 100644
index 000000000..9a06bdac6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0011.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0011.webp
new file mode 100644
index 000000000..bbf5dfa6a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0012.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0012.webp
new file mode 100644
index 000000000..cc63dab01
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0013.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0013.webp
new file mode 100644
index 000000000..bbf5dfa6a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0014.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0014.webp
new file mode 100644
index 000000000..9a06bdac6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0015.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0015.webp
new file mode 100644
index 000000000..ddce570dd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0016.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0016.webp
new file mode 100644
index 000000000..cdf734941
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0017.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0017.webp
new file mode 100644
index 000000000..7688fe006
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0018.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0018.webp
new file mode 100644
index 000000000..33162e0e7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0019.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0019.webp
new file mode 100644
index 000000000..f0620f2d7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0020.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0020.webp
new file mode 100644
index 000000000..d6a9068c8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0021.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0021.webp
new file mode 100644
index 000000000..8efeb3636
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0022.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0022.webp
new file mode 100644
index 000000000..6ca49ad19
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0023.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0023.webp
new file mode 100644
index 000000000..23d77baf2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0024.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0024.webp
new file mode 100644
index 000000000..fd2f21c7d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_idle_0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0001.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0001.webp
new file mode 100644
index 000000000..0a0d522d9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0002.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0002.webp
new file mode 100644
index 000000000..458668865
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0003.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0003.webp
new file mode 100644
index 000000000..37095b709
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0004.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0004.webp
new file mode 100644
index 000000000..91ed89424
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0005.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0005.webp
new file mode 100644
index 000000000..94d417989
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0006.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0006.webp
new file mode 100644
index 000000000..e6a739f95
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0007.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0007.webp
new file mode 100644
index 000000000..7ba7c2b99
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0008.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0008.webp
new file mode 100644
index 000000000..b241c4545
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0009.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0009.webp
new file mode 100644
index 000000000..fbb3e9adc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0010.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0010.webp
new file mode 100644
index 000000000..4e2877f72
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0011.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0011.webp
new file mode 100644
index 000000000..1656d275f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0012.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0012.webp
new file mode 100644
index 000000000..fba3242cd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0013.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0013.webp
new file mode 100644
index 000000000..63705c219
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0014.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0014.webp
new file mode 100644
index 000000000..16c3f6220
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0015.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0015.webp
new file mode 100644
index 000000000..127f332a2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0016.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0016.webp
new file mode 100644
index 000000000..ce8289d89
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0017.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0017.webp
new file mode 100644
index 000000000..84a216be2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0018.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0018.webp
new file mode 100644
index 000000000..90ffb565d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0019.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0019.webp
new file mode 100644
index 000000000..299ddd53d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0020.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0020.webp
new file mode 100644
index 000000000..c39e2f83d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0021.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0021.webp
new file mode 100644
index 000000000..85f432ab8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0022.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0022.webp
new file mode 100644
index 000000000..6d96e498f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0023.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0023.webp
new file mode 100644
index 000000000..70f637e2e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0024.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0024.webp
new file mode 100644
index 000000000..91d37df23
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0025.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0025.webp
new file mode 100644
index 000000000..30fa9bdc2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0025.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0026.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0026.webp
new file mode 100644
index 000000000..1ef5394cd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0026.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0027.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0027.webp
new file mode 100644
index 000000000..94f6b4261
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0027.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0028.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0028.webp
new file mode 100644
index 000000000..ca6546b7b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0028.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0029.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0029.webp
new file mode 100644
index 000000000..bfdc5ef80
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0029.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0030.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0030.webp
new file mode 100644
index 000000000..2ac4e947a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0030.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0031.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0031.webp
new file mode 100644
index 000000000..620e3c59a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0031.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0032.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0032.webp
new file mode 100644
index 000000000..73b52340f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_0032.webp 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
deleted file mode 100644
index 908d5e464..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0001.png and /dev/null 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
deleted file mode 100644
index 6b7416753..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0002.png and /dev/null 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
deleted file mode 100644
index f065f5455..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0003.png and /dev/null 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
deleted file mode 100644
index cb048ba00..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0004.png and /dev/null 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
deleted file mode 100644
index 2d07753bf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0005.png and /dev/null 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
deleted file mode 100644
index 6bce31a51..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0006.png and /dev/null 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
deleted file mode 100644
index 51261dfd4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0007.png and /dev/null 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..feadb2bf1 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
deleted file mode 100644
index ab49ad520..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0009.png and /dev/null 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
deleted file mode 100644
index bbdcd4439..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0010.png and /dev/null 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
deleted file mode 100644
index ee6cbbb41..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0011.png and /dev/null 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
deleted file mode 100644
index e3f1541cf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0012.png and /dev/null 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
deleted file mode 100644
index a5f464b28..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0013.png and /dev/null 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
deleted file mode 100644
index 6f8cb9a26..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0014.png and /dev/null 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
deleted file mode 100644
index 95157c370..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0015.png and /dev/null 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
deleted file mode 100644
index 333a01f18..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0016.png and /dev/null 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
deleted file mode 100644
index a8e3e235b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0017.png and /dev/null 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
deleted file mode 100644
index 595400797..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0018.png and /dev/null 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
deleted file mode 100644
index ebe25c7d7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0019.png and /dev/null 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
deleted file mode 100644
index 40c6a4692..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0021.png and /dev/null 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
deleted file mode 100644
index 04f6eafb4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0022.png and /dev/null 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
deleted file mode 100644
index e2939bc15..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0023.png and /dev/null 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
deleted file mode 100644
index 934316592..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0024.png and /dev/null 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
deleted file mode 100644
index d8fd29edf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0025.png and /dev/null 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
deleted file mode 100644
index c46c1e9af..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0026.png and /dev/null 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
deleted file mode 100644
index 3818c7865..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0027.png and /dev/null 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
deleted file mode 100644
index d0dc54e35..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0028.png and /dev/null 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
deleted file mode 100644
index cb8bee0dd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0029.png and /dev/null 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
deleted file mode 100644
index 9bd7dfdb3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0030.png and /dev/null 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
deleted file mode 100644
index 1081a6ce6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0031.png and /dev/null 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
deleted file mode 100644
index ebbfe0fa6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchin_ball0032.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0001.png
deleted file mode 100644
index 574dad317..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0002.png
deleted file mode 100644
index 1b62088d9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0003.png
deleted file mode 100644
index 0a3555ecb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0004.png
deleted file mode 100644
index f830acc38..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0005.png
deleted file mode 100644
index 8cdbe12a2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0006.png
deleted file mode 100644
index 0385480c6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0007.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0008.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0009.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0010.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0011.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0012.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0013.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0014.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0015.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0016.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0017.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0018.png
deleted file mode 100644
index 2999b0510..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0019.png
deleted file mode 100644
index d917dc91f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0020.png
deleted file mode 100644
index 4bb4408fe..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0021.png
deleted file mode 100644
index f3699e2b2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0022.png
deleted file mode 100644
index d6eb12ad1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0023.png
deleted file mode 100644
index 30b88baa2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0024.png
deleted file mode 100644
index e8aa47e39..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0001.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0001.webp
new file mode 100644
index 000000000..4e4f012b3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0002.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0002.webp
new file mode 100644
index 000000000..fe68d2c2d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0003.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0003.webp
new file mode 100644
index 000000000..beb6fd8f2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0004.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0004.webp
new file mode 100644
index 000000000..14880d972
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0005.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0005.webp
new file mode 100644
index 000000000..8f4bfcf47
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0006.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0006.webp
new file mode 100644
index 000000000..197a7afc7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0007.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0007.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0008.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0008.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0009.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0009.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0010.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0010.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0011.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0011.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0012.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0012.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0013.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0013.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0014.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0014.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0015.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0015.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0016.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0016.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0017.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0017.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0018.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0018.webp
new file mode 100644
index 000000000..72d4f4d75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0019.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0019.webp
new file mode 100644
index 000000000..101a1edb7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0020.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0020.webp
new file mode 100644
index 000000000..55249e8f6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0021.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0021.webp
new file mode 100644
index 000000000..290b6542a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0022.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0022.webp
new file mode 100644
index 000000000..f64346336
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0023.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0023.webp
new file mode 100644
index 000000000..be6853fa5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0024.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0024.webp
new file mode 100644
index 000000000..c613835ba
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_pinchout_0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0001.png
deleted file mode 100644
index 995bd0b79..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0002.png
deleted file mode 100644
index 7b535b22d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0003.png
deleted file mode 100644
index e0cab467f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0004.png
deleted file mode 100644
index 4818f79aa..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0005.png
deleted file mode 100644
index 8a552da60..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0006.png
deleted file mode 100644
index 0341331be..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0007.png
deleted file mode 100644
index 7d54c3c73..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0008.png
deleted file mode 100644
index 1b4961c81..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0009.png
deleted file mode 100644
index 8ab076220..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0010.png
deleted file mode 100644
index 1bf77a142..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0011.png
deleted file mode 100644
index 284b1a5df..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0012.png
deleted file mode 100644
index 5b7c199cf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0013.png
deleted file mode 100644
index 78b3bbd6e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0014.png
deleted file mode 100644
index c9ad0c741..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0015.png
deleted file mode 100644
index 43370b68b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0016.png
deleted file mode 100644
index 75a8b07ef..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0017.png
deleted file mode 100644
index 112711199..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0018.png
deleted file mode 100644
index 63d6cca85..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0019.png
deleted file mode 100644
index 36f6e4d65..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0020.png
deleted file mode 100644
index 4ef227643..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0021.png
deleted file mode 100644
index 3fb31afdc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0022.png
deleted file mode 100644
index 79fe62d02..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0023.png
deleted file mode 100644
index a3b1e4f6e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_shake0024.png
deleted file mode 100644
index 995bd0b79..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_shake0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0001.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0001.webp
new file mode 100644
index 000000000..7b8bb488d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0002.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0002.webp
new file mode 100644
index 000000000..5ee588b8b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0003.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0003.webp
new file mode 100644
index 000000000..dedea5062
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0004.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0004.webp
new file mode 100644
index 000000000..3499fab42
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0005.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0005.webp
new file mode 100644
index 000000000..1d4180e71
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0006.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0006.webp
new file mode 100644
index 000000000..e21eecb49
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0007.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0007.webp
new file mode 100644
index 000000000..d4a5664a8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0008.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0008.webp
new file mode 100644
index 000000000..efd8ec368
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0009.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0009.webp
new file mode 100644
index 000000000..f0bdf9e9e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0010.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0010.webp
new file mode 100644
index 000000000..f4d8ab631
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0011.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0011.webp
new file mode 100644
index 000000000..483e6b182
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0012.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0012.webp
new file mode 100644
index 000000000..80c5d6f89
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0013.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0013.webp
new file mode 100644
index 000000000..ade8e5eaf
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0014.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0014.webp
new file mode 100644
index 000000000..59c528e7a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0015.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0015.webp
new file mode 100644
index 000000000..7a5882a7c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0016.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0016.webp
new file mode 100644
index 000000000..f4733665b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0017.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0017.webp
new file mode 100644
index 000000000..bb50c36dc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0018.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0018.webp
new file mode 100644
index 000000000..1b10ba730
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0019.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0019.webp
new file mode 100644
index 000000000..1fdab6b75
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0020.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0020.webp
new file mode 100644
index 000000000..07ad0d194
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0021.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0021.webp
new file mode 100644
index 000000000..78276e24e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0022.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0022.webp
new file mode 100644
index 000000000..6c6f0c88b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0023.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0023.webp
new file mode 100644
index 000000000..89dfe4b9f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0024.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0024.webp
new file mode 100644
index 000000000..7b8bb488d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_shake_0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0001.png
deleted file mode 100644
index 6c015a13f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0002.png
deleted file mode 100644
index 6c015a13f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0003.png
deleted file mode 100644
index 2684ceaad..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0004.png
deleted file mode 100644
index 71aafff24..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0005.png
deleted file mode 100644
index a73c2f7c7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0006.png
deleted file mode 100644
index 57bc51cc8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0007.png
deleted file mode 100644
index 6fd0a821b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0008.png
deleted file mode 100644
index 07d509d3f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0008.png and /dev/null 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..e8b6fa141 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
deleted file mode 100644
index f0e359804..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0011.png
deleted file mode 100644
index 6480b5922..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0012.png
deleted file mode 100644
index 607d6ad08..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0013.png
deleted file mode 100644
index 18c720550..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0014.png
deleted file mode 100644
index 607d6ad08..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0015.png
deleted file mode 100644
index 20b16ced0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0016.png
deleted file mode 100644
index 21fd456af..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0016.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0016.webp
new file mode 100644
index 000000000..14291b735
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0017.png
deleted file mode 100644
index bc7f2b711..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0018.png
deleted file mode 100644
index 9af289f23..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0019.png
deleted file mode 100644
index 7ebf72e0e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0020.png
deleted file mode 100644
index 80d361e0c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0021.png
deleted file mode 100644
index dce325e68..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0022.png
deleted file mode 100644
index 46d6514b4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0023.png
deleted file mode 100644
index ded5d1fa9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0024.png
deleted file mode 100644
index 6c015a13f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0001.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0001.webp
new file mode 100644
index 000000000..1b2232370
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0002.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0002.webp
new file mode 100644
index 000000000..1b2232370
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0003.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0003.webp
new file mode 100644
index 000000000..33adc4cb7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0004.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0004.webp
new file mode 100644
index 000000000..c67aec5bf
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0005.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0005.webp
new file mode 100644
index 000000000..d9e72ab1f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0006.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0006.webp
new file mode 100644
index 000000000..47accbaf4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0007.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0007.webp
new file mode 100644
index 000000000..908752de8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0008.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0008.webp
new file mode 100644
index 000000000..b5db1bc0a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0009.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0009.webp
new file mode 100644
index 000000000..878e25e47
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0010.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0010.webp
new file mode 100644
index 000000000..ba0654ebc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0011.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0011.webp
new file mode 100644
index 000000000..98cb02d88
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0012.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0012.webp
new file mode 100644
index 000000000..fd799799d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0013.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0013.webp
new file mode 100644
index 000000000..2847e06da
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0014.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0014.webp
new file mode 100644
index 000000000..fd799799d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0015.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0015.webp
new file mode 100644
index 000000000..962a6d4fb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0016.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0016.webp
new file mode 100644
index 000000000..88f8aebe7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0017.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0017.webp
new file mode 100644
index 000000000..5de05e422
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0018.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0018.webp
new file mode 100644
index 000000000..37fecb301
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0019.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0019.webp
new file mode 100644
index 000000000..d78e9ab71
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0020.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0020.webp
new file mode 100644
index 000000000..4ef6b0ae3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0021.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0021.webp
new file mode 100644
index 000000000..087159a70
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0022.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0022.webp
new file mode 100644
index 000000000..cbfbf3b5c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0023.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0023.webp
new file mode 100644
index 000000000..d78bc60be
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0024.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0024.webp
new file mode 100644
index 000000000..1b2232370
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipedown_0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0001.png
deleted file mode 100644
index 4f21e029f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0002.png
deleted file mode 100644
index 38959c3e2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0003.png
deleted file mode 100644
index c011059ed..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0004.png
deleted file mode 100644
index 3aa531f94..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0005.png
deleted file mode 100644
index 6b5d74791..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0006.png
deleted file mode 100644
index d5aff98cc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0007.png
deleted file mode 100644
index 94bd587fa..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0008.png
deleted file mode 100644
index 0af1342f4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0009.png
deleted file mode 100644
index 7cda28487..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0009.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0009.webp
new file mode 100644
index 000000000..2b75d0fa7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0010.png
deleted file mode 100644
index 1f987632f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0011.png
deleted file mode 100644
index 31b0451a7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0012.png
deleted file mode 100644
index c58c11a9f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0013.png
deleted file mode 100644
index c2d445643..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0013.png and /dev/null 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
deleted file mode 100644
index e37e17aa8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0015.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0015.webp
new file mode 100644
index 000000000..cb2bc6ccd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0016.png
deleted file mode 100644
index 5f4340ba4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0017.png
deleted file mode 100644
index 91ccdb925..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0018.png
deleted file mode 100644
index 17eca8553..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0019.png
deleted file mode 100644
index b5f0495e1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0020.png
deleted file mode 100644
index c07361a4b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0021.png
deleted file mode 100644
index 47f4c9cc0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0022.png
deleted file mode 100644
index 0764e73a2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0023.png
deleted file mode 100644
index 225cf224e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0024.png
deleted file mode 100644
index 7dc00269d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0001.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0001.webp
new file mode 100644
index 000000000..872db7607
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0002.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0002.webp
new file mode 100644
index 000000000..25e0c0bf1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0003.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0003.webp
new file mode 100644
index 000000000..606345bc5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0004.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0004.webp
new file mode 100644
index 000000000..30e8ff2b1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0005.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0005.webp
new file mode 100644
index 000000000..52c57d250
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0006.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0006.webp
new file mode 100644
index 000000000..1da31dfc1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0007.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0007.webp
new file mode 100644
index 000000000..f11393da3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0008.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0008.webp
new file mode 100644
index 000000000..5f50f5acf
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0009.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0009.webp
new file mode 100644
index 000000000..865a0cd55
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0010.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0010.webp
new file mode 100644
index 000000000..9eeee300a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0011.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0011.webp
new file mode 100644
index 000000000..1599e832a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0012.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0012.webp
new file mode 100644
index 000000000..bf8956de3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0013.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0013.webp
new file mode 100644
index 000000000..e868a926a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0014.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0014.webp
new file mode 100644
index 000000000..ceb74ba6b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0015.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0015.webp
new file mode 100644
index 000000000..212a13c52
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0016.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0016.webp
new file mode 100644
index 000000000..03b39dfb4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0017.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0017.webp
new file mode 100644
index 000000000..1b7cd256e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0018.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0018.webp
new file mode 100644
index 000000000..011d68752
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0019.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0019.webp
new file mode 100644
index 000000000..58ae5d320
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0020.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0020.webp
new file mode 100644
index 000000000..ad04e7b53
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0021.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0021.webp
new file mode 100644
index 000000000..627cc8519
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0022.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0022.webp
new file mode 100644
index 000000000..e86002f05
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0023.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0023.webp
new file mode 100644
index 000000000..7bce48d7f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0024.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0024.webp
new file mode 100644
index 000000000..70258dc12
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeleft_0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0001.png
deleted file mode 100644
index 6c015a13f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0002.png
deleted file mode 100644
index 6853f69e0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0003.png
deleted file mode 100644
index 29602c492..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0004.png
deleted file mode 100644
index d8321aac6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0005.png
deleted file mode 100644
index 7160a4927..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0006.png
deleted file mode 100644
index 19af0c4f3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0007.png
deleted file mode 100644
index e021c5ad4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0008.png
deleted file mode 100644
index f5a46a69b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0009.png
deleted file mode 100644
index 519e907ee..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0010.png
deleted file mode 100644
index 39c1e787f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0011.png
deleted file mode 100644
index d7b2f9fae..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0012.png
deleted file mode 100644
index 1309106bd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0013.png
deleted file mode 100644
index f212a3a97..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0014.png
deleted file mode 100644
index 2040054ba..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0015.png
deleted file mode 100644
index 4f6c7d842..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0016.png
deleted file mode 100644
index 23f8f1959..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0017.png
deleted file mode 100644
index 880f02f38..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0018.png
deleted file mode 100644
index 4f103a178..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0019.png
deleted file mode 100644
index c8c2af3ae..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0020.png
deleted file mode 100644
index 26b52aec2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0021.png
deleted file mode 100644
index fe2eb30a0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0022.png
deleted file mode 100644
index 36f31eee7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0023.png
deleted file mode 100644
index 0380fbe24..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0024.png
deleted file mode 100644
index 6c015a13f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0001.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0001.webp
new file mode 100644
index 000000000..1b2232370
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0002.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0002.webp
new file mode 100644
index 000000000..c9d784f9a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0003.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0003.webp
new file mode 100644
index 000000000..9c0a2132f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0004.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0004.webp
new file mode 100644
index 000000000..73098ec4f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0005.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0005.webp
new file mode 100644
index 000000000..b31335618
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0006.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0006.webp
new file mode 100644
index 000000000..9a730b96c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0007.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0007.webp
new file mode 100644
index 000000000..9175e9f45
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0008.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0008.webp
new file mode 100644
index 000000000..aacee9e03
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0009.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0009.webp
new file mode 100644
index 000000000..3259011a0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0010.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0010.webp
new file mode 100644
index 000000000..b3245db41
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0011.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0011.webp
new file mode 100644
index 000000000..e3d310304
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0012.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0012.webp
new file mode 100644
index 000000000..9652d2750
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0013.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0013.webp
new file mode 100644
index 000000000..b410164bb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0014.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0014.webp
new file mode 100644
index 000000000..83d3fda69
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0015.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0015.webp
new file mode 100644
index 000000000..1f358d296
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0016.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0016.webp
new file mode 100644
index 000000000..e68248602
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0017.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0017.webp
new file mode 100644
index 000000000..f51a01860
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0018.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0018.webp
new file mode 100644
index 000000000..967bcb37f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0019.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0019.webp
new file mode 100644
index 000000000..276c00e88
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0020.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0020.webp
new file mode 100644
index 000000000..8e2b0f405
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0021.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0021.webp
new file mode 100644
index 000000000..ba2213ae2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0022.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0022.webp
new file mode 100644
index 000000000..a3504e23e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0023.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0023.webp
new file mode 100644
index 000000000..b28994740
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0024.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0024.webp
new file mode 100644
index 000000000..1b2232370
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swiperight_0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0001.png
deleted file mode 100644
index 6c015a13f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0002.png
deleted file mode 100644
index 1d57e3626..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0003.png
deleted file mode 100644
index 3cfd41a38..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0004.png
deleted file mode 100644
index 9f638e37a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0005.png
deleted file mode 100644
index e47e5c521..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0006.png
deleted file mode 100644
index 695faa88a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0007.png
deleted file mode 100644
index c84b7557b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0008.png
deleted file mode 100644
index e1d6221d5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0009.png
deleted file mode 100644
index 7ccea8b23..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0010.png
deleted file mode 100644
index e3ccda35d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0011.png
deleted file mode 100644
index 5cc80843e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0012.png
deleted file mode 100644
index b19ba8400..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0013.png
deleted file mode 100644
index 634c8d7c0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0014.png
deleted file mode 100644
index ff68c2f24..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0015.png
deleted file mode 100644
index 05b59097f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0016.png
deleted file mode 100644
index d4cee897e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0017.png
deleted file mode 100644
index 4c0a70cc8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0018.png
deleted file mode 100644
index 501a1067a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0019.png
deleted file mode 100644
index 826acff7a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0020.png
deleted file mode 100644
index b10414eba..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0021.png
deleted file mode 100644
index c4361924c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0022.png
deleted file mode 100644
index 123161f94..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0023.png
deleted file mode 100644
index dddf711b0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0024.png
deleted file mode 100644
index 6c015a13f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0001.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0001.webp
new file mode 100644
index 000000000..1b2232370
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0002.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0002.webp
new file mode 100644
index 000000000..a3df898dc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0003.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0003.webp
new file mode 100644
index 000000000..b424d3bc3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0004.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0004.webp
new file mode 100644
index 000000000..308d48e0c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0005.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0005.webp
new file mode 100644
index 000000000..5dc48743c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0006.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0006.webp
new file mode 100644
index 000000000..e2071f99a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0007.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0007.webp
new file mode 100644
index 000000000..e44dce9b0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0008.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0008.webp
new file mode 100644
index 000000000..3a349f27b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0009.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0009.webp
new file mode 100644
index 000000000..7f22d29a6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0010.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0010.webp
new file mode 100644
index 000000000..ee26b5c66
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0011.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0011.webp
new file mode 100644
index 000000000..09baac38f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0012.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0012.webp
new file mode 100644
index 000000000..2f0f4ef9f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0013.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0013.webp
new file mode 100644
index 000000000..f7563d6a0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0014.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0014.webp
new file mode 100644
index 000000000..cfd8aea53
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0015.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0015.webp
new file mode 100644
index 000000000..d5ca2fbc1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0016.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0016.webp
new file mode 100644
index 000000000..48f43ff78
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0017.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0017.webp
new file mode 100644
index 000000000..a33bae044
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0018.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0018.webp
new file mode 100644
index 000000000..50a2d60ef
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0019.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0019.webp
new file mode 100644
index 000000000..4af9470dc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0020.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0020.webp
new file mode 100644
index 000000000..1ec082ae0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0021.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0021.webp
new file mode 100644
index 000000000..ab3d06985
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0022.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0022.webp
new file mode 100644
index 000000000..620e3c59a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0023.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0023.webp
new file mode 100644
index 000000000..73b52340f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0024.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0024.webp
new file mode 100644
index 000000000..1b2232370
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_swipeup_0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0001.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0001.png
deleted file mode 100644
index e0d068825..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0002.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0002.png
deleted file mode 100644
index 5dd751adc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0003.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0003.png
deleted file mode 100644
index b1d5d528a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0004.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0004.png
deleted file mode 100644
index fdf4a6389..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0005.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0005.png
deleted file mode 100644
index 65a5dc934..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0006.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0006.png
deleted file mode 100644
index 83a7a34f1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0007.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0007.png
deleted file mode 100644
index a217e428e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0008.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0008.png
deleted file mode 100644
index 2a905d350..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0009.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0009.png
deleted file mode 100644
index 47e8e1827..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0010.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0010.png
deleted file mode 100644
index 0d585b2b1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0011.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0011.png
deleted file mode 100644
index 38ad8e972..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0012.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0012.png
deleted file mode 100644
index 9d5efd509..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0013.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0013.png
deleted file mode 100644
index 42bfac5a8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0014.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0014.png
deleted file mode 100644
index efe5bb92a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0015.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0015.png
deleted file mode 100644
index 19a995fdc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0016.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0016.png
deleted file mode 100644
index e9e7bf8c8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0017.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0017.png
deleted file mode 100644
index b85340d40..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0018.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0018.png
deleted file mode 100644
index 648514c89..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0019.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0019.png
deleted file mode 100644
index e0d068825..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0020.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0020.png
deleted file mode 100644
index e0d068825..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0021.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0021.png
deleted file mode 100644
index e0d068825..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0022.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0022.png
deleted file mode 100644
index e0d068825..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0023.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0023.png
deleted file mode 100644
index e0d068825..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0024.png b/dasherdancer/src/main/res/drawable-nodpi/elf_tap0024.png
deleted file mode 100644
index e0d068825..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/elf_tap0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0001.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0001.webp
new file mode 100644
index 000000000..fb1212da9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0002.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0002.webp
new file mode 100644
index 000000000..6a5d627a5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0003.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0003.webp
new file mode 100644
index 000000000..3d05805e5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0004.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0004.webp
new file mode 100644
index 000000000..d787db708
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0005.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0005.webp
new file mode 100644
index 000000000..16955c05b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0006.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0006.webp
new file mode 100644
index 000000000..560f53410
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0007.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0007.webp
new file mode 100644
index 000000000..9bad83d67
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0008.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0008.webp
new file mode 100644
index 000000000..9e20193fc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0009.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0009.webp
new file mode 100644
index 000000000..1168cfa9d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0010.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0010.webp
new file mode 100644
index 000000000..e0c7d9f95
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0011.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0011.webp
new file mode 100644
index 000000000..d106f5f1b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0012.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0012.webp
new file mode 100644
index 000000000..640e72320
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0013.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0013.webp
new file mode 100644
index 000000000..0df6ace89
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0014.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0014.webp
new file mode 100644
index 000000000..01459bc59
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0015.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0015.webp
new file mode 100644
index 000000000..36570c119
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0016.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0016.webp
new file mode 100644
index 000000000..62292f3d0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0017.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0017.webp
new file mode 100644
index 000000000..05b2de0be
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0018.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0018.webp
new file mode 100644
index 000000000..9943a324e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0019.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0019.webp
new file mode 100644
index 000000000..fb1212da9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0020.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0020.webp
new file mode 100644
index 000000000..fb1212da9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0021.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0021.webp
new file mode 100644
index 000000000..fb1212da9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0022.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0022.webp
new file mode 100644
index 000000000..fb1212da9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0023.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0023.webp
new file mode 100644
index 000000000..fb1212da9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0024.webp b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0024.webp
new file mode 100644
index 000000000..fb1212da9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/elf_tap_0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer.png
deleted file mode 100644
index 2c58a3006..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer.webp
new file mode 100644
index 000000000..f7f4a38ac
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0001.png
deleted file mode 100644
index 2cedb55dc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0001.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0001.webp
new file mode 100644
index 000000000..4e6095427
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0002.png
deleted file mode 100644
index 1149dbacb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0002.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0002.webp
new file mode 100644
index 000000000..eb1586e4a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0003.png
deleted file mode 100644
index b3d9869bb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0003.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0003.webp
new file mode 100644
index 000000000..2ceaebca0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0004.png
deleted file mode 100644
index 64e4a54fb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0004.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0004.webp
new file mode 100644
index 000000000..ebc26e002
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0005.png
deleted file mode 100644
index d824c90cd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0005.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0005.webp
new file mode 100644
index 000000000..a69efce2d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0006.png
deleted file mode 100644
index 958a041e5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0006.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0006.webp
new file mode 100644
index 000000000..216adbee5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0007.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0007.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0007.webp
new file mode 100644
index 000000000..b462438c3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0008.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0009.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0010.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0011.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0012.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0013.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0014.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0015.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0016.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0017.png
deleted file mode 100644
index 8dbcfb53b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0018.png
deleted file mode 100644
index e3c49f3f1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0018.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0018.webp
new file mode 100644
index 000000000..10e33fdc4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0019.png
deleted file mode 100644
index 52c3f3362..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0019.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0019.webp
new file mode 100644
index 000000000..14cbf9c39
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0020.png
deleted file mode 100644
index b5adfacab..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0020.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0020.webp
new file mode 100644
index 000000000..7e616c173
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0021.png
deleted file mode 100644
index 43eac7e6d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0021.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0021.webp
new file mode 100644
index 000000000..01729be99
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0022.png
deleted file mode 100644
index 1bad9963c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0022.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0022.webp
new file mode 100644
index 000000000..28606f001
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0023.png
deleted file mode 100644
index 4111d37c1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0023.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0023.webp
new file mode 100644
index 000000000..8bde5b5af
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0024.png
deleted file mode 100644
index 2cedb55dc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchin0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0001.png
deleted file mode 100644
index 830e7ec19..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0001.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0001.webp
new file mode 100644
index 000000000..11042d205
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0002.png
deleted file mode 100644
index e46105e42..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0002.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0002.webp
new file mode 100644
index 000000000..d376a9e21
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0003.png
deleted file mode 100644
index 4839b18dc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0003.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0003.webp
new file mode 100644
index 000000000..ae5c38c8c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0004.png
deleted file mode 100644
index bf07ed93e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0004.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0004.webp
new file mode 100644
index 000000000..7489fd3c6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0005.png
deleted file mode 100644
index 93a997407..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0005.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0005.webp
new file mode 100644
index 000000000..db14714b2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0006.png
deleted file mode 100644
index 7fc12dcd3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0006.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0006.webp
new file mode 100644
index 000000000..d28f0bad6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0007.png
deleted file mode 100644
index 32cd889b8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0007.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0007.webp
new file mode 100644
index 000000000..a986227e3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0008.png
deleted file mode 100644
index 1f90e40c2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0008.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0008.webp
new file mode 100644
index 000000000..a1e50d28e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0009.png
deleted file mode 100644
index 833c55ba9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0009.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0009.webp
new file mode 100644
index 000000000..7f6d5c2f6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0010.png
deleted file mode 100644
index 8f75a31ad..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0010.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0010.webp
new file mode 100644
index 000000000..2f21bb7fb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0011.png
deleted file mode 100644
index 9c52013d5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0011.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0011.webp
new file mode 100644
index 000000000..36a52d6d7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0012.png
deleted file mode 100644
index 33f09b80d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0012.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0012.webp
new file mode 100644
index 000000000..7db3f2fd6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0013.png
deleted file mode 100644
index 23f28d835..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0013.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0013.webp
new file mode 100644
index 000000000..36848aec6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0014.png
deleted file mode 100644
index d21b17eca..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0014.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0014.webp
new file mode 100644
index 000000000..320d586af
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0015.png
deleted file mode 100644
index 0efb5086c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0015.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0015.webp
new file mode 100644
index 000000000..f713e6d6f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0016.png
deleted file mode 100644
index d6a3f4b50..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0016.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0016.webp
new file mode 100644
index 000000000..4569bed01
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0017.png
deleted file mode 100644
index c1c32baaa..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0017.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0017.webp
new file mode 100644
index 000000000..a0a7b8b59
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0018.png
deleted file mode 100644
index f620c53a8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0018.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0018.webp
new file mode 100644
index 000000000..23fe5c4f3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0019.png
deleted file mode 100644
index 4a5d25b49..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0019.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0019.webp
new file mode 100644
index 000000000..61f4a0db9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0020.png
deleted file mode 100644
index 0e9742247..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0020.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0020.webp
new file mode 100644
index 000000000..88b868128
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0021.png
deleted file mode 100644
index 3d9af5468..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0021.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0021.webp
new file mode 100644
index 000000000..c149d97cd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0022.png
deleted file mode 100644
index 1dcbcc7b7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0022.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0022.webp
new file mode 100644
index 000000000..aa4e4582f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0023.png
deleted file mode 100644
index 0f188bf7f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0023.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0023.webp
new file mode 100644
index 000000000..929e874b8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0024.png
deleted file mode 100644
index 2ef561eba..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0024.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0024.webp
new file mode 100644
index 000000000..ebb6a1123
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_pinchout0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0001.png
deleted file mode 100644
index 830e7ec19..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0002.png
deleted file mode 100644
index 4594b943e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0002.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0002.webp
new file mode 100644
index 000000000..f6e7953b9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0003.png
deleted file mode 100644
index c83543cb6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0003.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0003.webp
new file mode 100644
index 000000000..5eab30e7c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0004.png
deleted file mode 100644
index 814b93848..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0004.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0004.webp
new file mode 100644
index 000000000..3327fac29
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0005.png
deleted file mode 100644
index 2a715538e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0005.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0005.webp
new file mode 100644
index 000000000..43eb0f645
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0006.png
deleted file mode 100644
index a264994c8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0006.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0006.webp
new file mode 100644
index 000000000..b7bc99d8f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0007.png
deleted file mode 100644
index 0429b1936..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0007.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0007.webp
new file mode 100644
index 000000000..890dc021b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0008.png
deleted file mode 100644
index 18a2a34cc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0008.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0008.webp
new file mode 100644
index 000000000..ea8382378
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0009.png
deleted file mode 100644
index 88e2bfe36..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0009.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0009.webp
new file mode 100644
index 000000000..875ab24ce
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0010.png
deleted file mode 100644
index efda24d8d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0010.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0010.webp
new file mode 100644
index 000000000..51c6ce8ff
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0011.png
deleted file mode 100644
index 5482728dc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0011.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0011.webp
new file mode 100644
index 000000000..d33d9ecdd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0012.png
deleted file mode 100644
index 9cbb19786..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0012.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0012.webp
new file mode 100644
index 000000000..c0b5b31ca
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0013.png
deleted file mode 100644
index 4bf71379e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0013.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0013.webp
new file mode 100644
index 000000000..05fe7dd1b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0014.png
deleted file mode 100644
index ec16c4e17..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0014.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0014.webp
new file mode 100644
index 000000000..86ed3f92f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0015.png
deleted file mode 100644
index 7b53fec0c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0015.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0015.webp
new file mode 100644
index 000000000..dc07f2c5b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0016.png
deleted file mode 100644
index ccbfa9b96..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0016.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0016.webp
new file mode 100644
index 000000000..67325aa1a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0017.png
deleted file mode 100644
index cc6e34a0b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0017.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0017.webp
new file mode 100644
index 000000000..ff80596b7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0018.png
deleted file mode 100644
index 0aafee8ee..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0018.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0018.webp
new file mode 100644
index 000000000..deec14226
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0019.png
deleted file mode 100644
index 9b07dd74a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0019.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0019.webp
new file mode 100644
index 000000000..309769577
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0020.png
deleted file mode 100644
index 89103de3e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0020.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0020.webp
new file mode 100644
index 000000000..ea26e8cdf
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0021.png
deleted file mode 100644
index 7b54ef65e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0021.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0021.webp
new file mode 100644
index 000000000..58c7f99e0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0022.png
deleted file mode 100644
index 30031462f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0022.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0022.webp
new file mode 100644
index 000000000..183e74ef9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0023.png
deleted file mode 100644
index 7567ca448..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0023.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0023.webp
new file mode 100644
index 000000000..f72b79000
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0024.png
deleted file mode 100644
index 84dab29eb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0024.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0024.webp
new file mode 100644
index 000000000..5b83392f0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_shake0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0001.png
deleted file mode 100644
index 7ee857bf1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0001.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0001.webp
new file mode 100644
index 000000000..ab5c078da
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0002.png
deleted file mode 100644
index 18f90ec03..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0002.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0002.webp
new file mode 100644
index 000000000..03d3f1959
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0003.png
deleted file mode 100644
index 87e47c927..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0003.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0003.webp
new file mode 100644
index 000000000..6e64c58d6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0004.png
deleted file mode 100644
index 6d224b4fc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0004.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0004.webp
new file mode 100644
index 000000000..a583dd937
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0005.png
deleted file mode 100644
index e97e9ecef..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0005.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0005.webp
new file mode 100644
index 000000000..3b0e9b6be
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0006.png
deleted file mode 100644
index e54f86e6a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0006.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0006.webp
new file mode 100644
index 000000000..71c1f4ff7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0007.png
deleted file mode 100644
index 48e8322bb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0007.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0007.webp
new file mode 100644
index 000000000..c45694f34
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0008.png
deleted file mode 100644
index 34ae3f298..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0008.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0008.webp
new file mode 100644
index 000000000..0aebad959
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0009.png
deleted file mode 100644
index e7e360688..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0009.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0009.webp
new file mode 100644
index 000000000..42e95a11d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0010.png
deleted file mode 100644
index 88535ab0b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0010.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0010.webp
new file mode 100644
index 000000000..bce0b40ed
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0011.png
deleted file mode 100644
index 8e255b902..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0011.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0011.webp
new file mode 100644
index 000000000..877b2f42e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0012.png
deleted file mode 100644
index 54e841f0c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0012.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0012.webp
new file mode 100644
index 000000000..84d305230
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0013.png
deleted file mode 100644
index 65d2f1eef..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0013.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0013.webp
new file mode 100644
index 000000000..b401eee86
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0014.png
deleted file mode 100644
index 97d3f55ce..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0014.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0014.webp
new file mode 100644
index 000000000..f33bccec5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0015.png
deleted file mode 100644
index 8608a2ddd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0015.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0015.webp
new file mode 100644
index 000000000..48832c3c5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0016.png
deleted file mode 100644
index 5a7498679..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0016.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0016.webp
new file mode 100644
index 000000000..ed35a566e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0017.png
deleted file mode 100644
index 75c86b9c5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0017.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0017.webp
new file mode 100644
index 000000000..30352840a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0018.png
deleted file mode 100644
index 86b47538f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0018.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0018.webp
new file mode 100644
index 000000000..b47220f5e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0019.png
deleted file mode 100644
index 04c722a93..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0019.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0019.webp
new file mode 100644
index 000000000..d21f5858d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0020.png
deleted file mode 100644
index 45e3b6894..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0020.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0020.webp
new file mode 100644
index 000000000..e1ce8bd0b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0021.png
deleted file mode 100644
index ca44daada..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0021.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0021.webp
new file mode 100644
index 000000000..d633a8708
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0022.png
deleted file mode 100644
index 5c1dcb057..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0022.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0022.webp
new file mode 100644
index 000000000..195abc356
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0023.png
deleted file mode 100644
index 673a0bd61..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0023.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0023.webp
new file mode 100644
index 000000000..c587f5781
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0024.png
deleted file mode 100644
index 7ee857bf1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipedown0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0001.png
deleted file mode 100644
index 5ba59356c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0001.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0001.webp
new file mode 100644
index 000000000..0cfcb07aa
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0002.png
deleted file mode 100644
index e2856daf1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0002.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0002.webp
new file mode 100644
index 000000000..bc1436f19
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0003.png
deleted file mode 100644
index 70cb533cc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0003.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0003.webp
new file mode 100644
index 000000000..4432f5585
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0004.png
deleted file mode 100644
index 49817f5ea..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0004.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0004.webp
new file mode 100644
index 000000000..f27520474
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0005.png
deleted file mode 100644
index 9d19bda8d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0005.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0005.webp
new file mode 100644
index 000000000..cba5f0480
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0006.png
deleted file mode 100644
index a06978f25..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0006.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0006.webp
new file mode 100644
index 000000000..c2aad9a55
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0007.png
deleted file mode 100644
index cd3d22836..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0007.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0007.webp
new file mode 100644
index 000000000..3d72a3af2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0008.png
deleted file mode 100644
index 70f84a1f1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0008.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0008.webp
new file mode 100644
index 000000000..45c929847
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0009.png
deleted file mode 100644
index edefd69a4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0009.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0009.webp
new file mode 100644
index 000000000..fb909c790
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0010.png
deleted file mode 100644
index 4afde9c36..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0010.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0010.webp
new file mode 100644
index 000000000..839ae9402
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0011.png
deleted file mode 100644
index 5587d4c3e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0011.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0011.webp
new file mode 100644
index 000000000..0538cd93d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0012.png
deleted file mode 100644
index b14f1c889..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0012.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0012.webp
new file mode 100644
index 000000000..3d1b042fa
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0013.png
deleted file mode 100644
index c6551763f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0013.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0013.webp
new file mode 100644
index 000000000..53abd3a08
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0014.png
deleted file mode 100644
index 5dec7ae46..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0014.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0014.webp
new file mode 100644
index 000000000..00efa1778
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0015.png
deleted file mode 100644
index 91e65169e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0015.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0015.webp
new file mode 100644
index 000000000..e4f4db277
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0016.png
deleted file mode 100644
index 9f675e46f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0016.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0016.webp
new file mode 100644
index 000000000..dec61327c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0017.png
deleted file mode 100644
index 7c2c129d0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0017.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0017.webp
new file mode 100644
index 000000000..7210fbba1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0018.png
deleted file mode 100644
index 29dd9b771..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0018.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0018.webp
new file mode 100644
index 000000000..f94e56532
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0019.png
deleted file mode 100644
index 339a577c0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0019.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0019.webp
new file mode 100644
index 000000000..1528a2aed
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0020.png
deleted file mode 100644
index 42182f2ec..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0020.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0020.webp
new file mode 100644
index 000000000..30b2c15d2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0021.png
deleted file mode 100644
index 8842f06a6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0021.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0021.webp
new file mode 100644
index 000000000..5bd2b0dca
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0022.png
deleted file mode 100644
index 5a7aa4b69..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0022.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0022.webp
new file mode 100644
index 000000000..3d601c03f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0023.png
deleted file mode 100644
index 99264dfdd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0023.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0023.webp
new file mode 100644
index 000000000..ac75784cd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0024.png
deleted file mode 100644
index fe22f7718..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0024.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0024.webp
new file mode 100644
index 000000000..aababc884
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeleft0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0001.png
deleted file mode 100644
index 982154340..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0001.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0001.webp
new file mode 100644
index 000000000..53d5d41d4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0002.png
deleted file mode 100644
index bc8068d5d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0002.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0002.webp
new file mode 100644
index 000000000..50ce7329e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0003.png
deleted file mode 100644
index 549240003..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0003.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0003.webp
new file mode 100644
index 000000000..45deea0bc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0004.png
deleted file mode 100644
index a7ddb6ce9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0004.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0004.webp
new file mode 100644
index 000000000..efb2956a1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0005.png
deleted file mode 100644
index 46db354b1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0005.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0005.webp
new file mode 100644
index 000000000..f56da473a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0006.png
deleted file mode 100644
index f3bcda2f8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0006.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0006.webp
new file mode 100644
index 000000000..bdfa7a14e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0007.png
deleted file mode 100644
index fce370011..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0007.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0007.webp
new file mode 100644
index 000000000..5063ff21b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0008.png
deleted file mode 100644
index 574e0702d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0008.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0008.webp
new file mode 100644
index 000000000..128094425
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0009.png
deleted file mode 100644
index 569c3815f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0009.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0009.webp
new file mode 100644
index 000000000..12e885f9b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0010.png
deleted file mode 100644
index f276e09ba..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0010.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0010.webp
new file mode 100644
index 000000000..11337c6d5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0011.png
deleted file mode 100644
index 146a1757a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0011.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0011.webp
new file mode 100644
index 000000000..bd2c01509
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0012.png
deleted file mode 100644
index 52b0c4b9f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0012.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0012.webp
new file mode 100644
index 000000000..17ceeec9c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0013.png
deleted file mode 100644
index 14ba9bfae..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0013.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0013.webp
new file mode 100644
index 000000000..1d9a3be20
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0014.png
deleted file mode 100644
index 92d26654b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0014.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0014.webp
new file mode 100644
index 000000000..f06084b30
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0015.png
deleted file mode 100644
index edde12d31..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0015.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0015.webp
new file mode 100644
index 000000000..cad966448
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0016.png
deleted file mode 100644
index 27f08791d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0016.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0016.webp
new file mode 100644
index 000000000..901cad6fe
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0017.png
deleted file mode 100644
index eaaf575b6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0017.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0017.webp
new file mode 100644
index 000000000..37940046d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0018.png
deleted file mode 100644
index 56429a9d1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0018.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0018.webp
new file mode 100644
index 000000000..0645963cb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0019.png
deleted file mode 100644
index c74ee5812..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0019.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0019.webp
new file mode 100644
index 000000000..1f7aa4819
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0020.png
deleted file mode 100644
index 67e41e2d7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0020.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0020.webp
new file mode 100644
index 000000000..a8824edbd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0021.png
deleted file mode 100644
index c9aece9f2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0021.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0021.webp
new file mode 100644
index 000000000..ea8cbb5b3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0022.png
deleted file mode 100644
index dc43e63c9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0022.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0022.webp
new file mode 100644
index 000000000..e79945bfa
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0023.png
deleted file mode 100644
index 6963c23cc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0023.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0023.webp
new file mode 100644
index 000000000..7c9d4b6e8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0024.png
deleted file mode 100644
index 1899123e2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0024.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0024.webp
new file mode 100644
index 000000000..d4718bf3b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swiperight0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0001.png
deleted file mode 100644
index d64816178..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0001.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0001.webp
new file mode 100644
index 000000000..96988ee49
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0002.png
deleted file mode 100644
index 57a84edbf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0002.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0002.webp
new file mode 100644
index 000000000..04b62fe42
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0003.png
deleted file mode 100644
index f48d1fc48..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0003.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0003.webp
new file mode 100644
index 000000000..e44bb45a5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0004.png
deleted file mode 100644
index 241d5a35a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0004.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0004.webp
new file mode 100644
index 000000000..0b14f532f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0005.png
deleted file mode 100644
index 46f0ed0b7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0005.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0005.webp
new file mode 100644
index 000000000..f06ead9e3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0006.png
deleted file mode 100644
index 98f952071..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0006.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0006.webp
new file mode 100644
index 000000000..3c681bcaa
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0007.png
deleted file mode 100644
index dc5600df5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0007.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0007.webp
new file mode 100644
index 000000000..1f921e69a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0008.png
deleted file mode 100644
index 42100e713..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0008.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0008.webp
new file mode 100644
index 000000000..bb9d7211f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0009.png
deleted file mode 100644
index 492e60dfc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0009.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0009.webp
new file mode 100644
index 000000000..95500e288
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0010.png
deleted file mode 100644
index 9bd1330d3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0010.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0010.webp
new file mode 100644
index 000000000..20d777dcf
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0011.png
deleted file mode 100644
index 6e566c090..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0011.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0011.webp
new file mode 100644
index 000000000..bd47f3214
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0012.png
deleted file mode 100644
index ade635c49..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0012.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0012.webp
new file mode 100644
index 000000000..ba4c0d5f8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0013.png
deleted file mode 100644
index e80f37ea7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0013.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0013.webp
new file mode 100644
index 000000000..4c655220d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0014.png
deleted file mode 100644
index 4a1c1afd7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0014.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0014.webp
new file mode 100644
index 000000000..580258c30
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0015.png
deleted file mode 100644
index 3561ef789..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0015.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0015.webp
new file mode 100644
index 000000000..a8f4d26c6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0016.png
deleted file mode 100644
index eeaebdc47..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0016.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0016.webp
new file mode 100644
index 000000000..67f52ff26
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0017.png
deleted file mode 100644
index c368484c3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0017.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0017.webp
new file mode 100644
index 000000000..5732be634
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0018.png
deleted file mode 100644
index bb89d546e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0018.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0018.webp
new file mode 100644
index 000000000..4d5a365b3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0019.png
deleted file mode 100644
index 0b389636f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0019.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0019.webp
new file mode 100644
index 000000000..254ad5a0e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0020.png
deleted file mode 100644
index 7de27dace..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0020.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0020.webp
new file mode 100644
index 000000000..14a87c01b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0021.png
deleted file mode 100644
index c236bb770..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0021.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0021.webp
new file mode 100644
index 000000000..702103924
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0022.png
deleted file mode 100644
index 9ea3b715b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0022.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0022.webp
new file mode 100644
index 000000000..d5cb07858
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0023.png
deleted file mode 100644
index af8da2178..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0023.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0023.webp
new file mode 100644
index 000000000..c5302c042
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0024.png
deleted file mode 100644
index d64816178..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_swipeup0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0001.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0001.png
deleted file mode 100644
index 8ff93c534..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0001.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0001.webp
new file mode 100644
index 000000000..6f741b3c6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0002.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0002.png
deleted file mode 100644
index 4d4a01f6b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0002.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0002.webp
new file mode 100644
index 000000000..5f2622f92
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0003.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0003.png
deleted file mode 100644
index dbe41b1fb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0003.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0003.webp
new file mode 100644
index 000000000..426566f88
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0004.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0004.png
deleted file mode 100644
index a95c86df7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0004.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0004.webp
new file mode 100644
index 000000000..e0090ed0f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0005.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0005.png
deleted file mode 100644
index 7abea52b2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0005.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0005.webp
new file mode 100644
index 000000000..81eb11c4b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0006.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0006.png
deleted file mode 100644
index ec5840be0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0006.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0006.webp
new file mode 100644
index 000000000..0ab69e312
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0007.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0007.png
deleted file mode 100644
index 374c9b36b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0007.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0007.webp
new file mode 100644
index 000000000..64e12877f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0008.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0008.png
deleted file mode 100644
index d82439ca0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0008.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0008.webp
new file mode 100644
index 000000000..2f0af550c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0009.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0009.png
deleted file mode 100644
index b3e6b2863..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0009.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0009.webp
new file mode 100644
index 000000000..38268050f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0010.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0010.png
deleted file mode 100644
index 879518dcf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0010.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0010.webp
new file mode 100644
index 000000000..c09015288
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0011.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0011.png
deleted file mode 100644
index 879518dcf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0012.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0012.png
deleted file mode 100644
index 879518dcf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0013.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0013.png
deleted file mode 100644
index 879518dcf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0014.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0014.png
deleted file mode 100644
index 879518dcf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0015.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0015.png
deleted file mode 100644
index 879518dcf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0016.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0016.png
deleted file mode 100644
index 879518dcf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0017.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0017.png
deleted file mode 100644
index 879518dcf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0018.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0018.png
deleted file mode 100644
index 879518dcf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0019.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0019.png
deleted file mode 100644
index 33de42a1c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0019.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0019.webp
new file mode 100644
index 000000000..56d1fb356
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0020.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0020.png
deleted file mode 100644
index 66115d214..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0020.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0020.webp
new file mode 100644
index 000000000..296bfa135
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0021.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0021.png
deleted file mode 100644
index 960e98481..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0021.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0021.webp
new file mode 100644
index 000000000..987c68528
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0022.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0022.png
deleted file mode 100644
index 73b97d383..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0022.webp b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0022.webp
new file mode 100644
index 000000000..63e39a1e2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0023.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0023.png
deleted file mode 100644
index 7abea52b2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0024.png b/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0024.png
deleted file mode 100644
index 7abea52b2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/reindeer_tap0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa.png b/dasherdancer/src/main/res/drawable-nodpi/santa.png
deleted file mode 100644
index 3a841f400..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa.webp b/dasherdancer/src/main/res/drawable-nodpi/santa.webp
new file mode 100644
index 000000000..e541a459a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0001.png
deleted file mode 100644
index 102722b18..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0001.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0001.webp
new file mode 100644
index 000000000..bcd03bfd8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0002.png
deleted file mode 100644
index 9f9fc55ed..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0002.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0002.webp
new file mode 100644
index 000000000..b4d257613
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0003.png
deleted file mode 100644
index 82a4c5c9e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0003.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0003.webp
new file mode 100644
index 000000000..e216490cd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0004.png
deleted file mode 100644
index 1f4a08467..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0004.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0004.webp
new file mode 100644
index 000000000..864cd6c60
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0005.png
deleted file mode 100644
index c5e523443..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0005.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0005.webp
new file mode 100644
index 000000000..c9636698c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0006.png
deleted file mode 100644
index 85c89a641..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0006.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0006.webp
new file mode 100644
index 000000000..d5473b4df
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0007.png
deleted file mode 100644
index 4d798347e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0007.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0007.webp
new file mode 100644
index 000000000..42c680d20
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0008.png
deleted file mode 100644
index 3fd4d9606..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0008.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0008.webp
new file mode 100644
index 000000000..4475575cc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0009.png
deleted file mode 100644
index 3572acaf8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0009.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0009.webp
new file mode 100644
index 000000000..afb2df216
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0010.png
deleted file mode 100644
index af84d9629..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0010.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0010.webp
new file mode 100644
index 000000000..73396640b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0011.png
deleted file mode 100644
index e39def95e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0011.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0011.webp
new file mode 100644
index 000000000..6f5c63870
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0012.png
deleted file mode 100644
index 013f016ef..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0012.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0012.webp
new file mode 100644
index 000000000..50eb55b03
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0013.png
deleted file mode 100644
index 06ed3ac9e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0013.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0013.webp
new file mode 100644
index 000000000..f7f6bdedb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0014.png
deleted file mode 100644
index 3fd4d9606..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0015.png
deleted file mode 100644
index ceee35f70..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0015.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0015.webp
new file mode 100644
index 000000000..fc28c3be0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0016.png
deleted file mode 100644
index b4042be37..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0016.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0016.webp
new file mode 100644
index 000000000..9062cb8ee
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0017.png
deleted file mode 100644
index 1adf5a89b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0017.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0017.webp
new file mode 100644
index 000000000..4f4a07ccd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0018.png
deleted file mode 100644
index 989f81194..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0018.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0018.webp
new file mode 100644
index 000000000..31fc40c32
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0019.png
deleted file mode 100644
index e85baea3b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0019.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0019.webp
new file mode 100644
index 000000000..3305957cb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0020.png
deleted file mode 100644
index 34a58af74..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0020.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0020.webp
new file mode 100644
index 000000000..b36fd6dcd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0021.png
deleted file mode 100644
index 4d3dc9274..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0021.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0021.webp
new file mode 100644
index 000000000..c19b63469
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0022.png
deleted file mode 100644
index ea1447017..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0022.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0022.webp
new file mode 100644
index 000000000..1ac468b4b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0023.png
deleted file mode 100644
index 102722b18..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0024.png
deleted file mode 100644
index 102722b18..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0025.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0025.png
deleted file mode 100644
index 9f9fc55ed..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0025.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0026.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0026.png
deleted file mode 100644
index 82a4c5c9e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0026.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0027.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0027.png
deleted file mode 100644
index 9b18d9452..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0027.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0027.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0027.webp
new file mode 100644
index 000000000..e71a4235c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0027.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0028.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0028.png
deleted file mode 100644
index 01c33d262..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0028.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0028.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0028.webp
new file mode 100644
index 000000000..4184f698f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0028.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0029.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0029.png
deleted file mode 100644
index 2e78fadae..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0029.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0029.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0029.webp
new file mode 100644
index 000000000..7ffef8f38
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0029.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0030.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0030.png
deleted file mode 100644
index 10472432f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0030.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0030.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0030.webp
new file mode 100644
index 000000000..57707ac49
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0030.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0031.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0031.png
deleted file mode 100644
index 533cf7729..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0031.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0031.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0031.webp
new file mode 100644
index 000000000..e312fe35d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0031.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0032.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0032.png
deleted file mode 100644
index 3fab52715..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0032.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0032.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0032.webp
new file mode 100644
index 000000000..f79ab5ac8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0032.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0033.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0033.png
deleted file mode 100644
index b89ea34d9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0033.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0033.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0033.webp
new file mode 100644
index 000000000..87e19f73b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0033.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0034.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0034.png
deleted file mode 100644
index e39def95e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0034.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0035.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0035.png
deleted file mode 100644
index 013f016ef..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0035.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0036.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0036.png
deleted file mode 100644
index 2e43de83b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0036.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0036.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0036.webp
new file mode 100644
index 000000000..31d89c3f5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0036.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0037.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0037.png
deleted file mode 100644
index 2197b3bab..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0037.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0037.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0037.webp
new file mode 100644
index 000000000..0f41c1214
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0037.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0038.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0038.png
deleted file mode 100644
index cde8afd61..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0038.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0038.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0038.webp
new file mode 100644
index 000000000..9c5bd54a1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0038.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0039.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0039.png
deleted file mode 100644
index 06b86d4fd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0039.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0039.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0039.webp
new file mode 100644
index 000000000..def6c84a2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0039.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0040.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0040.png
deleted file mode 100644
index b9af1764b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0040.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0040.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0040.webp
new file mode 100644
index 000000000..f8d4a38aa
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0040.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0041.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0041.png
deleted file mode 100644
index 679f6b5c2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0041.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0041.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0041.webp
new file mode 100644
index 000000000..3c9129802
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0041.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0042.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0042.png
deleted file mode 100644
index 700492ad3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0042.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0042.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0042.webp
new file mode 100644
index 000000000..14cfbb788
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0042.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0043.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0043.png
deleted file mode 100644
index 86115612c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0043.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0043.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0043.webp
new file mode 100644
index 000000000..c41388c6e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0043.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0044.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0044.png
deleted file mode 100644
index 02987dc27..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0044.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0044.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0044.webp
new file mode 100644
index 000000000..e3fb21fbe
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0044.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0045.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0045.png
deleted file mode 100644
index b89ec1801..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0045.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0045.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0045.webp
new file mode 100644
index 000000000..041cba21b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0045.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0046.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0046.png
deleted file mode 100644
index 2727003ce..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0046.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0046.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0046.webp
new file mode 100644
index 000000000..d0e6b2124
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0046.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0047.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0047.png
deleted file mode 100644
index 82d3a741a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0047.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0047.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0047.webp
new file mode 100644
index 000000000..1edc29d39
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0047.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0048.png b/dasherdancer/src/main/res/drawable-nodpi/santa_idle0048.png
deleted file mode 100644
index 102722b18..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_idle0048.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0001.png
deleted file mode 100644
index 08c890615..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0001.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0001.webp
new file mode 100644
index 000000000..bbdb4bea6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0002.png
deleted file mode 100644
index 21bca6749..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0002.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0002.webp
new file mode 100644
index 000000000..ead9e098e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0003.png
deleted file mode 100644
index a54326bd7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0003.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0003.webp
new file mode 100644
index 000000000..38b2ba77c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0004.png
deleted file mode 100644
index fddb8394a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0004.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0004.webp
new file mode 100644
index 000000000..cf1c5952d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0005.png
deleted file mode 100644
index f12f2a404..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0005.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0005.webp
new file mode 100644
index 000000000..f15014b9f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0006.png
deleted file mode 100644
index daef24b46..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0006.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0006.webp
new file mode 100644
index 000000000..af77a6b0d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0007.png
deleted file mode 100644
index 17fdee8fe..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0007.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0007.webp
new file mode 100644
index 000000000..ac154bb0e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0008.png
deleted file mode 100644
index 7a1fc1629..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0008.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0008.webp
new file mode 100644
index 000000000..c0f22cc6d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0009.png
deleted file mode 100644
index a7d6ef94e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0009.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0009.webp
new file mode 100644
index 000000000..44e84ffe6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0010.png
deleted file mode 100644
index 3fca71da3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0010.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0010.webp
new file mode 100644
index 000000000..fa4275dae
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0011.png
deleted file mode 100644
index a7d6ef94e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0012.png
deleted file mode 100644
index 7a1fc1629..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0013.png
deleted file mode 100644
index dbe2a5aa1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0013.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0013.webp
new file mode 100644
index 000000000..e32da0016
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0014.png
deleted file mode 100644
index 479e0172c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0014.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0014.webp
new file mode 100644
index 000000000..e2a7539b3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0015.png
deleted file mode 100644
index f12f2a404..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0016.png
deleted file mode 100644
index fddb8394a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0017.png
deleted file mode 100644
index 2f8b96e1c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0017.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0017.webp
new file mode 100644
index 000000000..1e9827f3b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0018.png
deleted file mode 100644
index 208be4a9a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0018.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0018.webp
new file mode 100644
index 000000000..2fd6f9c91
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0019.png
deleted file mode 100644
index 875c78baa..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0019.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0019.webp
new file mode 100644
index 000000000..ce73be336
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0020.png
deleted file mode 100644
index 1145d6584..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0020.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0020.webp
new file mode 100644
index 000000000..c3f993bed
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0021.png
deleted file mode 100644
index 2f8b96e1c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0022.png
deleted file mode 100644
index ee3e61751..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0022.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0022.webp
new file mode 100644
index 000000000..456bdcdef
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0023.png
deleted file mode 100644
index 21bca6749..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0024.png
deleted file mode 100644
index 08c890615..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchin0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20001.png
deleted file mode 100644
index c9aae9f64..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20001.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20001.webp
new file mode 100644
index 000000000..3af26a5c9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20002.png
deleted file mode 100644
index 56d246020..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20002.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20002.webp
new file mode 100644
index 000000000..99ab7ffbc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20003.png
deleted file mode 100644
index 174b81809..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20003.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20003.webp
new file mode 100644
index 000000000..3a8c0a972
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20004.png
deleted file mode 100644
index d0099e780..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20004.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20004.webp
new file mode 100644
index 000000000..bcbd7834c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20005.png
deleted file mode 100644
index 14cc6880c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20005.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20005.webp
new file mode 100644
index 000000000..f479f5544
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20006.png
deleted file mode 100644
index 54e897363..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20006.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20006.webp
new file mode 100644
index 000000000..dccd4140f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20007.png
deleted file mode 100644
index 4a3840dcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20007.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20007.webp
new file mode 100644
index 000000000..4edb399e4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20008.png
deleted file mode 100644
index 4a3840dcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20009.png
deleted file mode 100644
index 4a3840dcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20010.png
deleted file mode 100644
index 4a3840dcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20011.png
deleted file mode 100644
index 4a3840dcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20012.png
deleted file mode 100644
index 4a3840dcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20013.png
deleted file mode 100644
index 4a3840dcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20014.png
deleted file mode 100644
index 4a3840dcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20015.png
deleted file mode 100644
index 4a3840dcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20016.png
deleted file mode 100644
index 4a3840dcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20017.png
deleted file mode 100644
index aa712e8f1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20017.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20017.webp
new file mode 100644
index 000000000..45ecbeaee
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20018.png
deleted file mode 100644
index 88d88d15c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20018.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20018.webp
new file mode 100644
index 000000000..6e300dc63
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20019.png
deleted file mode 100644
index eb122aea6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20019.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20019.webp
new file mode 100644
index 000000000..291bab2b6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20020.png
deleted file mode 100644
index ea436c4d9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20020.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20020.webp
new file mode 100644
index 000000000..e6e828a19
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20021.png
deleted file mode 100644
index 03e41b506..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20021.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20021.webp
new file mode 100644
index 000000000..8eec8a7b7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20022.png
deleted file mode 100644
index c9aae9f64..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20023.png
deleted file mode 100644
index 60e96c96d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20023.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20023.webp
new file mode 100644
index 000000000..1df06fa68
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20024.png
deleted file mode 100644
index 60e96c96d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_pinchout20024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0001.png
deleted file mode 100644
index 778276d99..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0001.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0001.webp
new file mode 100644
index 000000000..5e914807b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0002.png
deleted file mode 100644
index af3b404c4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0002.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0002.webp
new file mode 100644
index 000000000..944a1459c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0003.png
deleted file mode 100644
index 5b5098769..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0003.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0003.webp
new file mode 100644
index 000000000..afd65dcef
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0004.png
deleted file mode 100644
index 106621aed..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0004.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0004.webp
new file mode 100644
index 000000000..7e5f761c9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0005.png
deleted file mode 100644
index 7623f11b7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0005.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0005.webp
new file mode 100644
index 000000000..3def2c8ce
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0006.png
deleted file mode 100644
index d5dedecb1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0006.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0006.webp
new file mode 100644
index 000000000..c3921e69a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0007.png
deleted file mode 100644
index 54e805a37..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0007.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0007.webp
new file mode 100644
index 000000000..2c32551c8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0008.png
deleted file mode 100644
index be5e55303..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0008.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0008.webp
new file mode 100644
index 000000000..dcad572cb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0009.png
deleted file mode 100644
index db142d92c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0009.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0009.webp
new file mode 100644
index 000000000..b421230f5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0010.png
deleted file mode 100644
index e05e09b1d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0010.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0010.webp
new file mode 100644
index 000000000..e61438d13
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0011.png
deleted file mode 100644
index ae9893a13..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0011.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0011.webp
new file mode 100644
index 000000000..86c97cc68
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0012.png
deleted file mode 100644
index def5a9fcd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0012.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0012.webp
new file mode 100644
index 000000000..3fd53250d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0013.png
deleted file mode 100644
index 3fb9bdfa5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0013.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0013.webp
new file mode 100644
index 000000000..94f51e440
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0014.png
deleted file mode 100644
index 4910d2156..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0014.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0014.webp
new file mode 100644
index 000000000..0bf5aed8d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0015.png
deleted file mode 100644
index 9557cc69e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0015.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0015.webp
new file mode 100644
index 000000000..48b4e977e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0016.png
deleted file mode 100644
index 570bdeb52..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0016.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0016.webp
new file mode 100644
index 000000000..b28e7d796
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0017.png
deleted file mode 100644
index d93d78a05..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0017.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0017.webp
new file mode 100644
index 000000000..da9db85de
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0018.png
deleted file mode 100644
index a982fefa3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0018.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0018.webp
new file mode 100644
index 000000000..13c697ba3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0019.png
deleted file mode 100644
index 821e2ab95..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0019.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0019.webp
new file mode 100644
index 000000000..2bd4afffc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0020.png
deleted file mode 100644
index 4547b1ee3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0020.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0020.webp
new file mode 100644
index 000000000..ccb54c653
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0021.png
deleted file mode 100644
index 473a6e941..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0021.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0021.webp
new file mode 100644
index 000000000..c10972370
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0022.png
deleted file mode 100644
index 4521a781c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0022.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0022.webp
new file mode 100644
index 000000000..446e84046
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0023.png
deleted file mode 100644
index 0abe1e5c4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0023.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0023.webp
new file mode 100644
index 000000000..252abb7c4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0024.png
deleted file mode 100644
index fe6814992..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_shake0024.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0024.webp
new file mode 100644
index 000000000..a447e9a28
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_shake0024.webp 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
deleted file mode 100644
index 97b489b38..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20001.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20001.webp
new file mode 100644
index 000000000..ba4f97703
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20001.webp 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
deleted file mode 100644
index b22a952a5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20002.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20002.webp
new file mode 100644
index 000000000..517449bd8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20002.webp 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
deleted file mode 100644
index 4addeffaa..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20003.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20003.webp
new file mode 100644
index 000000000..8b9531dcd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20003.webp 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
deleted file mode 100644
index 28b1e6306..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20004.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20004.webp
new file mode 100644
index 000000000..40d1e87c6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20004.webp 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
deleted file mode 100644
index d8d638a42..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20005.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20005.webp
new file mode 100644
index 000000000..edab5d640
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20005.webp 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
deleted file mode 100644
index 2039bae01..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20006.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20006.webp
new file mode 100644
index 000000000..0ad0de26e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20006.webp 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
deleted file mode 100644
index a6838a7ed..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20007.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20007.webp
new file mode 100644
index 000000000..a1d2290cb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20007.webp 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
deleted file mode 100644
index 6e98cf2c5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20008.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20008.webp
new file mode 100644
index 000000000..7fb7dd01f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20008.webp 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
deleted file mode 100644
index 934941169..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20009.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20009.webp
new file mode 100644
index 000000000..a09b4dcc3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20009.webp 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
deleted file mode 100644
index 90ff48772..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20010.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20010.webp
new file mode 100644
index 000000000..10e2324f4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20010.webp 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
deleted file mode 100644
index 8dcaa68f4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20011.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20011.webp
new file mode 100644
index 000000000..aa81994ca
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20011.webp 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
deleted file mode 100644
index 35bf196c7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20012.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20012.webp
new file mode 100644
index 000000000..aa91a7204
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20012.webp 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
deleted file mode 100644
index 3aeeef3d5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20013.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20013.webp
new file mode 100644
index 000000000..01df4af23
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20013.webp 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
deleted file mode 100644
index 7948cc674..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20014.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20014.webp
new file mode 100644
index 000000000..f59c0a8cb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20014.webp 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
deleted file mode 100644
index 23200c132..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20015.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20015.webp
new file mode 100644
index 000000000..ce4e01eb0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20015.webp 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
deleted file mode 100644
index e8b87690b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20016.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20016.webp
new file mode 100644
index 000000000..ec3832119
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20016.webp 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
deleted file mode 100644
index 30435cdbc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20017.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20017.webp
new file mode 100644
index 000000000..d1504d34f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20017.webp 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
deleted file mode 100644
index 0ba926107..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20018.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20018.webp
new file mode 100644
index 000000000..fafc22683
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20018.webp 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
deleted file mode 100644
index 4c73f421f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20019.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20019.webp
new file mode 100644
index 000000000..c7213cb89
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20019.webp 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
deleted file mode 100644
index 7680c785a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20020.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20020.webp
new file mode 100644
index 000000000..2137aca6b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20020.webp 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
deleted file mode 100644
index 131b6515b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20021.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20021.webp
new file mode 100644
index 000000000..57cb28d92
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20021.webp 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
deleted file mode 100644
index 15eb5fa1b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20022.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20022.webp
new file mode 100644
index 000000000..002d96043
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20022.webp 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
deleted file mode 100644
index 07dd2edc0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20023.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20023.webp
new file mode 100644
index 000000000..7c18caf0d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20023.webp 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
deleted file mode 100644
index 2ee120091..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20024.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20024.webp
new file mode 100644
index 000000000..cea4b6ee4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipe_right20024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0001.png
deleted file mode 100644
index 4be7d4ebf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0001.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0001.webp
new file mode 100644
index 000000000..72c215e12
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0002.png
deleted file mode 100644
index 76596cc99..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0002.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0002.webp
new file mode 100644
index 000000000..dc0bcb93c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0003.png
deleted file mode 100644
index 2ad329636..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0003.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0003.webp
new file mode 100644
index 000000000..11b1d2d3c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0004.png
deleted file mode 100644
index 1b6c5d225..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0004.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0004.webp
new file mode 100644
index 000000000..c327d5f6a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0005.png
deleted file mode 100644
index e11a8aa87..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0005.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0005.webp
new file mode 100644
index 000000000..baad2a901
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0006.png
deleted file mode 100644
index 88e4bc07a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0006.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0006.webp
new file mode 100644
index 000000000..7b09a87ad
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0007.png
deleted file mode 100644
index f75588a2a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0007.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0007.webp
new file mode 100644
index 000000000..459d868e5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0008.png
deleted file mode 100644
index 34186f016..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0008.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0008.webp
new file mode 100644
index 000000000..5697c3c68
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0009.png
deleted file mode 100644
index fb4ea9246..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0009.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0009.webp
new file mode 100644
index 000000000..0cc95e067
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0010.png
deleted file mode 100644
index e90d5263e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0010.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0010.webp
new file mode 100644
index 000000000..31bf5abe5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0011.png
deleted file mode 100644
index 58cb7e3a4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0011.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0011.webp
new file mode 100644
index 000000000..9f77631b2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0012.png
deleted file mode 100644
index 0e3f870fe..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0012.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0012.webp
new file mode 100644
index 000000000..e8b933971
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0013.png
deleted file mode 100644
index 26b0c828f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0013.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0013.webp
new file mode 100644
index 000000000..9015b18a3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0014.png
deleted file mode 100644
index 1a0a66110..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0014.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0014.webp
new file mode 100644
index 000000000..afa5f9a05
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0015.png
deleted file mode 100644
index 0406d0382..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0015.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0015.webp
new file mode 100644
index 000000000..fa39ead7e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0016.png
deleted file mode 100644
index d0ea832e6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0016.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0016.webp
new file mode 100644
index 000000000..cc73e440f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0017.png
deleted file mode 100644
index e1fc5d1a6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0017.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0017.webp
new file mode 100644
index 000000000..e3098c071
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0018.png
deleted file mode 100644
index 2db882164..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0018.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0018.webp
new file mode 100644
index 000000000..a6b8bc11c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0019.png
deleted file mode 100644
index da73020e5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0019.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0019.webp
new file mode 100644
index 000000000..425f48411
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0020.png
deleted file mode 100644
index bc46e5851..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0020.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0020.webp
new file mode 100644
index 000000000..38de5b55e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0021.png
deleted file mode 100644
index 25f515b8a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0021.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0021.webp
new file mode 100644
index 000000000..b24bea8b2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0022.png
deleted file mode 100644
index 4162d244e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0022.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0022.webp
new file mode 100644
index 000000000..06b53bba6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0023.png
deleted file mode 100644
index 25c367638..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0023.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0023.webp
new file mode 100644
index 000000000..6abda4db2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0024.png
deleted file mode 100644
index e7d1c2be2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0024.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0024.webp
new file mode 100644
index 000000000..c97ed998c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipedown0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0001.png
deleted file mode 100644
index 08c890615..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0002.png
deleted file mode 100644
index 7f2903769..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0002.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0002.webp
new file mode 100644
index 000000000..040f0c0be
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0003.png
deleted file mode 100644
index 6a8cc022d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0003.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0003.webp
new file mode 100644
index 000000000..02e3c2dcb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0004.png
deleted file mode 100644
index e0acb9987..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0004.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0004.webp
new file mode 100644
index 000000000..cde4358f1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0005.png
deleted file mode 100644
index 057582c05..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0005.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0005.webp
new file mode 100644
index 000000000..5f8e306ee
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0006.png
deleted file mode 100644
index 9d21e1197..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0006.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0006.webp
new file mode 100644
index 000000000..840925046
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0007.png
deleted file mode 100644
index 0fdcd05fc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0007.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0007.webp
new file mode 100644
index 000000000..8dbd34b3d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0008.png
deleted file mode 100644
index c790ac482..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0008.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0008.webp
new file mode 100644
index 000000000..d02f66e7a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0009.png
deleted file mode 100644
index adf586712..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0009.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0009.webp
new file mode 100644
index 000000000..68e33c1bc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0010.png
deleted file mode 100644
index 0fdcd05fc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0011.png
deleted file mode 100644
index 08c890615..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0012.png
deleted file mode 100644
index 21419e3be..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0012.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0012.webp
new file mode 100644
index 000000000..8fd15779a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0013.png
deleted file mode 100644
index 62604f651..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0013.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0013.webp
new file mode 100644
index 000000000..3fabc9f51
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0014.png
deleted file mode 100644
index bae14b90f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0014.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0014.webp
new file mode 100644
index 000000000..9a892b18e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0015.png
deleted file mode 100644
index 6aa78c735..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0015.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0015.webp
new file mode 100644
index 000000000..b55c9d23a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0016.png
deleted file mode 100644
index c7c273884..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0016.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0016.webp
new file mode 100644
index 000000000..6f477daf6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0017.png
deleted file mode 100644
index 8d36347fc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0017.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0017.webp
new file mode 100644
index 000000000..9b766177f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0018.png
deleted file mode 100644
index 6210d55fd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0018.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0018.webp
new file mode 100644
index 000000000..8f581d8ca
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0019.png
deleted file mode 100644
index c16779688..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0019.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0019.webp
new file mode 100644
index 000000000..cf8d40453
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0020.png
deleted file mode 100644
index 73a0c7874..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0020.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0020.webp
new file mode 100644
index 000000000..62494d068
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0021.png
deleted file mode 100644
index be4ef2f80..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0021.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0021.webp
new file mode 100644
index 000000000..bc69eac18
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0022.png
deleted file mode 100644
index 281655078..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0022.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0022.webp
new file mode 100644
index 000000000..988d9f565
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0023.png
deleted file mode 100644
index 39803863c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0023.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0023.webp
new file mode 100644
index 000000000..db2218943
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0024.png
deleted file mode 100644
index eaa2eca85..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0024.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0024.webp
new file mode 100644
index 000000000..94e2451b1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeleft0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0001.png
deleted file mode 100644
index 954d87a71..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0001.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0001.webp
new file mode 100644
index 000000000..a49ad54a1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0002.png
deleted file mode 100644
index 0143c40dc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0002.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0002.webp
new file mode 100644
index 000000000..c4732a897
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0003.png
deleted file mode 100644
index 47a84854a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0003.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0003.webp
new file mode 100644
index 000000000..86c63064c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0004.png
deleted file mode 100644
index c2053aa22..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0004.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0004.webp
new file mode 100644
index 000000000..9cc080d8b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0005.png
deleted file mode 100644
index a248bb4a5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0005.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0005.webp
new file mode 100644
index 000000000..9000c4090
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0006.png
deleted file mode 100644
index 8029858b0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0006.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0006.webp
new file mode 100644
index 000000000..fc1328e5e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0007.png
deleted file mode 100644
index 3c9d01ce9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0007.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0007.webp
new file mode 100644
index 000000000..5a3049c8b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0008.png
deleted file mode 100644
index 2988b8280..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0008.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0008.webp
new file mode 100644
index 000000000..aa9d58f95
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0009.png
deleted file mode 100644
index 6389aab82..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0009.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0009.webp
new file mode 100644
index 000000000..da4bcdb81
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0010.png
deleted file mode 100644
index cbd109b3a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0010.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0010.webp
new file mode 100644
index 000000000..d41f64aea
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0011.png
deleted file mode 100644
index c6b18bbcc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0011.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0011.webp
new file mode 100644
index 000000000..72f57609b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0012.png
deleted file mode 100644
index c7509ad6b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0012.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0012.webp
new file mode 100644
index 000000000..57d295881
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0013.png
deleted file mode 100644
index 657d880b3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0013.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0013.webp
new file mode 100644
index 000000000..b68e82eda
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0014.png
deleted file mode 100644
index 0b57a0fe1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0014.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0014.webp
new file mode 100644
index 000000000..1cb31917a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0015.png
deleted file mode 100644
index 3d2a65b56..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0015.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0015.webp
new file mode 100644
index 000000000..e17d1ca15
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0016.png
deleted file mode 100644
index fb04b6f00..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0016.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0016.webp
new file mode 100644
index 000000000..c8380cbe0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0017.png
deleted file mode 100644
index 5ab839edb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0017.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0017.webp
new file mode 100644
index 000000000..4d908f2ec
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0018.png
deleted file mode 100644
index 644b2cbd4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0018.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0018.webp
new file mode 100644
index 000000000..1440d0f10
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0019.png
deleted file mode 100644
index b51d9b301..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0019.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0019.webp
new file mode 100644
index 000000000..2736f0faf
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0020.png
deleted file mode 100644
index 002d8d30e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0020.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0020.webp
new file mode 100644
index 000000000..6fa2f82e0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0021.png
deleted file mode 100644
index 932faeb6a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0021.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0021.webp
new file mode 100644
index 000000000..d7e5a823a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0022.png
deleted file mode 100644
index 0195e1cc0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0022.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0022.webp
new file mode 100644
index 000000000..bb36460ab
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0023.png
deleted file mode 100644
index 3709e5469..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0023.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0023.webp
new file mode 100644
index 000000000..37ef00f3d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0024.png
deleted file mode 100644
index 954d87a71..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_swipeup0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0001.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0001.png
deleted file mode 100644
index 08c890615..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0002.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0002.png
deleted file mode 100644
index 21bca6749..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0003.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0003.png
deleted file mode 100644
index 43be5fded..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0003.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0003.webp
new file mode 100644
index 000000000..396afa5f0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0004.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0004.png
deleted file mode 100644
index b1692428f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0004.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0004.webp
new file mode 100644
index 000000000..28bbae915
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0005.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0005.png
deleted file mode 100644
index 4c4cc8fef..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0005.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0005.webp
new file mode 100644
index 000000000..692b05cbf
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0006.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0006.png
deleted file mode 100644
index d625e6cf3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0006.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0006.webp
new file mode 100644
index 000000000..48f8cfa70
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0007.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0007.png
deleted file mode 100644
index c63398e50..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0007.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0007.webp
new file mode 100644
index 000000000..a2a40b11e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0008.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0008.png
deleted file mode 100644
index b2db5f1f5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0008.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0008.webp
new file mode 100644
index 000000000..fa03252a2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0009.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0009.png
deleted file mode 100644
index ab0601585..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0009.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0009.webp
new file mode 100644
index 000000000..9fa6f783a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0010.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0010.png
deleted file mode 100644
index 0149442c7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0010.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0010.webp
new file mode 100644
index 000000000..38dd854f9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0011.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0011.png
deleted file mode 100644
index 4750b3fc9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0011.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0011.webp
new file mode 100644
index 000000000..e7c523de6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0012.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0012.png
deleted file mode 100644
index 6cde27909..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0012.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0012.webp
new file mode 100644
index 000000000..ef111523f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0013.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0013.png
deleted file mode 100644
index ba4e67ff4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0013.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0013.webp
new file mode 100644
index 000000000..059388051
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0014.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0014.png
deleted file mode 100644
index 0e63da339..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0014.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0014.webp
new file mode 100644
index 000000000..9317b0d8c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0015.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0015.png
deleted file mode 100644
index d2da3f83e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0015.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0015.webp
new file mode 100644
index 000000000..6dd578a6f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0016.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0016.png
deleted file mode 100644
index cd63c16ca..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0016.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0016.webp
new file mode 100644
index 000000000..3e0d13865
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0017.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0017.png
deleted file mode 100644
index 51d062151..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0017.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0017.webp
new file mode 100644
index 000000000..fdeeebd09
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0018.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0018.png
deleted file mode 100644
index c24efb737..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0018.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0018.webp
new file mode 100644
index 000000000..a498dba8a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0019.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0019.png
deleted file mode 100644
index af54faebd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0019.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0019.webp
new file mode 100644
index 000000000..9aa366264
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0020.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0020.png
deleted file mode 100644
index cd63c16ca..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0021.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0021.png
deleted file mode 100644
index 43be5fded..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0022.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0022.png
deleted file mode 100644
index 63c685b7c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0022.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0022.webp
new file mode 100644
index 000000000..09fb2324f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0023.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0023.png
deleted file mode 100644
index 08c890615..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0024.png b/dasherdancer/src/main/res/drawable-nodpi/santa_tap0024.png
deleted file mode 100644
index 08c890615..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_tap0024.png and /dev/null 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
deleted file mode 100644
index b0c2be127..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_down01.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_down01.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_down01.webp
new file mode 100644
index 000000000..9ed2580aa
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_down01.webp 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
deleted file mode 100644
index cf8f2db40..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_left01.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_left01.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_left01.webp
new file mode 100644
index 000000000..e8822d26b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_left01.webp 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
deleted file mode 100644
index 3d38f6815..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_shake01.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_shake01.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_shake01.webp
new file mode 100644
index 000000000..06050d8dd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_shake01.webp 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
deleted file mode 100644
index ea45198e3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_tap01.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_tap01.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_tap01.webp
new file mode 100644
index 000000000..1782c39b8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_tap01.webp 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
deleted file mode 100644
index c5507106c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_zoom_in01.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/santa_temp_zoom_in01.webp b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_zoom_in01.webp
new file mode 100644
index 000000000..264f9a6b2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/santa_temp_zoom_in01.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman.webp
new file mode 100644
index 000000000..ab40ad051
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0001.png
deleted file mode 100644
index 8fc8923c0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0001.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0001.webp
new file mode 100644
index 000000000..5fb9b02f7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0002.png
deleted file mode 100644
index 0c3e6960e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0002.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0002.webp
new file mode 100644
index 000000000..8695cc7de
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0003.png
deleted file mode 100644
index 83355be7d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0003.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0003.webp
new file mode 100644
index 000000000..db38a2634
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0004.png
deleted file mode 100644
index 49d294c2c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0004.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0004.webp
new file mode 100644
index 000000000..5ed6e503b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0005.png
deleted file mode 100644
index 12e3cbb3c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0005.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0005.webp
new file mode 100644
index 000000000..9012e9992
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0006.png
deleted file mode 100644
index f2abd8477..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0006.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0006.webp
new file mode 100644
index 000000000..40da3dfe5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0007.png
deleted file mode 100644
index a0d27e5d6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0007.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0007.webp
new file mode 100644
index 000000000..04b853819
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0008.png
deleted file mode 100644
index 12de9ed3a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0008.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0008.webp
new file mode 100644
index 000000000..c836286dc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0009.png
deleted file mode 100644
index f146291c7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0009.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0009.webp
new file mode 100644
index 000000000..e6679932a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0010.png
deleted file mode 100644
index 300046251..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0010.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0010.webp
new file mode 100644
index 000000000..39ae9cc5b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0011.png
deleted file mode 100644
index 89ef95ef1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0011.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0011.webp
new file mode 100644
index 000000000..ed9b3c1e1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0012.png
deleted file mode 100644
index 89ef95ef1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0013.png
deleted file mode 100644
index 89ef95ef1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0014.png
deleted file mode 100644
index 300046251..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0015.png
deleted file mode 100644
index f146291c7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0016.png
deleted file mode 100644
index 7689f8897..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0016.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0016.webp
new file mode 100644
index 000000000..27ca4e1f8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0017.png
deleted file mode 100644
index 95090dfcf..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0017.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0017.webp
new file mode 100644
index 000000000..d4564f752
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0018.png
deleted file mode 100644
index a956d7d56..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0018.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0018.webp
new file mode 100644
index 000000000..a2fc77554
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0019.png
deleted file mode 100644
index ae39cc69b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0019.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0019.webp
new file mode 100644
index 000000000..d31149a83
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0020.png
deleted file mode 100644
index 6b5afa8f8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0020.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0020.webp
new file mode 100644
index 000000000..e443bcee6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0021.png
deleted file mode 100644
index bc0534aa4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0021.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0021.webp
new file mode 100644
index 000000000..53d7ac09c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0022.png
deleted file mode 100644
index 4fba28a45..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0022.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0022.webp
new file mode 100644
index 000000000..dca755f6f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0023.png
deleted file mode 100644
index d19d70747..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0023.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0023.webp
new file mode 100644
index 000000000..18348bf44
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0024.png
deleted file mode 100644
index 8fc8923c0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_idle0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0001.png
deleted file mode 100644
index 486ae2471..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0001.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0001.webp
new file mode 100644
index 000000000..4ada92b4b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0002.png
deleted file mode 100644
index d20f97f72..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0002.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0002.webp
new file mode 100644
index 000000000..639fc1c26
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0003.png
deleted file mode 100644
index 7e592d3fc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0003.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0003.webp
new file mode 100644
index 000000000..c0f4e1519
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0004.png
deleted file mode 100644
index ec2562363..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0004.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0004.webp
new file mode 100644
index 000000000..2bea13689
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0005.png
deleted file mode 100644
index af168962e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0005.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0005.webp
new file mode 100644
index 000000000..de3dc03a7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0006.png
deleted file mode 100644
index 7a51a79a9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0006.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0006.webp
new file mode 100644
index 000000000..f6ca2779c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0007.png
deleted file mode 100644
index 6a940b77e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0007.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0007.webp
new file mode 100644
index 000000000..0fdb245ec
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0008.png
deleted file mode 100644
index 0cddbb24d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0008.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0008.webp
new file mode 100644
index 000000000..fba2651b8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0009.png
deleted file mode 100644
index 1a5811a17..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0009.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0009.webp
new file mode 100644
index 000000000..3cf9e6c54
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0010.png
deleted file mode 100644
index ab9fa2211..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0010.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0010.webp
new file mode 100644
index 000000000..a34b60543
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0011.png
deleted file mode 100644
index 472d011f4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0011.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0011.webp
new file mode 100644
index 000000000..73c132e81
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0012.png
deleted file mode 100644
index 0ba683011..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0012.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0012.webp
new file mode 100644
index 000000000..de6a1d2e5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0013.png
deleted file mode 100644
index 777eaab2b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0013.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0013.webp
new file mode 100644
index 000000000..61bf9b2f2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0014.png
deleted file mode 100644
index 7f584c1d2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0014.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0014.webp
new file mode 100644
index 000000000..846f625ca
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0015.png
deleted file mode 100644
index 1309106bd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0016.png
deleted file mode 100644
index 54708811d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0016.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0016.webp
new file mode 100644
index 000000000..3eb22dbd5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0017.png
deleted file mode 100644
index 7badec902..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0017.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0017.webp
new file mode 100644
index 000000000..894bceff4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0018.png
deleted file mode 100644
index 169e0c27f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0018.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0018.webp
new file mode 100644
index 000000000..6863d6ce8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0019.png
deleted file mode 100644
index 5d52f872c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0019.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0019.webp
new file mode 100644
index 000000000..34d9b17f7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0020.png
deleted file mode 100644
index 0e1a30913..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0020.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0020.webp
new file mode 100644
index 000000000..06a2582f5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0021.png
deleted file mode 100644
index ae37dfb06..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0021.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0021.webp
new file mode 100644
index 000000000..00b6af8da
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0022.png
deleted file mode 100644
index 14b5ab0fc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0022.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0022.webp
new file mode 100644
index 000000000..b2437b33e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0023.png
deleted file mode 100644
index 381854784..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0023.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0023.webp
new file mode 100644
index 000000000..3a5c25a61
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0024.png
deleted file mode 100644
index 1ab37b1c9..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0024.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0024.webp
new file mode 100644
index 000000000..df041b4e8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchin0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0001.png
deleted file mode 100644
index ea1fc3986..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0001.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0001.webp
new file mode 100644
index 000000000..3523df5b3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0002.png
deleted file mode 100644
index 2dde60adb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0002.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0002.webp
new file mode 100644
index 000000000..e20233efc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0003.png
deleted file mode 100644
index 021d7ba06..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0003.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0003.webp
new file mode 100644
index 000000000..2594388a8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0004.png
deleted file mode 100644
index 138580b99..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0004.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0004.webp
new file mode 100644
index 000000000..286885ff2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0005.png
deleted file mode 100644
index d530ce175..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0005.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0005.webp
new file mode 100644
index 000000000..226d72a8e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0006.png
deleted file mode 100644
index 8b2e78482..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0006.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0006.webp
new file mode 100644
index 000000000..ee1b67582
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0007.png
deleted file mode 100644
index 896c630e1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0007.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0007.webp
new file mode 100644
index 000000000..9f6023829
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0008.png
deleted file mode 100644
index e6f8d21a3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0008.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0008.webp
new file mode 100644
index 000000000..fd24a0a62
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0009.png
deleted file mode 100644
index ec94972ea..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0009.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0009.webp
new file mode 100644
index 000000000..dd6a6c56c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0010.png
deleted file mode 100644
index e3debca3b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0010.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0010.webp
new file mode 100644
index 000000000..fea19d2d2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0011.png
deleted file mode 100644
index 150d0c2c2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0011.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0011.webp
new file mode 100644
index 000000000..2b5c8f261
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0012.png
deleted file mode 100644
index 63bc2af3e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0012.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0012.webp
new file mode 100644
index 000000000..2eec58e3f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0013.png
deleted file mode 100644
index d0ee2d37f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0013.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0013.webp
new file mode 100644
index 000000000..5f975564d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0014.png
deleted file mode 100644
index d0ee2d37f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0015.png
deleted file mode 100644
index d0ee2d37f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0016.png
deleted file mode 100644
index d0ee2d37f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0017.png
deleted file mode 100644
index d0ee2d37f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0018.png
deleted file mode 100644
index d0ee2d37f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0019.png
deleted file mode 100644
index d0ee2d37f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0020.png
deleted file mode 100644
index 01d5bfcb2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0020.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0020.webp
new file mode 100644
index 000000000..2c2cc0e87
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0021.png
deleted file mode 100644
index 336ac57c3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0021.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0021.webp
new file mode 100644
index 000000000..e5d4d1bf9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0022.png
deleted file mode 100644
index 72eb25f69..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0022.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0022.webp
new file mode 100644
index 000000000..36221e258
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0023.png
deleted file mode 100644
index 6fa2cb0af..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0023.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0023.webp
new file mode 100644
index 000000000..25d0bdbe2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0024.png
deleted file mode 100644
index 8b0f03bf4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0024.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0024.webp
new file mode 100644
index 000000000..9d9d468bd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_pinchout0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0001.png
deleted file mode 100644
index fdeeb1fa3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0001.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0001.webp
new file mode 100644
index 000000000..f9c30f3ba
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0002.png
deleted file mode 100644
index 3b11a200e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0002.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0002.webp
new file mode 100644
index 000000000..1f5f49e2e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0003.png
deleted file mode 100644
index dd6e1eadb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0003.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0003.webp
new file mode 100644
index 000000000..d5e9449d2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0004.png
deleted file mode 100644
index 6e3d0fa26..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0004.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0004.webp
new file mode 100644
index 000000000..50ea6af0c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0005.png
deleted file mode 100644
index 23b651dd3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0005.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0005.webp
new file mode 100644
index 000000000..50f57fa45
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0006.png
deleted file mode 100644
index ec0e6f3c7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0006.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0006.webp
new file mode 100644
index 000000000..2d1bc5a19
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0007.png
deleted file mode 100644
index 4964b5cc7..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0007.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0007.webp
new file mode 100644
index 000000000..e035d8897
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0008.png
deleted file mode 100644
index 6cd93a245..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0008.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0008.webp
new file mode 100644
index 000000000..a996ad0ac
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0009.png
deleted file mode 100644
index 3bb106cf4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0009.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0009.webp
new file mode 100644
index 000000000..f16d4a833
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0010.png
deleted file mode 100644
index 319b9b188..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0010.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0010.webp
new file mode 100644
index 000000000..aaa5e3e16
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0011.png
deleted file mode 100644
index 330533867..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0011.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0011.webp
new file mode 100644
index 000000000..9200abe36
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0012.png
deleted file mode 100644
index 88ce3c018..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0012.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0012.webp
new file mode 100644
index 000000000..92fd18b1e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0013.png
deleted file mode 100644
index cd267adaa..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0013.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0013.webp
new file mode 100644
index 000000000..efc878d4f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0014.png
deleted file mode 100644
index 519af9c1b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0014.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0014.webp
new file mode 100644
index 000000000..e1931c7c0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0015.png
deleted file mode 100644
index 83fc3423e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0015.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0015.webp
new file mode 100644
index 000000000..caf7d3557
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0016.png
deleted file mode 100644
index 30e8b240b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0016.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0016.webp
new file mode 100644
index 000000000..9021e7b42
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0017.png
deleted file mode 100644
index 739827087..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0017.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0017.webp
new file mode 100644
index 000000000..ab5801339
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0018.png
deleted file mode 100644
index d98c2fb5b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0018.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0018.webp
new file mode 100644
index 000000000..952b47353
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0019.png
deleted file mode 100644
index 047e5bebd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0019.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0019.webp
new file mode 100644
index 000000000..1ff8cdd2e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0020.png
deleted file mode 100644
index 8f26a95e2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0020.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0020.webp
new file mode 100644
index 000000000..3166efaff
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0021.png
deleted file mode 100644
index 19efdb4ac..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0021.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0021.webp
new file mode 100644
index 000000000..6470de35c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0022.png
deleted file mode 100644
index 16466a4e1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0022.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0022.webp
new file mode 100644
index 000000000..45407f6b6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0023.png
deleted file mode 100644
index 90a674f13..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0023.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0023.webp
new file mode 100644
index 000000000..64da1261a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0024.png
deleted file mode 100644
index 1601b4338..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0024.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0024.webp
new file mode 100644
index 000000000..722ab07b1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_shake0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0001.png
deleted file mode 100644
index 8fc8923c0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0002.png
deleted file mode 100644
index 196f67494..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0002.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0002.webp
new file mode 100644
index 000000000..c7c34efdc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0003.png
deleted file mode 100644
index 763eaafec..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0003.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0003.webp
new file mode 100644
index 000000000..bc077ecaf
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0004.png
deleted file mode 100644
index 19b798a46..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0004.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0004.webp
new file mode 100644
index 000000000..be4137e38
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0005.png
deleted file mode 100644
index 85b444cfa..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0005.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0005.webp
new file mode 100644
index 000000000..9e48a1433
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0006.png
deleted file mode 100644
index 832414b89..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0006.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0006.webp
new file mode 100644
index 000000000..79754b897
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0007.png
deleted file mode 100644
index a3f9dd6dd..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0007.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0007.webp
new file mode 100644
index 000000000..609a1efef
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0008.png
deleted file mode 100644
index 5eb7ed211..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0008.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0008.webp
new file mode 100644
index 000000000..9f8bc7350
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0009.png
deleted file mode 100644
index c870a5fad..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0009.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0009.webp
new file mode 100644
index 000000000..d736f2466
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0010.png
deleted file mode 100644
index a750a0230..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0010.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0010.webp
new file mode 100644
index 000000000..794e305d1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0011.png
deleted file mode 100644
index acfa3c121..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0011.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0011.webp
new file mode 100644
index 000000000..51e4bdc59
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0012.png
deleted file mode 100644
index f13b9fe1d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0012.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0012.webp
new file mode 100644
index 000000000..87c7d7322
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0013.png
deleted file mode 100644
index 7a9466346..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0013.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0013.webp
new file mode 100644
index 000000000..850845023
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0014.png
deleted file mode 100644
index c1ee27c20..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0014.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0014.webp
new file mode 100644
index 000000000..717c4e291
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0015.png
deleted file mode 100644
index 450888074..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0015.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0015.webp
new file mode 100644
index 000000000..535ef8b58
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0016.png
deleted file mode 100644
index 1023c800d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0016.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0016.webp
new file mode 100644
index 000000000..c3b814976
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0017.png
deleted file mode 100644
index be2652f9a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0017.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0017.webp
new file mode 100644
index 000000000..7e0588f60
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0018.png
deleted file mode 100644
index fc130a338..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0018.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0018.webp
new file mode 100644
index 000000000..8f571c65c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0019.png
deleted file mode 100644
index db29ef2cc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0019.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0019.webp
new file mode 100644
index 000000000..669ecdab9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0020.png
deleted file mode 100644
index 8bd2714df..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0020.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0020.webp
new file mode 100644
index 000000000..0f1532906
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0021.png
deleted file mode 100644
index 8d4cab9c4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0021.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0021.webp
new file mode 100644
index 000000000..de90b7359
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0022.png
deleted file mode 100644
index 8fc8923c0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0023.png
deleted file mode 100644
index 8fc8923c0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0024.png
deleted file mode 100644
index 196f67494..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipedown0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0001.png
deleted file mode 100644
index 30b13f2c2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0001.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0001.webp
new file mode 100644
index 000000000..fa4351adc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0002.png
deleted file mode 100644
index c5c86a2d1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0002.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0002.webp
new file mode 100644
index 000000000..0cd186cb2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0003.png
deleted file mode 100644
index 4f7ea58e0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0003.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0003.webp
new file mode 100644
index 000000000..373e33a2d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0004.png
deleted file mode 100644
index 4ca59c42a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0004.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0004.webp
new file mode 100644
index 000000000..850652d6d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0005.png
deleted file mode 100644
index df727f66c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0005.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0005.webp
new file mode 100644
index 000000000..ff87b519a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0006.png
deleted file mode 100644
index 9d068cdba..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0006.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0006.webp
new file mode 100644
index 000000000..97b6b230e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0007.png
deleted file mode 100644
index 183d27482..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0007.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0007.webp
new file mode 100644
index 000000000..f4b08c92e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0008.png
deleted file mode 100644
index bd21dfcd0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0008.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0008.webp
new file mode 100644
index 000000000..e416fe150
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0009.png
deleted file mode 100644
index 5ec92c718..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0009.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0009.webp
new file mode 100644
index 000000000..fcc0fb3dc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0010.png
deleted file mode 100644
index 5cb194613..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0010.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0010.webp
new file mode 100644
index 000000000..6cc5a6e55
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0011.png
deleted file mode 100644
index 957bed986..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0011.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0011.webp
new file mode 100644
index 000000000..cc861e82e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0012.png
deleted file mode 100644
index aefd11f88..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0012.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0012.webp
new file mode 100644
index 000000000..49776ede2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0013.png
deleted file mode 100644
index 789d831c2..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0013.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0013.webp
new file mode 100644
index 000000000..9a48ee23c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0014.png
deleted file mode 100644
index 1733eba70..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0014.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0014.webp
new file mode 100644
index 000000000..c1113ab0d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0015.png
deleted file mode 100644
index 0f84c9121..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0015.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0015.webp
new file mode 100644
index 000000000..54bd1d82f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0016.png
deleted file mode 100644
index 0073e2e01..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0016.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0016.webp
new file mode 100644
index 000000000..7503cfd10
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0017.png
deleted file mode 100644
index 34483780f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0017.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0017.webp
new file mode 100644
index 000000000..265d96d0f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0018.png
deleted file mode 100644
index b93793aea..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0018.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0018.webp
new file mode 100644
index 000000000..12ccc03ca
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0019.png
deleted file mode 100644
index 641995e82..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0019.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0019.webp
new file mode 100644
index 000000000..eb9769e3e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0020.png
deleted file mode 100644
index 7cd3c91ad..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0020.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0020.webp
new file mode 100644
index 000000000..33ed5da1c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0021.png
deleted file mode 100644
index cc6fcd582..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0021.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0021.webp
new file mode 100644
index 000000000..5fae1714b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0022.png
deleted file mode 100644
index 0537efbea..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0022.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0022.webp
new file mode 100644
index 000000000..c4cadc944
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0023.png
deleted file mode 100644
index ec69020ce..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0023.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0023.webp
new file mode 100644
index 000000000..42790f0fd
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0024.png
deleted file mode 100644
index 6129865ec..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0024.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0024.webp
new file mode 100644
index 000000000..6a04a6f43
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeleft0024.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0001.png
deleted file mode 100644
index 8f757df57..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0001.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0001.webp
new file mode 100644
index 000000000..b7aa6c20b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0002.png
deleted file mode 100644
index 343185af8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0002.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0002.webp
new file mode 100644
index 000000000..3518705d8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0003.png
deleted file mode 100644
index 255ef6cf5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0003.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0003.webp
new file mode 100644
index 000000000..236601418
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0004.png
deleted file mode 100644
index 747cf600e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0004.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0004.webp
new file mode 100644
index 000000000..c6b46067f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0005.png
deleted file mode 100644
index 34d505aff..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0005.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0005.webp
new file mode 100644
index 000000000..0942694fe
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0006.png
deleted file mode 100644
index 9ab1f3e6b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0006.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0006.webp
new file mode 100644
index 000000000..e415d598f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0007.png
deleted file mode 100644
index d97424f94..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0007.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0007.webp
new file mode 100644
index 000000000..8773eee24
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0008.png
deleted file mode 100644
index f62558e0a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0008.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0008.webp
new file mode 100644
index 000000000..db9b3fa43
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0009.png
deleted file mode 100644
index 5217e1a29..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0009.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0009.webp
new file mode 100644
index 000000000..31f254784
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0010.png
deleted file mode 100644
index e717eedd4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0010.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0010.webp
new file mode 100644
index 000000000..1b6586451
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0011.png
deleted file mode 100644
index d8cccb176..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0011.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0011.webp
new file mode 100644
index 000000000..d04224ee7
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0012.png
deleted file mode 100644
index b5866a4fb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0012.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0012.webp
new file mode 100644
index 000000000..2cd6a6c46
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0013.png
deleted file mode 100644
index 5777d5e01..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0013.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0013.webp
new file mode 100644
index 000000000..0331a8a59
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0014.png
deleted file mode 100644
index 67311b0b5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0014.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0014.webp
new file mode 100644
index 000000000..d5d5d3a93
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0015.png
deleted file mode 100644
index b1a4dfa8e..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0015.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0015.webp
new file mode 100644
index 000000000..e43bea08a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0016.png
deleted file mode 100644
index 9435c6933..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0016.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0016.webp
new file mode 100644
index 000000000..9761419aa
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0017.png
deleted file mode 100644
index 6653ada95..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0017.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0017.webp
new file mode 100644
index 000000000..e0bdae3a2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0018.png
deleted file mode 100644
index e2e5ad263..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0018.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0018.webp
new file mode 100644
index 000000000..a8c433374
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0019.png
deleted file mode 100644
index 361cbeec0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0019.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0019.webp
new file mode 100644
index 000000000..b05424cc5
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0020.png
deleted file mode 100644
index 25d5ed75d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0020.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0020.webp
new file mode 100644
index 000000000..fb0b5586c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0021.png
deleted file mode 100644
index 34445ac58..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0021.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0021.webp
new file mode 100644
index 000000000..8d96f6fd8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0022.png
deleted file mode 100644
index 4887e5c19..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0022.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0022.webp
new file mode 100644
index 000000000..2141b4002
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0023.png
deleted file mode 100644
index 22839c67d..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0023.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0023.webp
new file mode 100644
index 000000000..fa7a16265
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0024.png
deleted file mode 100644
index 8f757df57..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swiperight0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0001.png
deleted file mode 100644
index 8fc8923c0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0002.png
deleted file mode 100644
index 15eb8101a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0002.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0002.webp
new file mode 100644
index 000000000..78b0fe3c6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0003.png
deleted file mode 100644
index 5e914e985..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0003.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0003.webp
new file mode 100644
index 000000000..a0bd5e148
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0004.png
deleted file mode 100644
index 067606d99..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0004.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0004.webp
new file mode 100644
index 000000000..24a46641f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0005.png
deleted file mode 100644
index 9f30e72f5..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0005.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0005.webp
new file mode 100644
index 000000000..732615523
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0006.png
deleted file mode 100644
index c53e80c10..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0006.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0006.webp
new file mode 100644
index 000000000..450fd9859
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0007.png
deleted file mode 100644
index ee58e233c..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0007.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0007.webp
new file mode 100644
index 000000000..4048112c3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0008.png
deleted file mode 100644
index 964a01a45..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0008.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0008.webp
new file mode 100644
index 000000000..a27be3e4a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0009.png
deleted file mode 100644
index 964a01a45..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0010.png
deleted file mode 100644
index 964a01a45..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0011.png
deleted file mode 100644
index cff9ac554..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0011.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0011.webp
new file mode 100644
index 000000000..630f8a823
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0012.png
deleted file mode 100644
index 0ff5a2e36..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0012.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0012.webp
new file mode 100644
index 000000000..3ab9c0d21
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0013.png
deleted file mode 100644
index d732c80d1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0013.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0013.webp
new file mode 100644
index 000000000..bfa1e4166
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0014.png
deleted file mode 100644
index 43a5b8e47..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0014.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0014.webp
new file mode 100644
index 000000000..5d33ddaef
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0015.png
deleted file mode 100644
index 784c26be1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0015.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0015.webp
new file mode 100644
index 000000000..d2b5e00b1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0016.png
deleted file mode 100644
index 381b5cef1..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0016.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0016.webp
new file mode 100644
index 000000000..f74e3f163
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0017.png
deleted file mode 100644
index afa69e037..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0017.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0017.webp
new file mode 100644
index 000000000..997f50767
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0018.png
deleted file mode 100644
index 86cd903ae..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0018.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0018.webp
new file mode 100644
index 000000000..e187a028c
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0019.png
deleted file mode 100644
index 66666c734..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0019.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0019.webp
new file mode 100644
index 000000000..359d8fc58
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0020.png
deleted file mode 100644
index 103f9947a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0020.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0020.webp
new file mode 100644
index 000000000..84f34ac0f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0021.png
deleted file mode 100644
index 7982f4d8b..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0021.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0021.webp
new file mode 100644
index 000000000..82c0d301f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0022.png
deleted file mode 100644
index 2506c82cb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0022.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0022.webp
new file mode 100644
index 000000000..566dfe200
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0023.png
deleted file mode 100644
index 66420e2c3..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0023.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0023.webp
new file mode 100644
index 000000000..46d46dba8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0024.png
deleted file mode 100644
index 8fc8923c0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_swipeup0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0001.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0001.png
deleted file mode 100644
index f0a1cd493..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0001.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0001.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0001.webp
new file mode 100644
index 000000000..1ed4a5fe1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0001.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0002.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0002.png
deleted file mode 100644
index 65d655508..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0002.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0002.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0002.webp
new file mode 100644
index 000000000..cac64b3c4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0002.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0003.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0003.png
deleted file mode 100644
index 96afe1a96..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0003.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0003.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0003.webp
new file mode 100644
index 000000000..f11b0b534
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0003.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0004.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0004.png
deleted file mode 100644
index fc78fd9f8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0004.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0004.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0004.webp
new file mode 100644
index 000000000..5519a680d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0004.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0005.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0005.png
deleted file mode 100644
index 09ed3a3f8..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0005.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0005.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0005.webp
new file mode 100644
index 000000000..6c9bcb497
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0005.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0006.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0006.png
deleted file mode 100644
index 336d46103..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0006.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0006.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0006.webp
new file mode 100644
index 000000000..425feab8d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0006.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0007.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0007.png
deleted file mode 100644
index 5d657d0cb..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0007.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0007.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0007.webp
new file mode 100644
index 000000000..76a48e9ca
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0007.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0008.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0008.png
deleted file mode 100644
index 20ee98019..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0008.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0008.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0008.webp
new file mode 100644
index 000000000..de6d1f2e2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0008.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0009.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0009.png
deleted file mode 100644
index 5e5a464ff..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0009.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0009.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0009.webp
new file mode 100644
index 000000000..54cdb9912
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0009.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0010.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0010.png
deleted file mode 100644
index 8819f4721..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0010.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0010.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0010.webp
new file mode 100644
index 000000000..f9307cfbb
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0010.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0011.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0011.png
deleted file mode 100644
index ca37f4781..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0011.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0011.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0011.webp
new file mode 100644
index 000000000..0322f2388
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0011.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0012.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0012.png
deleted file mode 100644
index 5a944a695..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0012.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0012.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0012.webp
new file mode 100644
index 000000000..64e18a9b8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0012.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0013.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0013.png
deleted file mode 100644
index 87bd76a32..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0013.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0013.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0013.webp
new file mode 100644
index 000000000..abd9b59af
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0013.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0014.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0014.png
deleted file mode 100644
index 00c7f17bc..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0014.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0014.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0014.webp
new file mode 100644
index 000000000..6c1eef165
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0014.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0015.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0015.png
deleted file mode 100644
index 08d8602c0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0015.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0015.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0015.webp
new file mode 100644
index 000000000..3239787b0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0015.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0016.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0016.png
deleted file mode 100644
index 1eb8ba8b4..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0016.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0016.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0016.webp
new file mode 100644
index 000000000..7b3dbd6e9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0016.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0017.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0017.png
deleted file mode 100644
index 6124f6dd6..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0017.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0017.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0017.webp
new file mode 100644
index 000000000..f5efeb67e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0017.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0018.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0018.png
deleted file mode 100644
index 5edebf86f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0018.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0018.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0018.webp
new file mode 100644
index 000000000..7b8379d13
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0018.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0019.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0019.png
deleted file mode 100644
index bd6f40734..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0019.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0019.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0019.webp
new file mode 100644
index 000000000..cf77e8cd9
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0019.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0020.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0020.png
deleted file mode 100644
index d9af99f8f..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0020.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0020.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0020.webp
new file mode 100644
index 000000000..80abde9d8
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0020.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0021.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0021.png
deleted file mode 100644
index 8b9f2fb45..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0021.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0021.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0021.webp
new file mode 100644
index 000000000..e7a5c3752
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0021.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0022.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0022.png
deleted file mode 100644
index 2fa345787..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0022.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0022.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0022.webp
new file mode 100644
index 000000000..7be3e7849
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0022.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0023.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0023.png
deleted file mode 100644
index b0a7aba3a..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0023.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0023.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0023.webp
new file mode 100644
index 000000000..4a1c3d99b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0023.webp differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0024.png b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0024.png
deleted file mode 100644
index 58301c7e0..000000000
Binary files a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0024.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0024.webp b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0024.webp
new file mode 100644
index 000000000..5577f8b71
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-nodpi/snowman_tap0024.webp 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..6d9a22028 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..8e800f218 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
deleted file mode 100644
index 2050120fa..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer.webp b/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer.webp
new file mode 100644
index 000000000..dd54eec31
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer.webp 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
deleted file mode 100644
index cae06c682..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer_p.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer_p.webp b/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer_p.webp
new file mode 100644
index 000000000..a50a89b8a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xhdpi/btn_nav_drawer_p.webp 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
deleted file mode 100644
index c02828653..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character.webp b/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character.webp
new file mode 100644
index 000000000..385b104af
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character.webp 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
deleted file mode 100644
index 794c3cb5f..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character_pressed.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character_pressed.webp b/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character_pressed.webp
new file mode 100644
index 000000000..43ef03113
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xhdpi/btn_select_character_pressed.webp 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
deleted file mode 100644
index bc5da3542..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out.webp b/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out.webp
new file mode 100644
index 000000000..065de6707
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out.webp 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
deleted file mode 100644
index 598b9d0c8..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out_pressed.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out_pressed.webp b/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out_pressed.webp
new file mode 100644
index 000000000..6ba3b4940
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xhdpi/btn_x_out_pressed.webp differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/elf.png b/dasherdancer/src/main/res/drawable-xhdpi/elf.png
deleted file mode 100644
index bfdff002b..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/elf.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index df82a166d..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null 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
deleted file mode 100644
index 0724f6e65..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_left.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_left.webp b/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_left.webp
new file mode 100644
index 000000000..4f324b8cc
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_left.webp 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
deleted file mode 100644
index e151aa236..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_right.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_right.webp b/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_right.webp
new file mode 100644
index 000000000..e86e24e5e
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xhdpi/icn_arrow_right.webp 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
deleted file mode 100644
index 96911bff7..000000000
Binary files a/dasherdancer/src/main/res/drawable-xhdpi/img_mint_loading_spinner.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xhdpi/img_mint_loading_spinner.webp b/dasherdancer/src/main/res/drawable-xhdpi/img_mint_loading_spinner.webp
new file mode 100644
index 000000000..cd934cab2
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xhdpi/img_mint_loading_spinner.webp 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
deleted file mode 100644
index 28738e251..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer.webp b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer.webp
new file mode 100644
index 000000000..2a8225e40
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer.webp 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
deleted file mode 100644
index b810e7035..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer_p.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer_p.webp b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer_p.webp
new file mode 100644
index 000000000..3cde3599a
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_nav_drawer_p.webp 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
deleted file mode 100644
index fce126edf..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character.webp b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character.webp
new file mode 100644
index 000000000..22d5f4662
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character.webp 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
deleted file mode 100644
index cc6568d2f..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character_pressed.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character_pressed.webp b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character_pressed.webp
new file mode 100644
index 000000000..2b434c2b3
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_select_character_pressed.webp 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
deleted file mode 100644
index e3af85425..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out.webp b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out.webp
new file mode 100644
index 000000000..e2a96f13f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out.webp 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
deleted file mode 100644
index d61aa5601..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out_pressed.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out_pressed.webp b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out_pressed.webp
new file mode 100644
index 000000000..07d400b1b
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/btn_x_out_pressed.webp 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
deleted file mode 100644
index 91475edc4..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/ic_launcher.png and /dev/null 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
deleted file mode 100644
index 8b1a16985..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/img_mint_loading_spinner.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/img_mint_loading_spinner.webp b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/img_mint_loading_spinner.webp
new file mode 100644
index 000000000..ec5cf68cf
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/img_mint_loading_spinner.webp differ
diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/reindeer.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/reindeer.png
deleted file mode 100644
index 2c58a3006..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/reindeer.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/santa.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/santa.png
deleted file mode 100644
index 3a841f400..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/santa.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/snowman.png b/dasherdancer/src/main/res/drawable-xlarge-xhdpi/snowman.png
deleted file mode 100644
index c8b6e4d73..000000000
Binary files a/dasherdancer/src/main/res/drawable-xlarge-xhdpi/snowman.png and /dev/null 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
deleted file mode 100644
index ec65de817..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer.webp b/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer.webp
new file mode 100644
index 000000000..761792c43
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer.webp 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
deleted file mode 100644
index 94c36a676..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer_p.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer_p.webp b/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer_p.webp
new file mode 100644
index 000000000..7ff5c23d0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_nav_drawer_p.webp 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
deleted file mode 100644
index 5bc4bf761..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character.webp b/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character.webp
new file mode 100644
index 000000000..5e95aeeb1
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character.webp 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
deleted file mode 100644
index 2a1e05a4c..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character_pressed.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character_pressed.webp b/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character_pressed.webp
new file mode 100644
index 000000000..06adb18a6
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_select_character_pressed.webp 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
deleted file mode 100644
index c0a791bf7..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out.webp b/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out.webp
new file mode 100644
index 000000000..65fe1357d
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out.webp 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
deleted file mode 100644
index 209349e0f..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out_pressed.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out_pressed.webp b/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out_pressed.webp
new file mode 100644
index 000000000..8367b4ac4
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xxhdpi/btn_x_out_pressed.webp differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/games_cancelbar.png b/dasherdancer/src/main/res/drawable-xxhdpi/games_cancelbar.png
deleted file mode 100644
index 06123258c..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/games_cancelbar.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 91475edc4..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null 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
deleted file mode 100644
index 5970d6b81..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/img_mint_loading_spinner.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/img_mint_loading_spinner.webp b/dasherdancer/src/main/res/drawable-xxhdpi/img_mint_loading_spinner.webp
new file mode 100644
index 000000000..c6130571f
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xxhdpi/img_mint_loading_spinner.webp differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/reindeer.png b/dasherdancer/src/main/res/drawable-xxhdpi/reindeer.png
deleted file mode 100644
index 2c58a3006..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/reindeer.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/santa.png b/dasherdancer/src/main/res/drawable-xxhdpi/santa.png
deleted file mode 100644
index 3a841f400..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/santa.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxhdpi/snowman.png b/dasherdancer/src/main/res/drawable-xxhdpi/snowman.png
deleted file mode 100644
index c8b6e4d73..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxhdpi/snowman.png and /dev/null 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
deleted file mode 100644
index ec65de817..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer.webp b/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer.webp
new file mode 100644
index 000000000..761792c43
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer.webp 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
deleted file mode 100644
index 94c36a676..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer_p.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer_p.webp b/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer_p.webp
new file mode 100644
index 000000000..7ff5c23d0
Binary files /dev/null and b/dasherdancer/src/main/res/drawable-xxxhdpi/btn_nav_drawer_p.webp differ
diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/ic_launcher.png b/dasherdancer/src/main/res/drawable-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 91475edc4..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/reindeer.png b/dasherdancer/src/main/res/drawable-xxxhdpi/reindeer.png
deleted file mode 100644
index 2c58a3006..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/reindeer.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/santa.png b/dasherdancer/src/main/res/drawable-xxxhdpi/santa.png
deleted file mode 100644
index 3a841f400..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/santa.png and /dev/null differ
diff --git a/dasherdancer/src/main/res/drawable-xxxhdpi/snowman.png b/dasherdancer/src/main/res/drawable-xxxhdpi/snowman.png
deleted file mode 100644
index c8b6e4d73..000000000
Binary files a/dasherdancer/src/main/res/drawable-xxxhdpi/snowman.png and /dev/null 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..a588e81cb 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..3bf800aaf 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..ecfbf15b8 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..ec0d2b01c 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..5e6c72371 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..10271977b 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..4d6a598d2 100644
--- a/dasherdancer/src/main/res/layout/activity_dasher_dancer.xml
+++ b/dasherdancer/src/main/res/layout/activity_dasher_dancer.xml
@@ -1,73 +1,101 @@
-
+
+
+ tools:context="com.google.android.apps.santatracker.dasherdancer.DasherDancerActivity">
-
-
-
-
+ android:id="@+id/character_pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
-
-
-
+
-
+
+
-
-
\ No newline at end of file
+ android:layout_gravity="right"
+ android:adjustViewBounds="true"
+ android:background="@null"
+ android:onClick="onChangeClick"
+ android:scaleType="center"
+ android:src="@drawable/btn_select_character_pressable" />
+
+
+
+
+
+
+
+
+
+
+
+
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..2bf893538 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..63b4ff1b2 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..2bf893538 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..2bf893538 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..81ea07862 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..81ea07862 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..2bf893538 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..2bf893538 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..2bf893538 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..81ea07862 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..489f1cfe0 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..ddfa15002 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
deleted file mode 100644
index 073e5e546..000000000
--- a/dasherdancer/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- Dasher Dancer
-
diff --git a/dasherdancer/src/main/res/values/strings_analytics.xml b/dasherdancer/src/main/res/values/strings_analytics.xml
index d7e7ab1a7..0c9c11639 100644
--- a/dasherdancer/src/main/res/values/strings_analytics.xml
+++ b/dasherdancer/src/main/res/values/strings_analytics.xml
@@ -1,16 +1,30 @@
-
- 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/docs/village.png b/docs/village.png
new file mode 100644
index 000000000..5d011c526
Binary files /dev/null and b/docs/village.png differ
diff --git a/doodles-lib/build.gradle b/doodles-lib/build.gradle
new file mode 100644
index 000000000..93876fcb5
--- /dev/null
+++ b/doodles-lib/build.gradle
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.tools
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ }
+}
+
+dependencies {
+ implementation project(":common")
+
+ implementation rootProject.ext.appCompat
+ implementation rootProject.ext.firebaseConfig
+ implementation rootProject.ext.firebaseCore
+ implementation rootProject.ext.firebaseAppinvite
+
+ api fileTree(dir: 'libs', include: ['*.jar'])
+}
diff --git a/doodles-lib/src/main/AndroidManifest.xml b/doodles-lib/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..aeea6a59d
--- /dev/null
+++ b/doodles-lib/src/main/AndroidManifest.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/BaseDoodleActivity.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/BaseDoodleActivity.java
new file mode 100644
index 000000000..f61405edc
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/BaseDoodleActivity.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.DOODLE_LAUNCHED;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.os.Bundle;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleDebugLogger;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogTimer;
+import com.google.android.apps.santatracker.doodles.shared.views.GameFragment;
+import com.google.android.apps.santatracker.games.OnDemandActivity;
+import com.google.android.apps.santatracker.invites.AppInvitesFragment;
+import com.google.android.apps.santatracker.util.MeasurementManager;
+import com.google.firebase.analytics.FirebaseAnalytics;
+
+/** Base activity for doodle games */
+public abstract class BaseDoodleActivity extends OnDemandActivity {
+
+ private AppInvitesFragment appInvitesFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_view);
+
+ // Setup Analytics
+ FirebaseAnalytics analytics = FirebaseAnalytics.getInstance(this);
+ int stringResource = getAnalyticsStringResource();
+ MeasurementManager.recordScreenView(analytics, getString(stringResource));
+
+ appInvitesFragment = AppInvitesFragment.getInstance(this);
+
+ // Setup Logging
+ DoodleDebugLogger logger = new DoodleDebugLogger();
+ String gameType = getGameType();
+
+ // Setup Fragment
+ Fragment fragment = makeFragment(logger);
+
+ // Log fragment returned
+ logger.logGameLaunchEvent(this, gameType, DOODLE_LAUNCHED);
+ DoodleLogTimer.getInstance().reset();
+
+ FragmentManager fragmentManager = getFragmentManager();
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ fragmentTransaction.add(R.id.activity_wrapper, fragment, "menu");
+ fragmentTransaction.commit();
+ }
+
+ protected abstract String getGameType();
+
+ protected abstract int getAnalyticsStringResource();
+
+ protected abstract Fragment makeFragment(DoodleDebugLogger logger);
+
+ @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-lib/src/main/java/com/google/android/apps/santatracker/doodles/Config.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/Config.java
new file mode 100644
index 000000000..816547b68
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/Config.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/AndroidUtils.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/AndroidUtils.java
new file mode 100644
index 000000000..ffa734455
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/AndroidUtils.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.Intent;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.os.Environment;
+import android.text.Html;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.WindowManager;
+import com.google.android.apps.santatracker.util.SantaLog;
+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) {
+ SantaLog.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;
+ }
+
+ public static void finishActivity(Context context) {
+ getActivityFromContext(context).finish();
+ }
+
+ public static void finishActivityWithResult(Context context, int resultCode, Bundle extras) {
+ Activity activity = getActivityFromContext(context);
+ Intent intent = activity.getIntent();
+ intent.putExtras(extras);
+ activity.setResult(resultCode, intent);
+ activity.finish();
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/BitmapCache.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/BitmapCache.java
new file mode 100644
index 000000000..302eff661
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/BitmapCache.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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<>();
+
+ private static String bitmapCacheKey(int id, int frameNumber) {
+ return id + ":" + frameNumber;
+ }
+
+ 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();
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/CallbackProcess.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/CallbackProcess.java
new file mode 100644
index 000000000..4178c80f0
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/CallbackProcess.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/ColoredRectangleActor.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/ColoredRectangleActor.java
new file mode 100644
index 000000000..0ebeb0cd1
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/ColoredRectangleActor.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Cap;
+import android.graphics.Paint.Style;
+import com.google.android.apps.santatracker.doodles.shared.actor.Actor;
+import com.google.android.apps.santatracker.doodles.shared.physics.Util;
+import java.util.HashMap;
+import java.util.Map;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/** 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);
+ }
+
+ public String type;
+ public Vector2D dimens;
+ private Direction selectedDirection;
+ 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();
+ }
+
+ 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);
+ }
+
+ @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);
+ }
+
+ /** A direction used to pull the boundaries of the colored rectangle. */
+ private enum Direction {
+ NONE,
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT,
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Constants.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Constants.java
new file mode 100644
index 000000000..e51115a8a
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Constants.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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;
+
+/** 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Debug.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Debug.java
new file mode 100644
index 000000000..dbdf061ea
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Debug.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.shared.actor.Actor;
+import com.google.android.apps.santatracker.doodles.shared.actor.SpriteActor;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite;
+import com.google.android.apps.santatracker.doodles.shared.animation.Sprites;
+
+/** 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;
+
+ public static final boolean DRAW_COLLISION_BOUNDS = 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/EventBus.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/EventBus.java
new file mode 100644
index 000000000..4b71d3447
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/EventBus.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 {
+ 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 static EventBus instance;
+ private final Object lock = new Object();
+ // Listeners for specific events.
+ private Map> specificListeners;
+ // Listeners for all events.
+ private Set globalListeners;
+
+ private EventBus() {
+ globalListeners = new HashSet<>();
+ specificListeners = new HashMap<>();
+ }
+
+ public static EventBus getInstance() {
+ if (instance == null) {
+ instance = new EventBus();
+ }
+ return instance;
+ }
+
+ /** 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();
+ }
+ }
+
+ /** Interface for objects which want to listen to the event bus. */
+ public interface EventBusListener {
+ void onEventReceived(int type, Object data);
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/ExternalStoragePermissions.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/ExternalStoragePermissions.java
new file mode 100644
index 000000000..60f885827
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/ExternalStoragePermissions.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameLoop.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameLoop.java
new file mode 100644
index 000000000..b1617d96a
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameLoop.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameType.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameType.java
new file mode 100644
index 000000000..0f42ee6ec
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/GameType.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 {
+ SWIMMING,
+ WATER_POLO,
+ PURSUIT,
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/HistoryManager.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/HistoryManager.java
new file mode 100644
index 000000000..27ed4ca80
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/HistoryManager.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 com.google.android.apps.santatracker.util.SantaLog;
+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 {
+ 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 TAG = HistoryManager.class.getSimpleName();
+ private static final String FILENAME = "history.json";
+
+ private final Context context;
+ private volatile JSONObject history;
+ 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;
+ }
+
+ /**
+ * 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) {
+ SantaLog.e(TAG, "error setting place", e);
+ }
+ }
+
+ /** ********************** Setters **************************** */
+
+ /**
+ * 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) {
+ SantaLog.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) {
+ SantaLog.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) {
+ SantaLog.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) {
+ SantaLog.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) {
+ SantaLog.e(TAG, "error setting distance", e);
+ }
+ }
+
+ /** 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;
+ }
+ }
+
+ /** ********************** Getters **************************** */
+
+ /** 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;
+ }
+ }
+
+ /** 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();
+ SantaLog.i(TAG, "Saved: " + history);
+ } catch (IOException e) {
+ SantaLog.w(TAG, "Couldn't save JSON at: " + FILENAME);
+ } catch (Exception e) {
+ SantaLog.w(TAG, "Crazy exception happened", e);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ if (listener != null) {
+ listener.onFinishedSaving();
+ }
+ }
+ }.execute();
+ }
+
+ /** ******************** File Management ************************* */
+
+ /**
+ * 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"));
+ SantaLog.i(TAG, "Loaded: " + history);
+ } catch (JSONException e) {
+ SantaLog.w(TAG, "Couldn't create JSON for: " + FILENAME);
+ } catch (UnsupportedEncodingException e) {
+ SantaLog.d(TAG, "Couldn't decode: " + FILENAME);
+ } catch (IOException e) {
+ SantaLog.w(TAG, "Couldn't read history: " + FILENAME);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ if (listener != null) {
+ listener.onFinishedLoading();
+ }
+ }
+ }.execute();
+ }
+
+ /** Listener for when the history is loaded. */
+ public static interface HistoryListener {
+ public void onFinishedLoading();
+
+ public void onFinishedSaving();
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/LogicRefreshThread.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/LogicRefreshThread.java
new file mode 100644
index 000000000..f3b3b4a5c
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/LogicRefreshThread.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 final ConditionVariable handlerCreatedCV = new ConditionVariable();
+ private Handler handler;
+ // 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 (running && 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Process.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Process.java
new file mode 100644
index 000000000..13dc90125
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Process.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/ProcessChain.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/ProcessChain.java
new file mode 100644
index 000000000..2c048bd96
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/ProcessChain.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 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 final ReentrantLock lock = new ReentrantLock();
+ private Queue processes;
+
+ public ProcessChain(Process p) {
+ processes = new LinkedList<>();
+ processes.add(p);
+ }
+
+ 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);
+ }
+ }
+
+ public ProcessChain then(Process p) {
+ lock.lock();
+ try {
+ processes.add(p);
+ } finally {
+ lock.unlock();
+ }
+ return this;
+ }
+
+ public ProcessChain then(ProcessChain pc) {
+ lock.lock();
+ try {
+ processes.addAll(pc.processes);
+ } finally {
+ lock.unlock();
+ }
+ return this;
+ }
+
+ public void update(float deltaMs) {
+ lock.lock();
+ try {
+ final Process activeProcess = processes.peek();
+ if (activeProcess != null) {
+ activeProcess.update(deltaMs);
+
+ if (activeProcess.isFinished()) {
+ processes.remove();
+ }
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public boolean isFinished() {
+ lock.lock();
+ try {
+ return processes.isEmpty();
+ } finally {
+ lock.unlock();
+ }
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Touchable.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Touchable.java
new file mode 100644
index 000000000..26c0c40c6
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Touchable.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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;
+
+/** 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIRefreshHandler.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIRefreshHandler.java
new file mode 100644
index 000000000..8921d0fcd
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIRefreshHandler.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIUtil.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIUtil.java
new file mode 100644
index 000000000..94be469c9
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/UIUtil.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Vector2D.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Vector2D.java
new file mode 100644
index 000000000..8e585cd73
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/Vector2D.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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);
+ }
+
+ public static float getLength(float x, float y) {
+ return (float) Math.sqrt(x * x + y * 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 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/WaitProcess.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/WaitProcess.java
new file mode 100644
index 000000000..fd60a82fb
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/WaitProcess.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/Actor.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/Actor.java
new file mode 100644
index 000000000..7778fa703
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/Actor.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.actor;
+
+import android.graphics.Canvas;
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/** Base class for different characters on the screen. */
+public abstract 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/ActorHelper.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/ActorHelper.java
new file mode 100644
index 000000000..843cbd19a
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/ActorHelper.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.actor;
+
+/** 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/Camera.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/Camera.java
new file mode 100644
index 000000000..022e26f8b
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/Camera.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.actor;
+
+import static com.google.android.apps.santatracker.doodles.shared.animation.Interpolator.EASE_IN_AND_OUT;
+
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import com.google.android.apps.santatracker.doodles.shared.animation.Tween;
+
+/**
+ * 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/CameraShake.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/CameraShake.java
new file mode 100644
index 000000000..791c61cf2
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/CameraShake.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.actor;
+
+/**
+ * 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/FakeButtonActor.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/FakeButtonActor.java
new file mode 100644
index 000000000..4e5c99f9b
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/FakeButtonActor.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.actor;
+
+import android.graphics.Canvas;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite;
+
+/**
+ * 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/MultiSpriteActor.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/MultiSpriteActor.java
new file mode 100644
index 000000000..a97cfde45
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/MultiSpriteActor.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.actor;
+
+import android.content.res.Resources;
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite;
+import com.google.android.apps.santatracker.util.SantaLog;
+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 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());
+ }
+
+ public void setSprite(String key) {
+ if (sprites.containsKey(key)) {
+ sprite = sprites.get(key);
+ } else {
+ SantaLog.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;
+ }
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/RectangularInstructionActor.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/RectangularInstructionActor.java
new file mode 100644
index 000000000..345c8eae0
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/RectangularInstructionActor.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.actor;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite.AnimatedSpriteListener;
+import com.google.android.apps.santatracker.doodles.shared.animation.Sprites;
+
+/** 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/SpriteActor.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/SpriteActor.java
new file mode 100644
index 000000000..82a234742
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/SpriteActor.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.actor;
+
+import android.graphics.Canvas;
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite;
+
+/** A generic actor class for game objects. */
+public class SpriteActor extends Actor {
+ public static final String TYPE = "Sprite actor";
+ private final String type;
+ public AnimatedSprite sprite;
+ // 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/TextActor.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/TextActor.java
new file mode 100644
index 000000000..de9f42691
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/actor/TextActor.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.actor;
+
+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();
+ public boolean hidden;
+ private String text;
+ private Paint paint;
+ private Rect bounds = new Rect();
+ private float previousAlpha;
+ 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 String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ paint.getTextBounds(text, 0, text.length(), bounds);
+ }
+
+ /** @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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/ActorTween.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/ActorTween.java
new file mode 100644
index 000000000..e40027751
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/ActorTween.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.animation;
+
+import com.google.android.apps.santatracker.doodles.shared.actor.Actor;
+
+/**
+ * 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/AnimatedSprite.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/AnimatedSprite.java
new file mode 100644
index 000000000..af8bfbfdf
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/AnimatedSprite.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.animation;
+
+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.Pair;
+import com.google.android.apps.santatracker.doodles.shared.BitmapCache;
+import com.google.android.apps.santatracker.doodles.shared.CallbackProcess;
+import com.google.android.apps.santatracker.doodles.shared.ProcessChain;
+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 com.google.android.apps.santatracker.util.SantaLog;
+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;
+ public int frameWidth;
+ public int frameHeight;
+ public Vector2D anchor = Vector2D.get();
+ private Bitmap[] frames;
+ 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();
+ 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;
+ SantaLog.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);
+ }
+
+ public static void clearCache() {
+ if (AnimatedSprite.bitmapCache != null) {
+ AnimatedSprite.bitmapCache.clear();
+ }
+ }
+
+ /** Set whether to loop the animation or not. */
+ public void setLoop(boolean loop) {
+ this.loop = loop;
+ }
+
+ public boolean isFlippedX() {
+ return flippedX;
+ }
+
+ public void setFlippedX(boolean value) {
+ this.flippedX = value;
+ }
+
+ 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;
+ }
+
+ public int getFrameIndex() {
+ return (int) frameIndex;
+ }
+
+ /** Sets the current frame. */
+ public void setFrameIndex(int frame) {
+ frameIndex = frame;
+ }
+
+ 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();
+ }
+
+ // 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/ElasticOutInterpolator.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/ElasticOutInterpolator.java
new file mode 100644
index 000000000..6a0adde61
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/ElasticOutInterpolator.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.animation;
+
+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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/EmptyTween.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/EmptyTween.java
new file mode 100644
index 000000000..88508ec12
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/EmptyTween.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.animation;
+
+/**
+ * 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/Interpolator.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/Interpolator.java
new file mode 100644
index 000000000..4ba175055
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/Interpolator.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.animation;
+
+/** 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/Sprites.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/Sprites.java
new file mode 100644
index 000000000..2d50614ab
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/Sprites.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.animation;
+
+import com.google.android.apps.santatracker.doodles.R;
+
+/** Frame data for all the sprites. */
+public interface Sprites {
+ int[] debug_marker = {
+ R.drawable.debug_marker,
+ };
+
+ 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,
+ };
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/Tween.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/Tween.java
new file mode 100644
index 000000000..747fbc084
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/Tween.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.animation;
+
+import com.google.android.apps.santatracker.doodles.shared.Process;
+
+/**
+ * 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/TweenManager.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/TweenManager.java
new file mode 100644
index 000000000..fdee59f4e
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/animation/TweenManager.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.animation;
+
+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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleDebugLogger.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleDebugLogger.java
new file mode 100644
index 000000000..7efcc0f17
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleDebugLogger.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.logging;
+
+import com.google.android.apps.santatracker.util.SantaLog;
+
+/**
+ * A stub logger for the purposes of testing output of log statements in the Pineapple 2016 games.
+ */
+public class DoodleDebugLogger extends DoodleLogger {
+ private static final String TAG = DoodleDebugLogger.class.getSimpleName();
+
+ @Override
+ public void logEvent(DoodleLogEvent event) {
+ SantaLog.d(TAG, event.toString());
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleLogEvent.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleLogEvent.java
new file mode 100644
index 000000000..e794103fb
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleLogEvent.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.logging;
+
+import androidx.annotation.Nullable;
+
+/** A class used for constructing log events for the Pineapple 2016 games. */
+public class DoodleLogEvent {
+ public static final String DEFAULT_DOODLE_NAME = "doodle_game";
+
+ 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 PRESENT_TOSS_GAME_TYPE = "tossing";
+ 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 DoodleLogEvent(
+ 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("DoodleLogEvent(" + 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 DoodleLogEvent build() {
+ return new DoodleLogEvent(
+ doodleName, eventName, eventSubType, eventValue1, eventValue2, latencyMs);
+ }
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleLogTimer.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleLogTimer.java
new file mode 100644
index 000000000..c6e78c03c
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleLogTimer.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.logging;
+
+import androidx.annotation.VisibleForTesting;
+
+/** A helper for timing log events in the Pineapple 2016 games. */
+public class DoodleLogTimer {
+ private static DoodleLogTimer instance;
+ private long startTimeMs;
+ private long pauseTimeMs;
+ private boolean isPaused;
+ private LogClock clock;
+
+ private DoodleLogTimer() {
+ this(new LogClock());
+ }
+
+ @VisibleForTesting
+ DoodleLogTimer(LogClock clock) {
+ this.clock = clock;
+ startTimeMs = clock.currentTimeMillis();
+ }
+
+ public static DoodleLogTimer getInstance() {
+ if (instance == null) {
+ instance = new DoodleLogTimer();
+ }
+ return instance;
+ }
+
+ 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 DoodleLogTimer. */
+ @VisibleForTesting
+ static class LogClock {
+ public long currentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleLogger.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleLogger.java
new file mode 100644
index 000000000..2de770a01
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleLogger.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.logging;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+
+/** Interface for logging DoodleEvents within the pineapple games. */
+public abstract class DoodleLogger {
+ private static final String PREFS_NAME = "PineappleLoggerPrefs";
+
+ public abstract void logEvent(DoodleLogEvent 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(DoodleLogEvent.DISTINCT_GAMES_PLAYED, 0);
+ if (gamePlays == 0) {
+ // If this is our first time playing this game, increment distinct games played.
+ editor.putInt(DoodleLogEvent.DISTINCT_GAMES_PLAYED, ++distinctGamesPlayed);
+ }
+ editor.putInt(gameType, ++gamePlays);
+ editor.commit();
+
+ logEvent(
+ new DoodleLogEvent.Builder(DoodleLogEvent.DEFAULT_DOODLE_NAME, eventName)
+ .withEventSubType(gameType)
+ .withEventValue1(gamePlays)
+ .withEventValue2(distinctGamesPlayed)
+ .build());
+
+ return null;
+ }
+ }.execute();
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleNullLogger.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleNullLogger.java
new file mode 100644
index 000000000..ef6837e7a
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/logging/DoodleNullLogger.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.logging;
+
+/** A stub of a logger which does nothing. */
+public class DoodleNullLogger extends DoodleLogger {
+
+ @Override
+ public void logEvent(DoodleLogEvent event) {
+ // Do nothing.
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Polygon.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Polygon.java
new file mode 100644
index 000000000..12edc7c0e
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Polygon.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.Constants;
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import java.util.ArrayList;
+import java.util.List;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * 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;
+ public List vertices;
+ public List normals;
+ public Vector2D min;
+ public Vector2D max;
+ private Paint vertexPaint;
+ private Paint midpointPaint;
+ private Paint linePaint;
+ 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 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);
+ }
+
+ 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) {
+ 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;
+ }
+
+ /**
+ * 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Util.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Util.java
new file mode 100644
index 000000000..45f3ed6a0
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/physics/Util.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/DoodleMediaPlayer.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/DoodleMediaPlayer.java
new file mode 100644
index 000000000..c032217e4
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/DoodleMediaPlayer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 DoodleMediaPlayer {
+ 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/DoodleMediaPlayerImpl.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/DoodleMediaPlayerImpl.java
new file mode 100644
index 000000000..334f93807
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/DoodleMediaPlayerImpl.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 com.google.android.apps.santatracker.util.SantaLog;
+
+/**
+ * A wrapper around a MediaPlayer so that we can define our own LoopingMediaPlayer and have it use a
+ * common interface.
+ */
+public class DoodleMediaPlayerImpl implements DoodleMediaPlayer {
+ private static final String TAG = DoodleMediaPlayerImpl.class.getSimpleName();
+
+ private MediaPlayer mediaPlayer;
+ private float volume;
+
+ private DoodleMediaPlayerImpl(Context context, int resId) {
+ mediaPlayer = MediaPlayer.create(context, resId);
+ }
+
+ public static DoodleMediaPlayerImpl create(Context context, int resId) {
+ return new DoodleMediaPlayerImpl(context, resId);
+ }
+
+ @Override
+ public void start() {
+ try {
+ mediaPlayer.start();
+ } catch (IllegalStateException e) {
+ SantaLog.w(TAG, "start() failed: " + e.toString());
+ }
+ }
+
+ @Override
+ public boolean isPlaying() {
+ return mediaPlayer.isPlaying();
+ }
+
+ @Override
+ public void pause() {
+ try {
+ mediaPlayer.pause();
+ } catch (IllegalStateException e) {
+ SantaLog.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) {
+ SantaLog.w(TAG, "setNextMediaPlayer() failed: " + e.toString());
+ }
+ }
+
+ @Override
+ public void setVolume(float volume) {
+ this.volume = volume;
+ try {
+ mediaPlayer.setVolume(volume, volume);
+ } catch (IllegalStateException e) {
+ SantaLog.w(TAG, "setVolume() failed: " + e.toString());
+ }
+ }
+
+ @Override
+ public void mute() {
+ try {
+ mediaPlayer.setVolume(0, 0);
+ } catch (IllegalStateException e) {
+ SantaLog.w(TAG, "mute() failed: " + e.toString());
+ }
+ }
+
+ @Override
+ public void unmute() {
+ try {
+ mediaPlayer.setVolume(volume, volume);
+ } catch (IllegalStateException e) {
+ SantaLog.w(TAG, "unmute() failed: " + e.toString());
+ }
+ }
+
+ @Override
+ public void release() {
+ try {
+ mediaPlayer.release();
+ } catch (IllegalStateException e) {
+ SantaLog.w(TAG, "release() failed: " + e.toString());
+ }
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/LoopingMediaPlayer.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/LoopingMediaPlayer.java
new file mode 100644
index 000000000..79c995742
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/LoopingMediaPlayer.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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 com.google.android.apps.santatracker.util.SantaLog;
+
+/** A wrapper around a MediaPlayer which allows for a gapless, looping track. */
+public class LoopingMediaPlayer implements DoodleMediaPlayer {
+ private static final String TAG = LoopingMediaPlayer.class.getSimpleName();
+
+ private MediaPlayer currentPlayer;
+ private MediaPlayer nextPlayer;
+ private AssetFileDescriptor soundFileDescriptor;
+ private float volume;
+
+ 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) {
+ SantaLog.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) {
+ SantaLog.w(TAG, "onCompletion: unexpected exception", e);
+ }
+ }
+ });
+ }
+
+ public static LoopingMediaPlayer create(Context context, int resId) {
+ return new LoopingMediaPlayer(context, resId);
+ }
+
+ @Override
+ public void start() {
+ try {
+ currentPlayer.start();
+ } catch (IllegalStateException e) {
+ SantaLog.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) {
+ SantaLog.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) {
+ SantaLog.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) {
+ SantaLog.w(TAG, "setVolume() failed: ", e);
+ }
+ }
+
+ @Override
+ public void mute() {
+ try {
+ currentPlayer.setVolume(0, 0);
+ nextPlayer.setVolume(0, 0);
+ } catch (Exception e) {
+ SantaLog.w(TAG, "mute() failed: ", e);
+ }
+ }
+
+ @Override
+ public void unmute() {
+ try {
+ currentPlayer.setVolume(volume, volume);
+ nextPlayer.setVolume(volume, volume);
+ } catch (Exception e) {
+ SantaLog.w(TAG, "unmute() failed: ", e);
+ }
+ }
+
+ @Override
+ public void release() {
+ try {
+ currentPlayer.release();
+ nextPlayer.release();
+ soundFileDescriptor.close();
+ } catch (Exception e) {
+ SantaLog.w(TAG, "release() failed: ", e);
+ }
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/SoundManager.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/SoundManager.java
new file mode 100644
index 000000000..0e31c1a53
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/sound/SoundManager.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.AudioManager;
+import android.media.SoundPool;
+import android.os.AsyncTask;
+import com.google.android.apps.santatracker.AudioConstants;
+import com.google.android.apps.santatracker.data.SantaPreferences;
+import com.google.android.apps.santatracker.util.SantaLog;
+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();
+ public static boolean soundsAreMuted;
+ private static SoundManager instance;
+ 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 SantaPreferences mSantaPreferences;
+
+ 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;
+ }
+ DoodleMediaPlayer mediaPlayer;
+ if (looping) {
+ mediaPlayer = LoopingMediaPlayer.create(context, resId);
+ } else {
+ mediaPlayer = DoodleMediaPlayerImpl.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, AudioConstants.DEFAULT_BACKGROUND_VOLUME);
+ }
+
+ 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, AudioConstants.DEFAULT_SOUND_EFFECT_VOLUME);
+ }
+
+ 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)) {
+ DoodleMediaPlayer 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 {
+ DoodleMediaPlayer[] sounds = new DoodleMediaPlayer[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) {
+ SantaLog.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 (DoodleMediaPlayer 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) {
+ if (mSantaPreferences == null) {
+ mSantaPreferences = new SantaPreferences(context.getApplicationContext());
+ }
+ mSantaPreferences.setMuted(soundsAreMuted);
+ }
+
+ public void loadMutePreference(final Context context) {
+ if (mSantaPreferences == null) {
+ mSantaPreferences = new SantaPreferences(context.getApplicationContext());
+ }
+ if (mSantaPreferences.isMuted()) {
+ mute();
+ } else {
+ unmute();
+ }
+ }
+
+ 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-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/GameFragment.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/GameFragment.java
new file mode 100644
index 000000000..0d0c6297b
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/GameFragment.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.views;
+
+import static com.google.android.apps.santatracker.doodles.shared.EventBus.GAME_LOADED;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.DEFAULT_DOODLE_NAME;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.LOADING_COMPLETE;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.Fragment;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import com.google.android.apps.santatracker.doodles.BaseDoodleActivity;
+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.EventBus;
+import com.google.android.apps.santatracker.doodles.shared.GameLoop;
+import com.google.android.apps.santatracker.doodles.shared.HistoryManager;
+import com.google.android.apps.santatracker.doodles.shared.LogicRefreshThread;
+import com.google.android.apps.santatracker.doodles.shared.UIRefreshHandler;
+import com.google.android.apps.santatracker.doodles.shared.UIUtil;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.Builder;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogTimer;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogger;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleNullLogger;
+import com.google.android.apps.santatracker.doodles.shared.sound.SoundManager;
+import com.google.android.apps.santatracker.invites.AppInvitesFragment;
+
+/** 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 Context context;
+ public final DoodleLogger logger;
+ public boolean isDestroyed = false;
+ protected FrameLayout wrapper;
+ protected View titleView;
+ protected ScoreView scoreView;
+ protected PauseView pauseView;
+ protected LogicRefreshThread logicRefreshThread;
+ protected UIRefreshHandler uiRefreshHandler;
+ protected SoundManager soundManager;
+ protected HistoryManager historyManager;
+ protected boolean isFinishedLoading = false;
+ protected boolean isPaused = false;
+ protected PauseView.GamePausedListener gamePausedListener =
+ new PauseView.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 ScoreView.LevelFinishedListener levelFinishedListener =
+ new ScoreView.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 boolean resumeAfterLoading;
+ private ImageView titleImageView;
+ private AsyncTask asyncLoadGameTask;
+
+ public GameFragment() {
+ this.logger = new DoodleNullLogger();
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ // TODO: Remove context from the field. Workaround not to change the existing code
+ this.context = context;
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ this.context = null;
+ }
+
+ @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 == null || 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;
+ }
+
+ firstPassLoadOnUiThread();
+ secondPassLoadOnBackgroundThread();
+ finalPassLoadOnUiThread();
+
+ asyncLoadGameTask =
+ new AsyncTask() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ if (getActivity() != null) {
+ secondPassLoadOnBackgroundThread();
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ if (getActivity() != null) {
+ finalPassLoadOnUiThread();
+ }
+ }
+ };
+ asyncLoadGameTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ protected void firstPassLoadOnUiThread() {}
+
+ protected void secondPassLoadOnBackgroundThread() {
+ EventBus.getInstance().clearListeners();
+ }
+
+ protected void finalPassLoadOnUiThread() {}
+
+ protected void onFinishedLoading() {
+ DoodleLogTimer logTimer = DoodleLogTimer.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() {
+ if (titleView != null && titleView.getVisibility() == View.VISIBLE) {
+ 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;
+ DoodleLogTimer.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.setLogger(logger);
+ scoreView.setListener(levelFinishedListener);
+ return scoreView;
+ }
+
+ protected PauseView getPauseView() {
+ PauseView pauseView = new PauseView(context);
+ pauseView.setLogger(logger);
+ pauseView.setListener(gamePausedListener);
+ return pauseView;
+ }
+
+ @Override
+ public void onShareClicked() {
+ Activity activity = getActivity();
+ if (activity instanceof BaseDoodleActivity) {
+ AppInvitesFragment invites = ((BaseDoodleActivity) activity).getAppInvitesFragment();
+ if (invites != null) {
+ invites.sendGenericInvite();
+ }
+ }
+ }
+
+ protected abstract String getGameType();
+
+ public void onBackPressed() {
+ pauseView.pause();
+ }
+
+ public abstract boolean isGameOver();
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/GameOverlayButton.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/GameOverlayButton.java
new file mode 100644
index 000000000..c49f9ae18
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/GameOverlayButton.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.views;
+
+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,
+ com.google.android.apps.santatracker.common.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);
+ }
+ ta.recycle();
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/PauseView.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/PauseView.java
new file mode 100644
index 000000000..84ac9a9b5
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/PauseView.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.views;
+
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.DEFAULT_DOODLE_NAME;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.HOME_CLICKED;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.MUTE_CLICKED;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.PAUSE_CLICKED;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.REPLAY_CLICKED;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.UNMUTE_CLICKED;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.UNPAUSE_CLICKED;
+
+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.AndroidUtils;
+import com.google.android.apps.santatracker.doodles.shared.EventBus;
+import com.google.android.apps.santatracker.doodles.shared.UIUtil;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.Builder;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogTimer;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogger;
+import com.google.android.apps.santatracker.doodles.shared.sound.SoundManager;
+
+/** The overlay which is shown when a game is paused. */
+public class PauseView extends FrameLayout {
+
+ public static final int FADE_DURATION_MS = 400; // The pause button fading in and out.
+ 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 boolean isPauseButtonEnabled = true;
+ private GamePausedListener listener;
+ private DoodleLogger logger;
+
+ private ImageButton muteButton;
+ private GameOverlayButton pauseButton;
+ private View resumeButton;
+ private View buttonContainer;
+ private View background;
+ 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 setLogger(DoodleLogger 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(
+ com.google.android.apps.santatracker.common.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
+ ? com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .drawable
+ .common_btn_speaker_off
+ : com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .drawable
+ .common_btn_speaker_on);
+ muteButton.setContentDescription(
+ context.getResources()
+ .getString(
+ shouldMute
+ ? com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .string
+ .unmute
+ : com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .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(DoodleLogTimer.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(DoodleLogTimer.getInstance().timeElapsedMs())
+ .withEventValue1(listener.score())
+ .build());
+
+ AndroidUtils.finishActivity(context);
+ }
+ });
+
+ background = view.findViewById(R.id.pause_view_background);
+ backgroundAlpha = background.getAlpha();
+ }
+
+ private void replay() {
+ DoodleLogTimer.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(DoodleLogTimer.getInstance().timeElapsedMs())
+ .build());
+ DoodleLogTimer.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() {
+ DoodleLogTimer.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(
+ com.google.android.apps.santatracker.common.R.drawable.common_btn_speaker_off);
+ } else {
+ muteButton.setImageResource(
+ com.google.android.apps.santatracker.common.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();
+ }
+
+ /** A listener for interacting with the PauseView. */
+ public interface GamePausedListener {
+ void onPause();
+
+ void onResume();
+
+ void onReplay();
+
+ String gameType();
+
+ float score();
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/ScoreView.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/ScoreView.java
new file mode 100644
index 000000000..18e636687
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/ScoreView.java
@@ -0,0 +1,706 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.views;
+
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.DEFAULT_DOODLE_NAME;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.GAME_OVER;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.HOME_CLICKED;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.REPLAY_CLICKED;
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.SHARE_CLICKED;
+
+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.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.AndroidUtils;
+import com.google.android.apps.santatracker.doodles.shared.EventBus;
+import com.google.android.apps.santatracker.doodles.shared.UIUtil;
+import com.google.android.apps.santatracker.doodles.shared.animation.ElasticOutInterpolator;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.Builder;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogTimer;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogger;
+import com.google.android.apps.santatracker.util.SantaLog;
+
+/** 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();
+ // 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;
+ protected DoodleLogger logger;
+ protected LevelFinishedListener listener;
+ // 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 boolean canReplay;
+
+ private OnShareClickedListener shareClickedListener;
+
+ 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 setLogger(DoodleLogger 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);
+
+ 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());
+ AndroidUtils.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(),
+ com.google.android.apps.santatracker.common.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() {
+ SantaLog.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());
+ SantaLog.i(TAG, "Animate to end state");
+ canReplay = false;
+ setVisibility(View.VISIBLE);
+ logger.logEvent(
+ new Builder(DEFAULT_DOODLE_NAME, GAME_OVER)
+ .withEventSubType(listener.gameType())
+ .withLatencyMs(DoodleLogTimer.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();
+ }
+
+ public interface OnShareClickedListener {
+ void onShareClicked();
+ }
+
+ /** A listener for events which occur from the level finished screen. */
+ public interface LevelFinishedListener {
+ void onReplay();
+
+ String gameType();
+
+ float score();
+
+ int shareImageId();
+ }
+}
diff --git a/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/StarView.java b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/StarView.java
new file mode 100644
index 000000000..ca328fdc8
--- /dev/null
+++ b/doodles-lib/src/main/java/com/google/android/apps/santatracker/doodles/shared/views/StarView.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.views;
+
+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-lib/src/main/res/drawable-nodpi/debug_marker.webp b/doodles-lib/src/main/res/drawable-nodpi/debug_marker.webp
new file mode 100644
index 000000000..ccaf3c161
Binary files /dev/null and b/doodles-lib/src/main/res/drawable-nodpi/debug_marker.webp differ
diff --git a/doodles-lib/src/main/res/drawable-nodpi/pineapple_star_empty.webp b/doodles-lib/src/main/res/drawable-nodpi/pineapple_star_empty.webp
new file mode 100644
index 000000000..5fc23747a
Binary files /dev/null and b/doodles-lib/src/main/res/drawable-nodpi/pineapple_star_empty.webp differ
diff --git a/doodles-lib/src/main/res/drawable-nodpi/pineapple_star_filled.webp b/doodles-lib/src/main/res/drawable-nodpi/pineapple_star_filled.webp
new file mode 100644
index 000000000..0713e5f40
Binary files /dev/null and b/doodles-lib/src/main/res/drawable-nodpi/pineapple_star_filled.webp differ
diff --git a/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_00.webp b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_00.webp
new file mode 100644
index 000000000..a898bc520
Binary files /dev/null and b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_00.webp differ
diff --git a/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_01.webp b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_01.webp
new file mode 100644
index 000000000..d1a3fa91b
Binary files /dev/null and b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_01.webp differ
diff --git a/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_02.webp b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_02.webp
new file mode 100644
index 000000000..faefd61b3
Binary files /dev/null and b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_02.webp differ
diff --git a/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_03.webp b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_03.webp
new file mode 100644
index 000000000..44335d602
Binary files /dev/null and b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_03.webp differ
diff --git a/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_04.webp b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_04.webp
new file mode 100644
index 000000000..9a64f83b5
Binary files /dev/null and b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_04.webp differ
diff --git a/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_05.webp b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_05.webp
new file mode 100644
index 000000000..5e74b7d7b
Binary files /dev/null and b/doodles-lib/src/main/res/drawable-nodpi/tutoappear_new_05.webp differ
diff --git a/doodles-lib/src/main/res/layout/activity_view.xml b/doodles-lib/src/main/res/layout/activity_view.xml
new file mode 100644
index 000000000..937aff3c4
--- /dev/null
+++ b/doodles-lib/src/main/res/layout/activity_view.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
diff --git a/doodles-lib/src/main/res/layout/fact_view.xml b/doodles-lib/src/main/res/layout/fact_view.xml
new file mode 100644
index 000000000..0c8542626
--- /dev/null
+++ b/doodles-lib/src/main/res/layout/fact_view.xml
@@ -0,0 +1,26 @@
+
+
+
diff --git a/doodles-lib/src/main/res/layout/game_overlay_button.xml b/doodles-lib/src/main/res/layout/game_overlay_button.xml
new file mode 100644
index 000000000..c405325e3
--- /dev/null
+++ b/doodles-lib/src/main/res/layout/game_overlay_button.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
diff --git a/doodles-lib/src/main/res/layout/pause_view.xml b/doodles-lib/src/main/res/layout/pause_view.xml
new file mode 100644
index 000000000..ac76dd74e
--- /dev/null
+++ b/doodles-lib/src/main/res/layout/pause_view.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doodles-lib/src/main/res/layout/score_view.xml b/doodles-lib/src/main/res/layout/score_view.xml
new file mode 100644
index 000000000..3176d3908
--- /dev/null
+++ b/doodles-lib/src/main/res/layout/score_view.xml
@@ -0,0 +1,214 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doodles-lib/src/main/res/layout/star_view.xml b/doodles-lib/src/main/res/layout/star_view.xml
new file mode 100644
index 000000000..ec5898d9f
--- /dev/null
+++ b/doodles-lib/src/main/res/layout/star_view.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
diff --git a/doodles-lib/src/main/res/raw/fruit_doodle_music.m4a b/doodles-lib/src/main/res/raw/fruit_doodle_music.m4a
new file mode 100644
index 000000000..0547d03c5
Binary files /dev/null and b/doodles-lib/src/main/res/raw/fruit_doodle_music.m4a differ
diff --git a/doodles-lib/src/main/res/raw/menu_item_click.ogg b/doodles-lib/src/main/res/raw/menu_item_click.ogg
new file mode 100644
index 000000000..a8754bb10
Binary files /dev/null and b/doodles-lib/src/main/res/raw/menu_item_click.ogg differ
diff --git a/doodles-lib/src/main/res/raw/ui_positive_sound.ogg b/doodles-lib/src/main/res/raw/ui_positive_sound.ogg
new file mode 100644
index 000000000..98913c7a5
Binary files /dev/null and b/doodles-lib/src/main/res/raw/ui_positive_sound.ogg differ
diff --git a/doodles-lib/src/main/res/values-sw360dp/dimens.xml b/doodles-lib/src/main/res/values-sw360dp/dimens.xml
new file mode 100644
index 000000000..a26ad4c6f
--- /dev/null
+++ b/doodles-lib/src/main/res/values-sw360dp/dimens.xml
@@ -0,0 +1,27 @@
+
+
+
+
+ 20dp
+ 30dp
+ 60dp
+ 240dp
+ 70dp
+ 8dp
+ 16sp
+ 90dp
+
diff --git a/doodles-lib/src/main/res/values-sw600dp/dimens.xml b/doodles-lib/src/main/res/values-sw600dp/dimens.xml
new file mode 100644
index 000000000..4438dce37
--- /dev/null
+++ b/doodles-lib/src/main/res/values-sw600dp/dimens.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ 20dp
+ 16sp
+ 120dp
+ 80dp
+ 140dp
+ 100dp
+ 280dp
+ 20dp
+ 70dp
+ 8dp
+ 16sp
+ 100dp
+ 80dp
+ 70dp
+ 240dp
+
diff --git a/doodles-lib/src/main/res/values/attrs.xml b/doodles-lib/src/main/res/values/attrs.xml
new file mode 100644
index 000000000..326f2e596
--- /dev/null
+++ b/doodles-lib/src/main/res/values/attrs.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doodles-lib/src/main/res/values/colors.xml b/doodles-lib/src/main/res/values/colors.xml
new file mode 100644
index 000000000..bbbc8a57f
--- /dev/null
+++ b/doodles-lib/src/main/res/values/colors.xml
@@ -0,0 +1,27 @@
+
+
+
+
+ #ffffff
+ #fed32b
+ #000000
+ #ffffff
+ - 0.80
+
+ #aa032702
+ #00032702
+
diff --git a/doodles-lib/src/main/res/values/dimens.xml b/doodles-lib/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..e54734a4a
--- /dev/null
+++ b/doodles-lib/src/main/res/values/dimens.xml
@@ -0,0 +1,58 @@
+
+
+
+
+ 48dp
+ 25dp
+ 25dp
+ 76dp
+ 76dp
+ 24dp
+ 40dp
+ 3dp
+ 130dp
+ 25dp
+ 100sp
+ 100dp
+ 80dp
+ 40dp
+ 348dp
+ 148dp
+ 5dp
+ 70dp
+ 50dp
+ 100dp
+ 80dp
+ 15dp
+ 12sp
+ 200dp
+ 40dp
+ 10dp
+ 10dp
+ 20dp
+ 60dp
+ 6dp
+ 12sp
+ 10dp
+ 80dp
+ 46dp
+ 40dp
+ 138dp
+ 20sp
+ 20dp
+ 40dp
+
diff --git a/doodles-lib/src/main/res/values/values_analytics.xml b/doodles-lib/src/main/res/values/values_analytics.xml
new file mode 100644
index 000000000..d81ffb249
--- /dev/null
+++ b/doodles-lib/src/main/res/values/values_analytics.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ Swimming
+ Running
+ PresentToss
+
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 000000000..30b4b4f16
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,42 @@
+#
+# Copyright 2019. Google LLC
+#
+# 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
+#
+# https://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.
+#
+
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+
+org.gradle.daemon=true
+org.gradle.configureondemand=true
+org.gradle.parallel=true
+org.gradle.caching=true
+
+org.gradle.jvmargs=-Xmx6g -XX:MaxPermSize=1536m
+
+# https://developer.android.com/studio/build/build-cache.html
+android.enableBuildCache=true
+android.enableR8=true
+
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 8c0fb64a8..7a3265ee9 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ed9bb705d..acc201290 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Mon Jan 12 15:23:35 EST 2015
+#Fri Jan 11 14:26:09 AEDT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/gradlew b/gradlew
index 91a7e269e..cccdd3d51 100755
--- a/gradlew
+++ b/gradlew
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
##############################################################################
##
@@ -6,20 +6,38 @@
##
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
-warn ( ) {
+warn () {
echo "$*"
}
-die ( ) {
+die () {
echo
echo "$*"
echo
@@ -30,6 +48,7 @@ die ( ) {
cygwin=false
msys=false
darwin=false
+nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
@@ -40,31 +59,11 @@ case "`uname`" in
MINGW* )
msys=true
;;
+ NONSTOP* )
+ nonstop=true
+ ;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -90,7 +89,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +113,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +154,19 @@ if $cygwin ; then
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index aec99730b..e95643d6a 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +46,9 @@ echo location of your Java installation.
goto fail
:init
-@rem Get command-line arguments, handling Windowz variants
+@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
diff --git a/gumball/build.gradle b/gumball/build.gradle
new file mode 100644
index 000000000..30448f8f8
--- /dev/null
+++ b/gumball/build.gradle
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
+apply plugin: 'com.android.dynamic-feature'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.tools
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
+ }
+}
+
+dependencies {
+ implementation project(':santa-tracker')
+
+ implementation rootProject.files('third_party/jbox2d/jbox2d-library-2.2.1.1.jar')
+}
diff --git a/gumball/src/main/AndroidManifest.xml b/gumball/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8b780fdd0
--- /dev/null
+++ b/gumball/src/main/AndroidManifest.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/gumball/Edges.java b/gumball/src/main/java/com/google/android/apps/gumball/Edges.java
similarity index 96%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/gumball/Edges.java
rename to gumball/src/main/java/com/google/android/apps/gumball/Edges.java
index fe7a5d240..97dd04f0a 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/gumball/Edges.java
+++ b/gumball/src/main/java/com/google/android/apps/gumball/Edges.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,27 +14,23 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.gumball;
+package com.google.android.apps.gumball;
import org.jbox2d.collision.shapes.EdgeShape;
import org.jbox2d.common.Vec2;
-/**
- * Static methods to get the edge paths of the scene
- *
- * @author kchapman
- */
+/** Static methods to get the edge paths of the scene */
public class Edges {
public static EdgeShape[] getCaneEnd() {
EdgeShape[] edgeShapes = new EdgeShape[3];
- //rounded part
+ // rounded part
edgeShapes[0] = new EdgeShape();
edgeShapes[0].set(new Vec2(0.22f, .858f), new Vec2(0.22f, 1.02f));
- //bottom
+ // bottom
edgeShapes[1] = new EdgeShape();
edgeShapes[1].set(new Vec2(0.04f, .84f), new Vec2(.2f, .84f));
- //top
+ // top
edgeShapes[2] = new EdgeShape();
edgeShapes[2].set(new Vec2(0.03f, 1.04f), new Vec2(.2f, 1.04f));
return edgeShapes;
@@ -42,13 +38,13 @@ public static EdgeShape[] getCaneEnd() {
public static EdgeShape[] getCaneEndFlip() {
EdgeShape[] edgeShapes = new EdgeShape[3];
- //rounded part
+ // rounded part
edgeShapes[0] = new EdgeShape();
edgeShapes[0].set(new Vec2(0.04f, .858f), new Vec2(0.04f, 1.02f));
- //bottom
+ // bottom
edgeShapes[1] = new EdgeShape();
edgeShapes[1].set(new Vec2(0.06f, .845f), new Vec2(.263f, .845f));
- //top
+ // top
edgeShapes[2] = new EdgeShape();
edgeShapes[2].set(new Vec2(0.06f, 1.04f), new Vec2(.263f, 1.04f));
return edgeShapes;
@@ -56,13 +52,13 @@ public static EdgeShape[] getCaneEndFlip() {
public static EdgeShape[] getCaneEndReverse() {
EdgeShape[] edgeShapes = new EdgeShape[3];
- //rounded part
+ // rounded part
edgeShapes[0] = new EdgeShape();
edgeShapes[0].set(new Vec2(0.22f, .128f), new Vec2(0.22f, .29f));
- //bottom
+ // bottom
edgeShapes[1] = new EdgeShape();
edgeShapes[1].set(new Vec2(0.04f, .11f), new Vec2(.2f, .11f));
- //top
+ // top
edgeShapes[2] = new EdgeShape();
edgeShapes[2].set(new Vec2(0.03f, .31f), new Vec2(.2f, .31f));
return edgeShapes;
@@ -70,13 +66,13 @@ public static EdgeShape[] getCaneEndReverse() {
public static EdgeShape[] getCaneEndReverseFlip() {
EdgeShape[] edgeShapes = new EdgeShape[3];
- //rounded part
+ // rounded part
edgeShapes[0] = new EdgeShape();
edgeShapes[0].set(new Vec2(0.04f, .128f), new Vec2(0.04f, .29f));
- //connector
+ // connector
edgeShapes[1] = new EdgeShape();
edgeShapes[1].set(new Vec2(0.06f, .31f), new Vec2(0.04f, .29f));
- //top
+ // top
edgeShapes[2] = new EdgeShape();
edgeShapes[2].set(new Vec2(0.06f, .31f), new Vec2(.263f, .31f));
return edgeShapes;
@@ -305,10 +301,10 @@ public static EdgeShape[] getCaneMainSmallAngleNineShapes() {
edgeShapes[0].set(new Vec2(0.01f, 0.935f), new Vec2(3.66f, 0.325f));
edgeShapes[1] = new EdgeShape();
edgeShapes[1].set(new Vec2(0.25f, 0.675f), new Vec2(3.6f, 0.105f));
- //backstop
+ // backstop
edgeShapes[2] = new EdgeShape();
edgeShapes[2].set(new Vec2(0.15f, 0.755f), new Vec2(0.28f, 1.55f));
- //end
+ // end
edgeShapes[3] = new EdgeShape();
edgeShapes[3].set(new Vec2(3.66f, 0.128f), new Vec2(3.70f, 0.295f));
return edgeShapes;
@@ -320,10 +316,10 @@ public static EdgeShape[] getCaneMainSmallAngleTwelveShapes() {
edgeShapes[0].set(new Vec2(0.01f, 0.73f), new Vec2(2.04f, 0.305f));
edgeShapes[1] = new EdgeShape();
edgeShapes[1].set(new Vec2(0.25f, 0.475f), new Vec2(2.0f, 0.1f));
- //backstop
+ // backstop
edgeShapes[2] = new EdgeShape();
edgeShapes[2].set(new Vec2(0.18f, 0.725f), new Vec2(0.29f, 1.30f));
- //end
+ // end
edgeShapes[3] = new EdgeShape();
edgeShapes[3].set(new Vec2(2.01f, 0.128f), new Vec2(2.05f, 0.293f));
return edgeShapes;
@@ -335,10 +331,10 @@ public static EdgeShape[] getCaneMainTinyAngleSixShapes() {
edgeShapes[0].set(new Vec2(0.10f, 0.33f), new Vec2(1.9f, 0.425f));
edgeShapes[1] = new EdgeShape();
edgeShapes[1].set(new Vec2(0.15f, 0.105f), new Vec2(1.8f, 0.20f));
- //backstop
+ // backstop
edgeShapes[2] = new EdgeShape();
edgeShapes[2].set(new Vec2(1.94f, 0.425f), new Vec2(1.91f, 1.07f));
- //end
+ // end
edgeShapes[3] = new EdgeShape();
edgeShapes[3].set(new Vec2(0.07f, 0.128f), new Vec2(0.06f, 0.313f));
@@ -357,7 +353,7 @@ public static EdgeShape[] getCaneMainSmallAngleSixShapes() {
edgeShapes[0].set(new Vec2(0.05f, 0.515f), new Vec2(2.69f, 0.329f));
edgeShapes[1] = new EdgeShape();
edgeShapes[1].set(new Vec2(0.30f, 0.285f), new Vec2(2.66f, 0.119f));
- //backstop
+ // backstop
edgeShapes[2] = new EdgeShape();
edgeShapes[2].set(new Vec2(0.15f, 0.455f), new Vec2(0.27f, 1.15f));
return edgeShapes;
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/gumball/Gumball.java b/gumball/src/main/java/com/google/android/apps/gumball/Gumball.java
similarity index 75%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/gumball/Gumball.java
rename to gumball/src/main/java/com/google/android/apps/gumball/Gumball.java
index 3deeb7af8..77fba5d38 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/gumball/Gumball.java
+++ b/gumball/src/main/java/com/google/android/apps/gumball/Gumball.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,13 +14,10 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.gumball;
+package com.google.android.apps.gumball;
import java.util.UUID;
-/**
- * @author kchapman
- */
public class Gumball {
public float mXInitPos;
@@ -28,7 +25,5 @@ public class Gumball {
public UUID mSoundPoolId;
public int mGumballColorId;
- public Gumball() {
-
- }
+ public Gumball() {}
}
diff --git a/gumball/src/main/java/com/google/android/apps/gumball/GumballActivity.java b/gumball/src/main/java/com/google/android/apps/gumball/GumballActivity.java
new file mode 100644
index 000000000..eeaeaafed
--- /dev/null
+++ b/gumball/src/main/java/com/google/android/apps/gumball/GumballActivity.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.gumball;
+
+import android.os.Bundle;
+import com.google.android.apps.playgames.common.PlayGamesActivity;
+import com.google.android.apps.santatracker.util.MeasurementManager;
+import com.google.firebase.analytics.FirebaseAnalytics;
+
+public class GumballActivity extends PlayGamesActivity {
+
+ private static final String TAG = GumballActivity.class.getSimpleName();
+
+ private TiltGameFragment mGumballFragment;
+ private FirebaseAnalytics mMeasurement;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mGumballFragment = TiltGameFragment.newInstance();
+ getSupportFragmentManager()
+ .beginTransaction()
+ .replace(
+ com.google.android.apps.playgames.R.id.mainFragmentContainer,
+ mGumballFragment)
+ .commit();
+
+ // App Measurement
+ mMeasurement = FirebaseAnalytics.getInstance(this);
+ MeasurementManager.recordScreenView(
+ mMeasurement,
+ getString(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .string
+ .analytics_screen_gumball));
+ }
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.activity_gumball;
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mGumballFragment != null) {
+ mGumballFragment.onBackKeyPressed();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ public void onSignInSucceeded() {
+ super.onSignInSucceeded();
+ mGumballFragment.onSignInSucceeded();
+ }
+
+ @Override
+ public String getGameId() {
+ return getResources().getString(com.google.android.apps.playgames.R.string.gumball_game_id);
+ }
+
+ @Override
+ public String getGameTitle() {
+ return getString(com.google.android.apps.santatracker.common.R.string.gumball);
+ }
+
+ @Override
+ public void onSignInFailed() {
+ super.onSignInFailed();
+ mGumballFragment.onSignInFailed();
+ }
+}
diff --git a/gumball/src/main/java/com/google/android/apps/gumball/PhysicsWorld.java b/gumball/src/main/java/com/google/android/apps/gumball/PhysicsWorld.java
new file mode 100644
index 000000000..a184bdda5
--- /dev/null
+++ b/gumball/src/main/java/com/google/android/apps/gumball/PhysicsWorld.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.gumball;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.jbox2d.collision.shapes.CircleShape;
+import org.jbox2d.collision.shapes.EdgeShape;
+import org.jbox2d.collision.shapes.PolygonShape;
+import org.jbox2d.collision.shapes.Shape;
+import org.jbox2d.common.Vec2;
+import org.jbox2d.dynamics.Body;
+import org.jbox2d.dynamics.BodyDef;
+import org.jbox2d.dynamics.BodyType;
+import org.jbox2d.dynamics.FixtureDef;
+import org.jbox2d.dynamics.World;
+
+/** Wraps the game world and physics simulation for the gumball game. */
+public class PhysicsWorld {
+
+ /** All {@link org.jbox2d.dynamics.Body} objects in the world. */
+ private List
mBodies = new ArrayList();
+ /** The Physics world. */
+ private World mWorld;
+ /** Bodies that are to be removed from the scene. */
+ public List mBodiesToBeRemoved = new ArrayList();
+ /** Render refresh rate. */
+ private static final float FRAME_RATE = 1.0f / 45.0f;
+ /** Create the physics world and draws the boundries */
+ public void create(Vec2 gravity) {
+
+ // Create Physics World with Gravity
+ mWorld = new World(gravity);
+ mWorld.setAllowSleep(false);
+ mWorld.setSleepingAllowed(false);
+ mWorld.setAutoClearForces(true);
+
+ BodyDef groundBodyDef = new BodyDef();
+
+ // Create Ground Box
+ groundBodyDef.position.set(new Vec2(5.0f, -2.0f));
+ Body groundBody = mWorld.createBody(groundBodyDef);
+ PolygonShape polygonShape = new PolygonShape();
+
+ // Create top bound
+ groundBodyDef.position.set(new Vec2(5.0f, 32.0f));
+ groundBody = mWorld.createBody(groundBodyDef);
+ groundBody.createFixture(polygonShape, 1.0f);
+
+ polygonShape.setAsBox(2.0f, 18.0f);
+
+ // Create left wall
+ groundBodyDef.position.set(new Vec2(-2.0f, 16.0f));
+ groundBody = mWorld.createBody(groundBodyDef);
+ groundBody.createFixture(polygonShape, 1.0f);
+
+ // Create right wall
+ groundBodyDef.position.set(new Vec2(12.0f, 16.0f));
+ groundBody = mWorld.createBody(groundBodyDef);
+ groundBody.createFixture(polygonShape, 1.0f);
+ }
+
+ /** Adds a gumball to the scene. */
+ public void addGumball(
+ float x,
+ float y,
+ Gumball gumball,
+ float density,
+ float radius,
+ float bounce,
+ float friction,
+ BodyType bodyType) {
+ // Create Shape with Properties
+ CircleShape circleShape = new CircleShape();
+ circleShape.m_radius = radius;
+ addItem(x, y, circleShape, bounce, gumball, density, friction, bodyType);
+ }
+
+ public void addPipeSides(
+ float x,
+ float y,
+ int data,
+ float density,
+ float bounce,
+ float friction,
+ BodyType bodyType) {
+ EdgeShape[] edgeShapes = new EdgeShape[2];
+ edgeShapes[0] = new EdgeShape();
+ edgeShapes[0].set(new Vec2(.23f, -1f), new Vec2(.01f, .48f));
+ edgeShapes[1] = new EdgeShape();
+ edgeShapes[1].set(new Vec2(1.4f, -1f), new Vec2(1.55f, .45f));
+ addItem(x, y, edgeShapes, bounce, data, density, friction, bodyType);
+ }
+
+ public void addPipeBottom(
+ float x,
+ float y,
+ int data,
+ float density,
+ float bounce,
+ float friction,
+ BodyType bodyType) {
+ EdgeShape[] edgeShapes = new EdgeShape[1];
+ edgeShapes[0] = new EdgeShape();
+ edgeShapes[0].set(new Vec2(.83f, 0f), new Vec2(2.40f, 0f));
+ addItem(x, y, edgeShapes, bounce, data, density, friction, bodyType);
+ }
+
+ public void addFloor(
+ float x,
+ float y,
+ int data,
+ float density,
+ float bounce,
+ float friction,
+ BodyType bodyType) {
+ EdgeShape[] edgeShapes = new EdgeShape[1];
+ edgeShapes[0] = new EdgeShape();
+ edgeShapes[0].set(new Vec2(-9f, -.8f), new Vec2(9f, -.8f));
+ addItem(x, y, edgeShapes, bounce, data, density, friction, bodyType);
+ }
+
+ public void addItem(
+ float x,
+ float y,
+ Shape[] shapes,
+ float bounce,
+ int data,
+ float density,
+ float friction,
+ BodyType bodyType) {
+
+ // Create Dynamic Body
+ BodyDef bodyDef = new BodyDef();
+ bodyDef.position.set(x, y);
+ bodyDef.userData = data;
+ bodyDef.type = bodyType;
+ Body body = mWorld.createBody(bodyDef);
+ mBodies.add(body);
+
+ for (int i = 0; i < shapes.length; i++) {
+ // Assign shape to Body
+ FixtureDef fixtureDef = new FixtureDef();
+ fixtureDef.shape = shapes[i];
+ fixtureDef.density = density;
+ fixtureDef.friction = friction;
+ fixtureDef.restitution = bounce;
+
+ body.createFixture(fixtureDef);
+ }
+ }
+
+ public void addItem(
+ float x,
+ float y,
+ Shape shape,
+ float bounce,
+ int data,
+ float density,
+ float friction,
+ BodyType bodyType) {
+
+ // Create Dynamic Body
+ BodyDef bodyDef = new BodyDef();
+ bodyDef.position.set(x, y);
+ bodyDef.userData = data;
+ bodyDef.type = bodyType;
+ Body body = mWorld.createBody(bodyDef);
+ mBodies.add(body);
+
+ // Assign shape to Body
+ FixtureDef fixtureDef = new FixtureDef();
+ fixtureDef.shape = shape;
+ fixtureDef.density = density;
+ fixtureDef.friction = friction;
+ fixtureDef.restitution = bounce;
+ body.createFixture(fixtureDef);
+ }
+
+ public void addItem(
+ float x,
+ float y,
+ Shape shape,
+ float bounce,
+ Gumball gumball,
+ float density,
+ float friction,
+ BodyType bodyType) {
+
+ // Create Dynamic Body
+ BodyDef bodyDef = new BodyDef();
+ bodyDef.position.set(x, y);
+ bodyDef.userData = gumball;
+ bodyDef.type = bodyType;
+ Body body = mWorld.createBody(bodyDef);
+ mBodies.add(body);
+
+ // Assign shape to Body
+ FixtureDef fixtureDef = new FixtureDef();
+ fixtureDef.shape = shape;
+ fixtureDef.density = density;
+ fixtureDef.friction = friction;
+ fixtureDef.restitution = bounce;
+ body.createFixture(fixtureDef);
+ }
+
+ /** Updates the physics world by removing all pending bodies. */
+ public void update() {
+ // Update Physics World
+ for (int i = 0; i < mBodiesToBeRemoved.size(); i++) {
+ mWorld.destroyBody(mBodiesToBeRemoved.get(i));
+ }
+ mBodiesToBeRemoved.clear();
+ mWorld.step(FRAME_RATE, 10, 10);
+ mWorld.clearForces();
+ }
+
+ /** Gets a reference to the world. */
+ public World getWorld() {
+ return mWorld;
+ }
+}
diff --git a/gumball/src/main/java/com/google/android/apps/gumball/TiltGameFragment.java b/gumball/src/main/java/com/google/android/apps/gumball/TiltGameFragment.java
new file mode 100644
index 000000000..9192b792b
--- /dev/null
+++ b/gumball/src/main/java/com/google/android/apps/gumball/TiltGameFragment.java
@@ -0,0 +1,1215 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.gumball;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.graphics.drawable.AnimationDrawable;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.SoundPool;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Surface;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.view.animation.TranslateAnimation;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+import androidx.fragment.app.Fragment;
+import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
+import com.google.android.apps.playgames.Utils;
+import com.google.android.apps.playgames.common.GameConstants;
+import com.google.android.apps.playgames.common.PlayGamesActivity;
+import com.google.android.apps.playgames.customviews.CircleView;
+import com.google.android.apps.playgames.customviews.LevelTextView;
+import com.google.android.apps.santatracker.common.CheckableImageButton;
+import com.google.android.apps.santatracker.data.SantaPreferences;
+import com.google.android.apps.santatracker.invites.AppInvitesFragment;
+import com.google.android.apps.santatracker.util.ImmersiveModeHelper;
+import com.google.android.apps.santatracker.util.SoundPoolUtils;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import org.jbox2d.callbacks.ContactImpulse;
+import org.jbox2d.callbacks.ContactListener;
+import org.jbox2d.collision.Manifold;
+import org.jbox2d.common.Vec2;
+import org.jbox2d.dynamics.Body;
+import org.jbox2d.dynamics.BodyType;
+import org.jbox2d.dynamics.contacts.Contact;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/** Gumball game fragment. */
+public class TiltGameFragment extends Fragment
+ implements SensorEventListener, ContactListener, AnimationListener, OnClickListener {
+
+ /** Bounce rate of objects in the physics world. */
+ public static final float WORLD_OBJECT_BOUNCE = 0.2f;
+ /** Density of objects in the physics world. */
+ public static final float WORLD_OBJECT_DENSITY = 185.77f;
+ /** Friction of objects in the physics world. */
+ public static final float WORLD_OBJECT_FRICTION = 0.2f;
+ /** Friction of floor objects in the physics world. */
+ public static final float WORLD_FLOOR_FRICTION = 0.8f;
+ /** Initial X position of the floor and pipes in the physics world. */
+ public static final float WORLD_FLOOR_X = 3.37f;
+ /*
+ * Initial Y position of the floor and pipes in the physics world.
+ */
+ public static final float WORLD_FLOOR_Y = 0f;
+ /** Holder for sound pool id to handle playbacks, connects and disconnects. */
+ private final HashMap mSoundPoolId = new HashMap<>();
+ /** View that contains the main game. */
+ private TiltGameView mGameView;
+ /** Box2D physics world for this game. */
+ private PhysicsWorld mWorld;
+ /**
+ * Current rotation of the device. Used to adjust sensor readings if the screen is rotate in
+ * portrait or landscape.
+ *
+ * @see android.view.Display#getRotation()
+ */
+ private int mRotation;
+ /** Main game thread. */
+ private Runnable mGameThread;
+ /**
+ * Previous value of the sensor's Y reading. Used to calculate the rotational offset between
+ * sensor events.
+ */
+ private float mPreviousSensorY = 0f;
+ /** MediaPlayer that plays the background music. */
+ private MediaPlayer mBackgroundMusic;
+ /** Index of loaded sound effect in sound pool for small bounce. */
+ private int mSoundBounceSmall = -1;
+ /** Index of loaded sound effect in sound pool for medium bounce. */
+ private int mSoundBounceMed = -1;
+ /** Index of loaded sound effect in sound pool for large bounce. */
+ private int mSoundBounceLarge = -1;
+ /** Index of loaded sound effect in sound pool for ball in machine. */
+ private int mSoundBallInMachine = -1;
+ /** Index of loaded sound effect in sound pool for failed ball. */
+ private int mSoundBallFail = -1;
+ /** Index of loaded sound effect in sound pool for dropped ball. */
+ private int mSoundBallDrop = -1;
+ /** Index of loaded sound effect in sound pool for game over. */
+ private int mSoundGameOver = -1;
+ /** Scale down animation for level. */
+ private Animation mAnimationScaleLevelDown;
+ /** Fading out animation for level. */
+ private Animation mAnimationLevelFadeOut;
+ /** Scaling up animation for level. */
+ private Animation mAnimationLevelScaleUp;
+ /** Outlet animation for balls. */
+ private Animation mAnimationOutlet;
+ /** Alpha animation for timer updates. */
+ private Animation mAnimationTimerAlpha;
+ /** View for end of level circle overlay. */
+ private CircleView mEndLevelCircle;
+ /** View that shows the current level number. */
+ private LevelTextView mLevelNumberText;
+ /** Sound pool from which all sounds are played back. */
+ private SoundPool mSoundPool;
+ /** Number of balls left in the game. */
+ private int mGameBallsLeft = 2;
+
+ /** Current play level. Zero indexed, first level is 0. */
+ private int mCurrentLevelNum = 0;
+
+ /** View for the ball outlet at the top of the screen. */
+ private View mGameOutlet;
+
+ /** Root view of the game layout. */
+ private View mRootView;
+
+ /** Gumballs that are queued to be dropped through the outlet. */
+ private Queue mGumballQueue;
+
+ /** The current, active gumball on screen. */
+ private Gumball mCurrentGumball;
+
+ /** X position of outlet in the last animation. */
+ private float mOutletPreviousXPos = 0;
+
+ /** Array of the ball indicator views at the bottom of the screen. */
+ private ImageView mViewIndicators[] = new ImageView[6];
+
+ /** Number of gumballs collected in the current game. */
+ private int mNumberCollected = 0;
+
+ /**
+ * Refresh rate for the game countdown timer.
+ *
+ * @see GameCountdown
+ */
+ private int mFramesPerSecond = 60;
+
+ /** Time left in the current game. Value in milliseconds. */
+ private long mTimeLeftInMillis = GameConstants.GUMBALL_INIT_TIME;
+
+ /** Countdown timer for the current game. */
+ private GameCountdown mCountDownTimer = null;
+
+ /** Countdown timer text. */
+ private TextView mViewCountdown;
+
+ /** Score text. */
+ private TextView mViewScore;
+
+ /** Total score of current game. */
+ private int mMatchScore = 0;
+
+ /**
+ * Number of balls that have respawned in the current level. Used to calculate the total game
+ * score.
+ */
+ private int mCountLevelBallRespawns = 0;
+
+ /** Flag indicating if the game is paused. */
+ private boolean wasPaused = false;
+
+ private ImageView mViewPlayButton;
+
+ private ImageView mViewPauseButton;
+
+ private ImageButton mViewBigPlayButton;
+
+ private ImageView mViewCancelBar;
+
+ private ImageView mViewInviteButton;
+
+ private View mViewMatchPauseOverlay;
+
+ private View mViewPlayAgainBackground;
+
+ private View mViewPlayAgainMain;
+
+ private Button mViewPlayAgainButton;
+
+ private TextView mViewPlayAgainScore;
+
+ private TextView mViewPlayAgainLevel;
+
+ private Animation mAnimationPlayAgainBackground;
+
+ private Animation mAnimationPlayAgainMain;
+
+ /** Display offset on X axis for outlet in pixels. */
+ private int mOutletOffset;
+
+ /** View that displays the instructions from {@link #mDrawableTransition} */
+ private ImageView mViewInstructions;
+
+ /** Drawable that contains all images for the instructions. */
+ private AnimationDrawable mDrawableTransition;
+
+ private SharedPreferences mSharedPreferences;
+
+ private ImageView mViewGPlusSignIn;
+
+ private View mViewGPlusLayout;
+
+ private ImageButton mViewMainMenuButton;
+
+ private AppInvitesFragment mInvitesFragment;
+
+ private CheckableImageButton mMuteButton;
+ private SantaPreferences mSantaPreferences;
+
+ /** Gets an instance of this fragment */
+ public static TiltGameFragment newInstance() {
+ TiltGameFragment fragment = new TiltGameFragment();
+ return fragment;
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mSantaPreferences = new SantaPreferences(context);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ mRootView = inflater.inflate(R.layout.fragment_gumball, container, false);
+ mRootView.setKeepScreenOn(true);
+
+ mViewPlayAgainScore =
+ mRootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_score);
+ mViewPlayAgainScore.setText(String.valueOf(mMatchScore));
+ mViewPlayAgainLevel =
+ mRootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_level);
+ mViewPlayAgainLevel.setText(String.valueOf(mCurrentLevelNum));
+ mViewPlayAgainBackground =
+ mRootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_bkgrd);
+ mViewPlayAgainMain =
+ mRootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_main);
+ mViewPlayAgainButton =
+ mRootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_btn);
+ mViewPlayAgainButton.setOnClickListener(this);
+
+ mViewGPlusSignIn =
+ mRootView.findViewById(com.google.android.apps.santatracker.R.id.gplus_button);
+ mViewGPlusSignIn.setOnClickListener(this);
+ mViewGPlusLayout =
+ mRootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_gplus);
+ mViewGPlusLayout.setVisibility(View.GONE);
+
+ // Initialise all animations
+ // Construct an animation to blink the timer indefinitely
+ mAnimationTimerAlpha = new AlphaAnimation(0.0f, 1.0f);
+ mAnimationTimerAlpha.setDuration(1000);
+ mAnimationTimerAlpha.setRepeatMode(Animation.REVERSE);
+ mAnimationTimerAlpha.setRepeatCount(Animation.INFINITE);
+
+ // Load all other animations
+ mAnimationPlayAgainBackground =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.play_again_bkgrd_anim);
+ mAnimationPlayAgainBackground.setFillAfter(true);
+ mAnimationPlayAgainBackground.setAnimationListener(this);
+ mAnimationPlayAgainMain =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.play_again_main_anim);
+ mAnimationPlayAgainMain.setFillAfter(true);
+ mAnimationPlayAgainMain.setAnimationListener(this);
+ mAnimationScaleLevelDown =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.scale_level_anim_down);
+ mAnimationScaleLevelDown.setAnimationListener(this);
+ mAnimationLevelFadeOut =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.level_fade_out_anim);
+ mAnimationLevelFadeOut.setAnimationListener(this);
+ mAnimationLevelScaleUp =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.scale_up_level_anim);
+ mAnimationLevelScaleUp.setAnimationListener(this);
+
+ mViewMainMenuButton =
+ mRootView.findViewById(com.google.android.apps.santatracker.R.id.main_menu_button);
+ mViewMainMenuButton.setVisibility(View.GONE);
+ mViewMainMenuButton.setOnClickListener(this);
+
+ // App Invites Button
+ mViewInviteButton =
+ mRootView.findViewById(com.google.android.apps.santatracker.R.id.invite_button);
+ mViewInviteButton.setVisibility(View.GONE);
+ mViewInviteButton.setOnClickListener(this);
+
+ mGameOutlet = mRootView.findViewById(R.id.tiltGameOutlet);
+ mOutletOffset =
+ getResources()
+ .getInteger(com.google.android.apps.playgames.R.integer.outlet_offset);
+
+ mViewIndicators[0] = (ImageView) mRootView.findViewById(R.id.indicator1);
+ mViewIndicators[1] = (ImageView) mRootView.findViewById(R.id.indicator2);
+ mViewIndicators[2] = (ImageView) mRootView.findViewById(R.id.indicator3);
+ mViewIndicators[3] = (ImageView) mRootView.findViewById(R.id.indicator4);
+ mViewIndicators[4] = (ImageView) mRootView.findViewById(R.id.indicator5);
+ mViewIndicators[5] = (ImageView) mRootView.findViewById(R.id.indicator6);
+ mViewCountdown = (TextView) mRootView.findViewById(R.id.tiltTimer);
+
+ mLevelNumberText = (LevelTextView) mRootView.findViewById(R.id.tilt_end_level_number);
+ mLevelNumberText.setVisibility(View.GONE);
+ mEndLevelCircle = (CircleView) mRootView.findViewById(R.id.tilt_end_level_circle);
+ mEndLevelCircle.setVisibility(View.GONE);
+
+ mViewPlayButton = (ImageView) mRootView.findViewById(R.id.tilt_play_button);
+ mViewPlayButton.setOnClickListener(this);
+ mViewPlayButton.setVisibility(View.GONE);
+ mViewPauseButton = (ImageView) mRootView.findViewById(R.id.tilt_pause_button);
+ mViewPauseButton.setOnClickListener(this);
+ mViewPauseButton.setVisibility(View.VISIBLE);
+ mViewMatchPauseOverlay = mRootView.findViewById(R.id.tilt_pause_overlay);
+ mViewMatchPauseOverlay.setVisibility(View.GONE);
+ mViewBigPlayButton = (ImageButton) mRootView.findViewById(R.id.tilt_big_play_button);
+ mViewBigPlayButton.setOnClickListener(this);
+ mViewCancelBar = (ImageView) mRootView.findViewById(R.id.tilt_cancel_bar);
+ mViewCancelBar.setOnClickListener(this);
+ mViewCancelBar.setVisibility(View.GONE);
+
+ mViewScore = (TextView) mRootView.findViewById(R.id.tilt_score);
+ mViewScore.setText(String.valueOf(mMatchScore));
+
+ mGameView = (TiltGameView) mRootView.findViewById(R.id.tiltGameView);
+
+ // Create the Box2D physics world.
+ mWorld = new PhysicsWorld();
+ Vec2 gravity = new Vec2(0.0f, 0.0f);
+ mWorld.create(gravity);
+ mGameView.setModel(mWorld);
+ mWorld.getWorld().setContactListener(this);
+
+ mGumballQueue = new LinkedList<>();
+
+ // Initialise the sound pool and audio playback
+ mSoundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
+ mSoundBounceSmall = mSoundPool.load(getActivity(), R.raw.gbg_ball_bounce_1, 1);
+ mSoundBounceMed = mSoundPool.load(getActivity(), R.raw.gbg_ball_bounce_2, 1);
+ mSoundBounceLarge = mSoundPool.load(getActivity(), R.raw.gbg_ball_bounce_3, 1);
+ mSoundBallInMachine = mSoundPool.load(getActivity(), R.raw.gbg_ball_into_machine, 1);
+ mSoundBallFail = mSoundPool.load(getActivity(), R.raw.gbg_ball_fall_out, 1);
+ mSoundBallDrop = mSoundPool.load(getActivity(), R.raw.gbg_new_ball_bounce_drop, 1);
+ mSoundGameOver =
+ mSoundPool.load(getActivity(), com.google.android.apps.playgames.R.raw.gameover, 1);
+
+ // Display the instructions if they haven't been seen before
+ mSharedPreferences =
+ getActivity()
+ .getSharedPreferences(
+ GameConstants.PREFERENCES_FILENAME, getActivity().MODE_PRIVATE);
+ if (!mSharedPreferences.getBoolean(GameConstants.GUMBALL_INSTRUCTIONS_VIEWED, false)) {
+ mDrawableTransition = new AnimationDrawable();
+
+ mDrawableTransition.addFrame(
+ VectorDrawableCompat.create(
+ getResources(),
+ com.google.android.apps.playgames.R.drawable.instructions_shake_1,
+ null),
+ 300);
+ mDrawableTransition.addFrame(
+ VectorDrawableCompat.create(
+ getResources(),
+ com.google.android.apps.playgames.R.drawable.instructions_shake_2,
+ null),
+ 300);
+ mDrawableTransition.addFrame(
+ VectorDrawableCompat.create(
+ getResources(),
+ com.google.android.apps.playgames.R.drawable.instructions_shake_3,
+ null),
+ 300);
+ mDrawableTransition.setOneShot(false);
+ mViewInstructions =
+ mRootView.findViewById(com.google.android.apps.playgames.R.id.instructions);
+
+ mViewInstructions.setImageDrawable(mDrawableTransition);
+ mViewInstructions.post(
+ new Runnable() {
+ public void run() {
+ mDrawableTransition.start();
+ }
+ });
+
+ // Hide the instructions after 2 seconds
+ mViewInstructions.postDelayed(new HideInstructionsRunnable(), 2200);
+ }
+
+ mMuteButton = mRootView.findViewById(R.id.mute_button);
+ mMuteButton.setChecked(!mSantaPreferences.isMuted());
+ mMuteButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mSantaPreferences.toggleMuted();
+ mMuteButton.setChecked(!mSantaPreferences.isMuted());
+ onMuteChanged(mSantaPreferences.isMuted());
+ }
+ });
+
+ return mRootView;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ mInvitesFragment = AppInvitesFragment.getInstance(getActivity());
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ // Resume the game play if the game was not paused
+ if (!wasPaused) {
+ mRotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
+ SensorManager sensorManager =
+ (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
+ Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ if (sensor != null) {
+ sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);
+ }
+ mCountDownTimer = new GameCountdown(mFramesPerSecond, mTimeLeftInMillis);
+ mCountDownTimer.start();
+ mGameView.setGameCountDown(mCountDownTimer);
+ }
+
+ // Start the game loop if it is not initialised yet
+ if (mGameThread == null) {
+ mGameThread =
+ new Runnable() {
+ public void run() {
+ synchronized (mWorld) {
+ if (!wasPaused) {
+ if (mCurrentLevelNum == 0) {
+ mCurrentLevelNum++;
+ loadLevel(mCurrentLevelNum);
+ }
+ mWorld.update();
+ mGameView.invalidate();
+ }
+ }
+ getActivity().getWindow().getDecorView().postDelayed(mGameThread, 10);
+ }
+ };
+ }
+ getActivity().getWindow().getDecorView().postDelayed(mGameThread, 1000);
+
+ loadBackgroundMusic();
+ updateSignInButtonVisibility();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ pauseGame();
+ stopBackgroundMusic();
+ getActivity().getWindow().getDecorView().removeCallbacks(mGameThread);
+ }
+
+ private void stopBackgroundMusic() {
+ if (mBackgroundMusic != null) {
+ mBackgroundMusic.stop();
+ mBackgroundMusic.release();
+ mBackgroundMusic = null;
+ }
+ }
+
+ private void loadBackgroundMusic() {
+ if (mSantaPreferences.isMuted()) {
+ return;
+ }
+ mBackgroundMusic =
+ MediaPlayer.create(
+ getActivity(),
+ com.google.android.apps.santatracker.R.raw.santatracker_musicloop);
+ mBackgroundMusic.setLooping(true);
+ mBackgroundMusic.setVolume(.2f, .2f);
+ mBackgroundMusic.start();
+ }
+
+ /** Hide the sign in button if sign in was successful. */
+ public void onSignInSucceeded() {
+ setSignInButtonVisibility(false);
+ }
+
+ public void onSignInFailed() {}
+
+ @Override
+ public void onClick(View view) {
+ if (view.equals(mViewPauseButton)) {
+ // Pause the game
+ pauseGame();
+ } else if (view.equals(mViewPlayButton) || view.equals(mViewBigPlayButton)) {
+ // Continue the game
+ unPauseGame();
+ } else if (view.equals(mViewPlayAgainButton)) {
+ // Reload the background music for a new game
+ if (mBackgroundMusic != null) {
+ mBackgroundMusic.stop();
+ mBackgroundMusic.release();
+ }
+ loadBackgroundMusic();
+
+ // Reset the game variables
+ mCurrentLevelNum = 0;
+ mTimeLeftInMillis = GameConstants.GUMBALL_INIT_TIME;
+ mMatchScore = 0;
+ mViewScore.setText(String.valueOf(mMatchScore));
+ wasPaused = false;
+
+ // Hide the pause screen
+ mViewPlayAgainBackground.clearAnimation();
+ mViewPlayAgainMain.clearAnimation();
+ mViewPlayAgainBackground.setVisibility(View.GONE);
+ mViewPlayAgainMain.setVisibility(View.GONE);
+ mViewGPlusLayout.setVisibility(View.GONE);
+ mViewMainMenuButton.setVisibility(View.GONE);
+ mViewInviteButton.setVisibility(View.GONE);
+ } else if (view.equals(mViewGPlusSignIn)) {
+ // Start sign-in flow.
+ PlayGamesActivity act = Utils.getPlayGamesActivity(this);
+ if (act != null) {
+ act.startSignIn();
+ }
+ } else if (view.equals(mViewCancelBar) || (view.equals(mViewMainMenuButton))) {
+ // Exit and return to previous Activity.
+ returnToBackClass();
+ } else if (view.equals(mViewInviteButton)) {
+ // Send App Invite
+ mInvitesFragment.sendGameInvite(
+ getString(com.google.android.apps.santatracker.common.R.string.gumball),
+ getString(com.google.android.apps.playgames.R.string.gumball_game_id),
+ mMatchScore);
+ }
+ }
+
+ private void returnToBackClass() {
+ getActivity().finish();
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ float x, y;
+ if (getActivity() != null) {
+ // Store the current screen rotation (used to offset the readings of the sensor).
+ mRotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
+ }
+
+ // Handle screen rotations by interpreting the sensor readings here
+ if (mRotation == Surface.ROTATION_0) {
+ x = -event.values[0];
+ y = -event.values[1];
+ } else if (mRotation == Surface.ROTATION_90) {
+ x = event.values[1];
+ y = -event.values[0];
+ } else if (mRotation == Surface.ROTATION_180) {
+ x = event.values[0];
+ y = event.values[1];
+ } else {
+ x = -event.values[1];
+ y = event.values[0];
+ }
+ // keep y low to simulate gravity
+ if (mPreviousSensorY == 0f) {
+ mPreviousSensorY = -9;
+ } else if (mPreviousSensorY > y) {
+ mPreviousSensorY = y;
+ }
+ // restrict x to ~+-45 degrees
+ x *= 0.5;
+ mWorld.getWorld().setGravity(new Vec2(x, mPreviousSensorY));
+ }
+
+ @Override
+ public void beginContact(Contact contact) {}
+
+ /**
+ * Handle contact with objects in the Box 2D world. Here the main game logic is implemented:
+ * When a ball hits the bottom pipe, it is removed and the next level or ball is started. When
+ * the ball goes over the edge, it is removed and a new ball is dropped from the pipe again.
+ */
+ @Override
+ public void endContact(Contact contact) {
+ // If the gumball goes in the pipe, remove it from the scene (Case 1/2)
+ if (contact.getFixtureA().getBody().getUserData() != null
+ && !(contact.getFixtureA().getBody().getUserData() instanceof Gumball)
+ && (contact.getFixtureA().getBody().getUserData().equals(TiltGameView.PIPE_BOTTOM)
+ || contact.getFixtureA()
+ .getBody()
+ .getUserData()
+ .equals(TiltGameView.PIPE_SIDES))) {
+ mWorld.mBodiesToBeRemoved.add(contact.getFixtureB().getBody());
+ mSoundPoolId.remove(
+ ((Gumball) contact.getFixtureB().getBody().getUserData()).mSoundPoolId);
+ onBallInPipe();
+ } else if (contact.getFixtureB().getBody().getUserData() != null
+ && !(contact.getFixtureB().getBody().getUserData() instanceof Gumball)
+ && (
+ // If the gumball goes in the pipe, remove it from the scene (Case 2/2)
+ contact.getFixtureA().getBody().getUserData().equals(TiltGameView.PIPE_BOTTOM)
+ || contact.getFixtureA()
+ .getBody()
+ .getUserData()
+ .equals(TiltGameView.PIPE_SIDES))) {
+ mWorld.mBodiesToBeRemoved.add(contact.getFixtureA().getBody());
+ mSoundPoolId.remove(
+ ((Gumball) contact.getFixtureA().getBody().getUserData()).mSoundPoolId);
+ onBallInPipe();
+ } else if (contact.getFixtureA().getBody().getUserData() != null
+ && !(contact.getFixtureA().getBody().getUserData() instanceof Gumball)
+ && contact.getFixtureA().getBody().getUserData().equals(TiltGameView.GAME_FLOOR)) {
+ // If the gumball goes over the edge, remove it and respawn (Case 1/2)
+ Gumball gumball = ((Gumball) contact.getFixtureB().getBody().getUserData());
+ mWorld.mBodiesToBeRemoved.add(contact.getFixtureB().getBody());
+ mSoundPoolId.remove(gumball.mSoundPoolId);
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundBallFail);
+ }
+ mWorld.getWorld().step(1.0f / 60.0f, 10, 10);
+ moveOutlet((mCurrentGumball.mXInitPos));
+ mCountLevelBallRespawns++;
+ } else if (contact.getFixtureB().getBody().getUserData() != null
+ && !(contact.getFixtureB().getBody().getUserData() instanceof Gumball)
+ && contact.getFixtureB().getBody().getUserData().equals(TiltGameView.GAME_FLOOR)) {
+ // If the gumball goes over the edge, remove it and respawn (Case 2/2)
+ Gumball gumball = ((Gumball) contact.getFixtureB().getBody().getUserData());
+ mWorld.mBodiesToBeRemoved.add(contact.getFixtureA().getBody());
+ mSoundPoolId.remove(gumball.mSoundPoolId);
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundBallFail);
+ }
+ mWorld.getWorld().step(1.0f / 60.0f, 10, 10);
+ moveOutlet((mCurrentGumball.mXInitPos));
+ mCountLevelBallRespawns++;
+ }
+ }
+
+ /**
+ * Successfully dropped a ball in the pipe. Add the next ball and go to the next level if no
+ * balls are left in this level.
+ */
+ private void onBallInPipe() {
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundBallInMachine);
+ }
+ mGameBallsLeft--;
+ mNumberCollected++;
+ changeIndicator();
+ mMatchScore += 50 * Math.max(1f, (mCurrentLevelNum - mCountLevelBallRespawns));
+ mViewScore.setText(String.valueOf(mMatchScore));
+ if (mGameBallsLeft == 0 && mViewPlayAgainBackground.getVisibility() != View.VISIBLE) {
+ // No balls are left in this level, go to the next one
+ mCurrentLevelNum++;
+ mLevelNumberText.setLevelNumber(mCurrentLevelNum);
+ mLevelNumberText.startAnimation(mAnimationLevelScaleUp);
+ mEndLevelCircle.startAnimation(mAnimationScaleLevelDown);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.jbox2d.callbacks.ContactListener#postSolve(org.jbox2d.dynamics.contacts
+ * .Contact, org.jbox2d.callbacks.ContactImpulse)
+ */
+
+ /**
+ * Play a sound on impact (when a ball is dropped). The sound depends on the severity of the
+ * impact.
+ *
+ * @see #playBounceSound(float)
+ */
+ @Override
+ public void postSolve(Contact contact, ContactImpulse impulse) {
+ // Get both collision objects
+ Object dataA = contact.getFixtureA().getBody().getUserData();
+ Object dataB = contact.getFixtureB().getBody().getUserData();
+
+ // Check if one of the objects is NOT a gumball, but a candy cane.
+ boolean hitCane = false;
+ if (dataA != null
+ && !(dataA instanceof Gumball)
+ && (Integer) dataA > TiltGameView.GUMBALL_PURPLE) {
+ hitCane = true;
+ } else if (dataB != null
+ && !(dataB instanceof Gumball)
+ && (Integer) dataB > TiltGameView.GUMBALL_PURPLE) {
+ hitCane = true;
+ }
+
+ if (hitCane && impulse.normalImpulses[0] > 80) {
+ playBounceSound(impulse.normalImpulses[0]);
+ }
+ }
+
+ /** Plays a 'bounce' sound through the sound pool, depending on the impulse. */
+ private void playBounceSound(float impulse) {
+ if (mSantaPreferences.isMuted()) {
+ return;
+ }
+ if (impulse > 80) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundBounceLarge);
+ } else if (impulse > 60) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundBounceMed);
+ } else if (impulse > 30) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundBounceSmall);
+ }
+ }
+
+ @Override
+ public void preSolve(Contact contact, Manifold arg1) {}
+
+ /** Add a gumball to the game and play the ball drop sound. */
+ private void addGumball(float xPos, float yPos) {
+ Gumball gumball = new Gumball();
+ gumball.mXInitPos = xPos;
+ gumball.mYInitPos = yPos;
+ gumball.mSoundPoolId = UUID.randomUUID();
+ mSoundPoolId.put(gumball.mSoundPoolId, false);
+ mGameView.addGumball(gumball);
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundBallDrop);
+ }
+ }
+
+ private JSONObject readLevelFile(int levelNumber) throws IOException, JSONException {
+ // load the appropriate levels file from a raw resource.
+ InputStream is = getResources().openRawResource(getCurrentLevelRawFile());
+ int size = is.available();
+ byte[] buffer = new byte[size];
+ is.read(buffer);
+ is.close();
+ String json = new String(buffer, "UTF-8");
+ JSONObject level = new JSONObject(json);
+
+ return level;
+ }
+
+ private int getCurrentLevelRawFile() {
+ if (mCurrentLevelNum > 13) {
+ mCurrentLevelNum = (mCurrentLevelNum % 13) + 1;
+ }
+ switch (mCurrentLevelNum) {
+ case 1:
+ return R.raw.level1;
+ case 2:
+ return R.raw.level2;
+ case 3:
+ return R.raw.level3;
+ case 4:
+ return R.raw.level4;
+ case 5:
+ return R.raw.level5;
+ case 6:
+ return R.raw.level6;
+ case 7:
+ return R.raw.level7;
+ case 8:
+ return R.raw.level8;
+ case 9:
+ return R.raw.level9;
+ case 10:
+ return R.raw.level10;
+ case 11:
+ return R.raw.level11;
+ case 12:
+ return R.raw.level12;
+ case 13:
+ return R.raw.level13;
+ default:
+ return R.raw.level1;
+ }
+ }
+
+ /** Loads a level from the levels json file and sets up the game world. */
+ private void loadLevel(int levelNumber) {
+
+ // Reset the current game state
+ if (mCountDownTimer != null) {
+ mCountDownTimer.cancel();
+ }
+ mCountLevelBallRespawns = 0;
+ mNumberCollected = 0;
+ mViewPlayAgainLevel.setText(String.valueOf(levelNumber));
+ Body body = mWorld.getWorld().getBodyList();
+ while (body != null) {
+ if (body.m_userData == null) {
+ body = body.getNext();
+ continue;
+ }
+ mWorld.mBodiesToBeRemoved.add(body);
+ body = body.getNext();
+ }
+ mWorld.getWorld().step(1.0f / 60.0f, 10, 10);
+
+ try {
+ // Read the level file and extract the candy cane positions
+ JSONObject level = readLevelFile(levelNumber);
+ JSONArray canes = level.getJSONArray("candycanes");
+
+ for (int i = 0; i < canes.length(); i++) {
+ JSONObject canePart = canes.getJSONObject(i);
+ int type = canePart.getInt("type");
+ float xPos = (float) canePart.getDouble("xPos");
+ float yPos = (float) canePart.getDouble("yPos");
+ // Add the candy cane to the game world, the values represent the
+ mWorld.addItem(
+ xPos,
+ yPos,
+ Edges.getEdges(type),
+ WORLD_OBJECT_BOUNCE,
+ type,
+ WORLD_OBJECT_DENSITY,
+ WORLD_OBJECT_FRICTION,
+ BodyType.STATIC);
+ }
+
+ // Add the sides and floor to the game world to catch dropped balls.
+ // Note that the WORLD_FRICTION is used as the bounce rate of the floors.
+ mWorld.addItem(
+ WORLD_FLOOR_X,
+ WORLD_FLOOR_Y,
+ Edges.getPipeSideEdges(),
+ WORLD_OBJECT_BOUNCE,
+ TiltGameView.PIPE_SIDES,
+ WORLD_OBJECT_DENSITY,
+ WORLD_OBJECT_FRICTION,
+ BodyType.STATIC);
+ mWorld.addFloor(
+ WORLD_FLOOR_X,
+ WORLD_FLOOR_Y,
+ TiltGameView.GAME_FLOOR,
+ WORLD_OBJECT_DENSITY,
+ WORLD_OBJECT_FRICTION,
+ WORLD_FLOOR_FRICTION,
+ BodyType.STATIC);
+ mWorld.addPipeBottom(
+ WORLD_FLOOR_X,
+ WORLD_FLOOR_Y,
+ TiltGameView.PIPE_BOTTOM,
+ WORLD_OBJECT_DENSITY,
+ WORLD_OBJECT_FRICTION,
+ WORLD_FLOOR_FRICTION,
+ BodyType.STATIC);
+
+ // Add the gumballs
+ JSONArray gumballs = level.getJSONArray("gumballs");
+ mGameBallsLeft = gumballs.length();
+ setIndicators(mGameBallsLeft);
+ for (int j = 0; j < gumballs.length(); j++) {
+ JSONObject gumball = gumballs.getJSONObject(j);
+ float xPos = (float) gumball.getDouble("xPos");
+ float yPos = (float) gumball.getDouble("yPos");
+ Gumball gumballObject = new Gumball();
+ gumballObject.mXInitPos = xPos;
+ gumballObject.mYInitPos = yPos;
+ mGumballQueue.add(gumballObject);
+ }
+ mCurrentGumball = mGumballQueue.poll();
+
+ // Start the timer
+ if (mCurrentGumball != null) {
+ if (mCurrentLevelNum > 1) {
+ // Do not include gumball dropping time in countdown calculation.
+ mTimeLeftInMillis += GameConstants.GUMBALL_ADDED_TIME;
+ }
+ mCountDownTimer = new GameCountdown(mFramesPerSecond, mTimeLeftInMillis);
+ mCountDownTimer.start();
+ mGameView.setGameCountDown(mCountDownTimer);
+
+ // Move the outlet to its initial position
+ moveOutlet((mCurrentGumball.mXInitPos));
+ }
+ } catch (IOException e) {
+ } catch (JSONException e) {
+ }
+ }
+
+ /**
+ * Update the state of the indicators at the bottom of the screen to the number of balls
+ * collected.
+ */
+ private void setIndicators(int numGumballs) {
+ for (int i = 0; i < mViewIndicators.length; i++) {
+ int stateResource = R.drawable.gbg_gumball_indicator_collected_disabled;
+ if (i + 1 <= numGumballs) {
+ stateResource = R.drawable.gbg_gumball_indicator_pending;
+ }
+ mViewIndicators[i].setImageResource(stateResource);
+ }
+ }
+
+ /** Mark the last indicator for which a ball was collected in the 'collected' state. */
+ private void changeIndicator() {
+ mViewIndicators[mNumberCollected - 1].setImageResource(
+ R.drawable.gbg_gumball_indicator_collected);
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (animation == mAnimationScaleLevelDown) {
+ // After the level scale down animation, fade out the level number and end circle
+ mLevelNumberText.startAnimation(mAnimationLevelFadeOut);
+ mEndLevelCircle.startAnimation(mAnimationLevelFadeOut);
+ } else if (animation == mAnimationLevelFadeOut) {
+ // After the level fade out animation reset and hide all other end level views
+ mEndLevelCircle.clearAnimation();
+ mLevelNumberText.clearAnimation();
+ mLevelNumberText.setVisibility(View.GONE);
+ mEndLevelCircle.setVisibility(View.GONE);
+ } else if (animation == mAnimationOutlet) {
+ // After the outlet has moved to the correct position, add gumball
+ addGumball(mCurrentGumball.mXInitPos, mCurrentGumball.mYInitPos);
+ if (mGumballQueue.peek() != null) {
+ // Move it to the next position if there is a gumball left in the queue
+ mCurrentGumball = mGumballQueue.poll();
+ moveOutlet(mCurrentGumball.mXInitPos);
+ }
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation arg0) {
+ // do nothing
+
+ }
+
+ @Override
+ public void onAnimationStart(Animation animation) {
+ if (animation == mAnimationScaleLevelDown) {
+ // Show the circle level end and level text views when the animation starts
+ mEndLevelCircle.setVisibility(View.VISIBLE);
+ mLevelNumberText.setVisibility(View.VISIBLE);
+ } else if (animation == mAnimationLevelFadeOut) {
+ // Load the next level after the end level animation is over
+ loadLevel(mCurrentLevelNum);
+ } else if (animation == mAnimationPlayAgainBackground) {
+ // Show the 'play again' screen when the animation starts and cancel the timer
+ mViewPlayAgainBackground.setVisibility(View.VISIBLE);
+ if (mCountDownTimer != null) {
+ mCountDownTimer.cancel();
+ }
+ } else if (animation == mAnimationPlayAgainMain) {
+ mViewPlayAgainMain.setVisibility(View.VISIBLE);
+ setSignInButtonVisibility(true);
+ }
+ }
+
+ /** Set the visibility of the sign in button if the user is not already signed in. */
+ private void setSignInButtonVisibility(boolean show) {
+ mViewGPlusLayout.setVisibility(show && !Utils.isSignedIn(this) ? View.VISIBLE : View.GONE);
+ }
+
+ /** Hide the sign in button when the user signs in and the button is still visible on screen. */
+ private void updateSignInButtonVisibility() {
+ if (mViewGPlusLayout.getVisibility() == View.VISIBLE && Utils.isSignedIn(this)) {
+ setSignInButtonVisibility(false);
+ }
+ }
+
+ /** Start an animation to move the outlet to the x position in pixels. */
+ private void moveOutlet(float xPos) {
+ float scale = mRootView.getWidth() / 10.0f;
+ mAnimationOutlet =
+ new TranslateAnimation(mOutletPreviousXPos, (scale * xPos) - mOutletOffset, 0, 0);
+ mAnimationOutlet.setDuration(700);
+ mAnimationOutlet.setFillAfter(true);
+ mAnimationOutlet.setStartOffset(400);
+ mAnimationOutlet.setAnimationListener(this);
+ mGameOutlet.startAnimation(mAnimationOutlet);
+ mOutletPreviousXPos = (scale * xPos) - mOutletOffset;
+ }
+
+ /** Pause the game when the back key is pressed. */
+ public void onBackKeyPressed() {
+ if (mViewPlayAgainMain.getVisibility() == View.VISIBLE) {
+ returnToBackClass();
+ } else {
+ if (mViewPauseButton.getVisibility() != View.GONE) { // check if already handled
+ pauseGame();
+ } else {
+ // Exit and return to previous Activity.
+ returnToBackClass();
+ }
+ }
+ }
+
+ /** Pause the game and display the pause game screen. */
+ private void pauseGame() {
+ mViewPauseButton.setVisibility(View.GONE);
+ mViewPlayButton.setVisibility(View.VISIBLE);
+ if (mCountDownTimer != null) {
+ mCountDownTimer.cancel();
+ wasPaused = true;
+ }
+ mViewMatchPauseOverlay.setVisibility(View.VISIBLE);
+ mViewCancelBar.setVisibility(View.VISIBLE);
+
+ SensorManager sensorManager =
+ (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
+ sensorManager.unregisterListener(this);
+ ImmersiveModeHelper.setImmersiveStickyWithActionBar(getActivity().getWindow());
+ }
+
+ /** Continue the paused game. Restart the countdown timer and hide the pause game screen. */
+ private void unPauseGame() {
+ mViewPauseButton.setVisibility(View.VISIBLE);
+ mViewPlayButton.setVisibility(View.GONE);
+ mViewMatchPauseOverlay.setVisibility(View.GONE);
+ mViewCancelBar.setVisibility(View.GONE);
+ mCountDownTimer = new GameCountdown(mFramesPerSecond, mTimeLeftInMillis);
+ mCountDownTimer.start();
+ mGameView.setGameCountDown(mCountDownTimer);
+ wasPaused = false;
+ SensorManager sensorManager =
+ (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
+ Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ if (sensor != null) {
+ sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);
+ }
+ ImmersiveModeHelper.setImmersiveSticky(getActivity().getWindow());
+ }
+
+ private void onMuteChanged(boolean muted) {
+ if (muted) {
+ stopBackgroundMusic();
+ mSoundPool.autoPause();
+ } else {
+ loadBackgroundMusic();
+ mSoundPool.autoResume();
+ }
+ }
+
+ /** Submit score to play games services */
+ private void submitScore(int resId, int score) {
+ PlayGamesActivity act = Utils.getPlayGamesActivity(this);
+ if (act != null) {
+ act.postSubmitScore(resId, score);
+ }
+ }
+
+ /**
+ * Countdown for the main game. Updates the countdown on screen and stops the game when the
+ * timer runs out.
+ */
+ public class GameCountdown {
+
+ private final long mMillisDuration;
+ private final long mMillisTickDuration;
+ private Boolean animationStarted = false;
+ private long mTicksLeft;
+
+ private boolean mStarted = false;
+
+ private long mSecondsTextValue = -1;
+
+ /**
+ * @param framesPerSecond assumed frame rate
+ * @param millisInFuture duration of game at this frame rate
+ */
+ public GameCountdown(int framesPerSecond, long millisInFuture) {
+ mMillisDuration = millisInFuture;
+ mMillisTickDuration = 1000 / framesPerSecond;
+ mTicksLeft = mMillisDuration / mMillisTickDuration;
+ }
+
+ /** Stop the timer. */
+ public void cancel() {
+ mTicksLeft = 0;
+ mStarted = false;
+ }
+
+ /** Starts the timer. */
+ public void start() {
+ mStarted = true;
+ mSecondsTextValue = -1;
+ long seconds = TimeUnit.MILLISECONDS.toSeconds(mTicksLeft * mMillisTickDuration);
+ if (seconds >= 6) {
+ animationStarted = false;
+ mViewCountdown.clearAnimation();
+ mViewCountdown.setTextColor(Color.WHITE);
+ mViewCountdown.setTypeface(Typeface.DEFAULT);
+ }
+ }
+
+ /** Update the displayed timer. When the timer is below 6s the text color changes to red. */
+ public void tick() {
+ if (mStarted) {
+ --mTicksLeft;
+ mTimeLeftInMillis = mTicksLeft * mMillisTickDuration;
+ if (mTimeLeftInMillis < 6000 && !animationStarted) {
+ animationStarted = true;
+ mViewCountdown.setTextColor(Color.RED);
+ mViewCountdown.setTypeface(Typeface.DEFAULT_BOLD);
+ mViewCountdown.clearAnimation();
+ mViewCountdown.startAnimation(mAnimationTimerAlpha);
+ }
+ if (mSecondsTextValue != mTimeLeftInMillis / 1000) {
+ mViewCountdown.setText(
+ String.format(
+ "%d:%02d",
+ TimeUnit.MILLISECONDS.toMinutes(mTimeLeftInMillis),
+ TimeUnit.MILLISECONDS.toSeconds(mTimeLeftInMillis)));
+ mSecondsTextValue = mTimeLeftInMillis / 1000;
+ }
+ if (mTimeLeftInMillis == 0) {
+ finished();
+ }
+ }
+ }
+
+ /**
+ * Shut down the count down timer. Cancel all pending animations and display the 'play
+ * again' screen.
+ */
+ private void finished() {
+ mViewCountdown.clearAnimation();
+ animationStarted = false;
+ mViewCountdown.setTextColor(Color.WHITE);
+ mViewCountdown.setTypeface(Typeface.DEFAULT);
+ if (mViewPlayAgainBackground.getVisibility() != View.VISIBLE && !wasPaused) {
+ wasPaused = true;
+ submitScore(GameConstants.LEADERBOARDS_GUMBALL, mMatchScore);
+ if (mBackgroundMusic != null) {
+ mBackgroundMusic.stop();
+ mBackgroundMusic.release();
+ mBackgroundMusic = null;
+ }
+ mViewPlayAgainScore.setText(String.valueOf(mMatchScore));
+ mViewPlayAgainBackground.startAnimation(mAnimationPlayAgainBackground);
+ mViewPlayAgainMain.startAnimation(mAnimationPlayAgainMain);
+ mViewPlayAgainBackground.setVisibility(View.VISIBLE);
+ mViewPlayAgainMain.setVisibility(View.VISIBLE);
+ mViewMainMenuButton.setVisibility(View.VISIBLE);
+ mViewInviteButton.setVisibility(View.VISIBLE);
+ setSignInButtonVisibility(true);
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundGameOver, .2f);
+ }
+ }
+
+ cancel();
+ }
+ }
+
+ /** Hide the instructions and mark them as viewed. */
+ private class HideInstructionsRunnable implements Runnable {
+
+ @Override
+ public void run() {
+ mDrawableTransition.stop();
+ wasPaused = false;
+ mViewInstructions.setVisibility(View.GONE);
+ Editor edit = mSharedPreferences.edit();
+ edit.putBoolean(GameConstants.GUMBALL_INSTRUCTIONS_VIEWED, true);
+ edit.apply();
+ }
+ }
+}
diff --git a/gumball/src/main/java/com/google/android/apps/gumball/TiltGameView.java b/gumball/src/main/java/com/google/android/apps/gumball/TiltGameView.java
new file mode 100644
index 000000000..8ac3da9a9
--- /dev/null
+++ b/gumball/src/main/java/com/google/android/apps/gumball/TiltGameView.java
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.gumball;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+import java.util.Random;
+import org.jbox2d.collision.shapes.CircleShape;
+import org.jbox2d.collision.shapes.EdgeShape;
+import org.jbox2d.collision.shapes.Shape;
+import org.jbox2d.common.Vec2;
+import org.jbox2d.dynamics.Body;
+import org.jbox2d.dynamics.BodyType;
+import org.jbox2d.dynamics.Fixture;
+
+/**
+ * Custom view which contains the elements used in the physics word. It handles the painting of all
+ * bitmaps for the game, including all levels (canes), the pipe and gumballs.
+ */
+public class TiltGameView extends View {
+
+ public static final float GUMBALL_DENSITY = 185.77f;
+ public static final float GUMBALL_RADIUS = 0.258f;
+ public static final float GUMBALL_BOUNCE = 0.2f;
+ public static final float GUMBALL_FRICTION = 0.8f;
+ /** The physics world for the gumball game. */
+ private PhysicsWorld mWorld;
+
+ /** Bitmaps for all elements on screen. */
+ private Bitmap mGumballBlue;
+
+ private Bitmap mGumballYellow;
+ private Bitmap mGumballRed;
+ private Bitmap mGumballGreen;
+ private Bitmap mGumballOrange;
+ private Bitmap mGumballPurple;
+ private Bitmap mCaneMainLong;
+ private Bitmap mCaneMainLongReverse;
+ private Bitmap mCaneMainMed;
+ private Bitmap mCaneMainMedReverse;
+ private Bitmap mCaneMainSmall;
+ private Bitmap mCaneMainSmallReverse;
+ private Bitmap mCaneMainTiny;
+ private Bitmap mCaneMainTinyReverse;
+ private Bitmap mCaneHook;
+ private Bitmap mCaneHookFlip;
+ private Bitmap mCaneHookReverse;
+ private Bitmap mCaneHookReverseFlip;
+ private Bitmap mCaneEnd;
+ private Bitmap mCaneEndFlip;
+ private Bitmap mCaneEndReverse;
+ private Bitmap mCaneEndReverseFlip;
+
+ private Bitmap mCaneMainSmallAngleNine;
+ private Bitmap mCaneMainSmallAngleSix;
+ private Bitmap mCaneMainSmallAngleTwelve;
+ private Bitmap mCaneMainReverseTinyAngleTwelve;
+ private Bitmap mCaneMainLargeAngleSix;
+ private Bitmap mCaneMainMedAngleSix;
+
+ /** Bitmap of a pipe where gumballs drop. */
+ private Bitmap mPipeSides;
+
+ /** Default paint object that is used to draw all bitmaps to the screen. */
+ private Paint mPaint = new Paint();
+
+ /** Identifiers for objects in the world. */
+ public static final int GUMBALL_RED = 0;
+
+ public static final int GUMBALL_BLUE = 1;
+ public static final int GUMBALL_YELLOW = 2;
+ public static final int GUMBALL_GREEN = 3;
+ public static final int GUMBALL_ORANGE = 4;
+ public static final int GUMBALL_PURPLE = 5;
+ public static final int[] GUMBALLS =
+ new int[] {
+ GUMBALL_RED,
+ GUMBALL_BLUE,
+ GUMBALL_YELLOW,
+ GUMBALL_GREEN,
+ GUMBALL_ORANGE,
+ GUMBALL_PURPLE
+ };
+
+ public static final int CANE_MAIN_LONG = 6;
+ public static final int CANE_MAIN_LONG_REVERSE = 7;
+ public static final int CANE_MAIN_MEDIUM = 8;
+ public static final int CANE_MAIN_MEDIUM_REVERSE = 9;
+ public static final int CANE_MAIN_SMALL = 10;
+ public static final int CANE_MAIN_SMALL_REVERSE = 11;
+ public static final int CANE_MAIN_TINY = 12;
+ public static final int CANE_MAIN_TINY_REVERSE = 13;
+ public static final int CANE_HOOK = 14;
+ public static final int CANE_HOOK_FLIP = 15;
+ public static final int CANE_HOOK_REVERSE = 16;
+ public static final int CANE_HOOK_REVERSE_FLIP = 17;
+ public static final int CANE_END = 18;
+ public static final int CANE_END_FLIP = 19;
+ public static final int CANE_END_REVERSE = 20;
+ public static final int CANE_END_REVERSE_FLIP = 21;
+
+ public static final int CANE_MAIN_SMALL_ANGLE_NINE = 22;
+ public static final int CANE_MAIN_SMALL_ANGLE_SIX = 23;
+ public static final int CANE_MAIN_SMALL_ANGLE_TWELVE = 24;
+ public static final int CANE_MAIN_REVERSE_TINY_ANGLE_SIX = 25;
+ public static final int CANE_MAIN_LARGE_ANGLE_SIX = 26;
+ public static final int CANE_MAIN_MED_ANGLE_SIX = 27;
+
+ public static final int PIPE_SIDES = -1;
+ /**
+ * Bottom of the pipe user data, this is separate from the side because the gumball is removed
+ * from the scene on collision with it.
+ */
+ public static final int PIPE_BOTTOM = -2;
+
+ public static final int GAME_FLOOR = -3;
+
+ private static Random sRandomGenerator = new Random();
+
+ private TiltGameFragment.GameCountdown mGameCountDown;
+
+ public TiltGameView(Context context) {
+ super(context);
+ init();
+ }
+
+ public TiltGameView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ setClickable(true);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ // Load the bitmaps as soon as we have the size of the view to scale them appropriately.
+ if (mGumballBlue == null) {
+ loadBitmaps();
+ }
+ }
+
+ private void loadBitmaps() {
+ // set the bitmaps
+ Resources res = getResources();
+ int[] gumballBlue = {
+ R.drawable.gbg_gumball_blue_1920,
+ R.drawable.gbg_gumball_blue_800,
+ R.drawable.gbg_gumball_blue_480
+ };
+ int[] gumballRed = {
+ R.drawable.gbg_gumball_red_1920,
+ R.drawable.gbg_gumball_red_800,
+ R.drawable.gbg_gumball_red_480
+ };
+ int[] gumballYellow = {
+ R.drawable.gbg_gumball_yellow_1920,
+ R.drawable.gbg_gumball_yellow_800,
+ R.drawable.gbg_gumball_yellow_480
+ };
+ int[] gumballGreen = {
+ R.drawable.gbg_gumball_green_1920,
+ R.drawable.gbg_gumball_green_800,
+ R.drawable.gbg_gumball_green_480
+ };
+ int[] gumballOrange = {
+ R.drawable.gbg_gumball_orange_1920,
+ R.drawable.gbg_gumball_orange_800,
+ R.drawable.gbg_gumball_orange_480
+ };
+ int[] gumballPurple = {
+ R.drawable.gbg_gumball_purple_1920,
+ R.drawable.gbg_gumball_purple_800,
+ R.drawable.gbg_gumball_purple_480
+ };
+ int[] caneMain = {
+ R.drawable.gbg_candycane_main_1920,
+ R.drawable.gbg_candycane_main_800,
+ R.drawable.gbg_candycane_main_480
+ };
+ int[] caneMainReverse = {
+ R.drawable.gbg_candycane_main_reverse_1920,
+ R.drawable.gbg_candycane_main_reverse_800,
+ R.drawable.gbg_candycane_main_reverse_480
+ };
+ int[] caneHook = {
+ R.drawable.gbg_candycane_hook_1920,
+ R.drawable.gbg_candycane_hook_800,
+ R.drawable.gbg_candycane_hook_480
+ };
+ int[] caneHookReverse = {
+ R.drawable.gbg_candycane_hook_reverse_1920,
+ R.drawable.gbg_candycane_hook_reverse_800,
+ R.drawable.gbg_candycane_hook_reverse_480
+ };
+ int[] caneEnd = {
+ R.drawable.gbg_candycane_end_1920,
+ R.drawable.gbg_candycane_end_800,
+ R.drawable.gbg_candycane_end_480
+ };
+ int[] caneEndReverse = {
+ R.drawable.gbg_candycane_end_reverse_1920,
+ R.drawable.gbg_candycane_end_reverse_800,
+ R.drawable.gbg_candycane_end_reverse_480
+ };
+ int[] pipes = {
+ R.drawable.gbg_gumball_funnel_1920,
+ R.drawable.gbg_gumball_funnel_800,
+ R.drawable.gbg_gumball_funnel_480
+ };
+ int[] caneMainAngleNine = {
+ R.drawable.gbg_candycane_main_angle_nine_1920,
+ R.drawable.gbg_candycane_main_angle_nine_960,
+ R.drawable.gbg_candycane_main_angle_nine_480
+ };
+ int[] caneMainAngleSix = {
+ R.drawable.gbg_candycane_small_angle_six_1920,
+ R.drawable.gbg_candycane_small_angle_six_960,
+ R.drawable.gbg_candycane_small_angle_six_480
+ };
+ int[] caneMainAngleTwelve = {
+ R.drawable.gbg_candycane_small_angle_twelve_1920,
+ R.drawable.gbg_candycane_small_angle_twelve_960,
+ R.drawable.gbg_candycane_small_angle_twelve_480
+ };
+ int[] caneMainTinyReverseAngleSix = {
+ R.drawable.gbg_candycane_tiny_reverse_angle_six_1920,
+ R.drawable.gbg_candycane_tiny_reverse_angle_six_960,
+ R.drawable.gbg_candycane_tiny_reverse_angle_six_480
+ };
+ int[] caneMainLargeAngleSix = {
+ R.drawable.gbg_candycane_large_angle_six_1920,
+ R.drawable.gbg_candycane_large_angle_six_960,
+ R.drawable.gbg_candycane_large_angle_six_480
+ };
+ int[] caneMainMedAngleSix = {
+ R.drawable.gbg_candycane_med_angle_six_1920,
+ R.drawable.gbg_candycane_med_angle_six_960,
+ R.drawable.gbg_candycane_med_angle_six_480
+ };
+ int[] sizes = {1920, 960, 480};
+
+ final int viewWidth = getWidth();
+ int size = 0;
+ for (int i = 1; i <= sizes.length; i++) {
+ if (viewWidth <= sizes[i - 1]) {
+ size = i - 1;
+ } else {
+ break;
+ }
+ }
+
+ mGumballBlue = resizeImage(res, gumballBlue, sizes, size, viewWidth, -360f, true, 1);
+ mGumballRed = resizeImage(res, gumballRed, sizes, size, viewWidth, -360f, true, 1);
+ mGumballYellow = resizeImage(res, gumballYellow, sizes, size, viewWidth, -360f, true, 1);
+ mGumballGreen = resizeImage(res, gumballGreen, sizes, size, viewWidth, -360f, true, 1);
+ mGumballOrange = resizeImage(res, gumballOrange, sizes, size, viewWidth, -360f, true, 1);
+ mGumballPurple = resizeImage(res, gumballPurple, sizes, size, viewWidth, -360f, true, 1);
+
+ mCaneMainLong = resizeImage(res, caneMain, sizes, size, viewWidth, 180f, false, 1);
+ mCaneMainLongReverse =
+ resizeImage(res, caneMainReverse, sizes, size, viewWidth, 180f, false, 1);
+ mCaneMainMed = resizeImage(res, caneMain, sizes, size, viewWidth, 180f, false, .75f);
+ mCaneMainMedReverse =
+ resizeImage(res, caneMainReverse, sizes, size, viewWidth, 180f, false, .75f);
+
+ mCaneMainSmall = resizeImage(res, caneMain, sizes, size, viewWidth, 180f, false, .50f);
+ mCaneMainSmallReverse =
+ resizeImage(res, caneMainReverse, sizes, size, viewWidth, 180f, false, .50f);
+ mCaneMainTiny = resizeImage(res, caneMain, sizes, size, viewWidth, 180f, false, .25f);
+ mCaneMainTinyReverse =
+ resizeImage(res, caneMainReverse, sizes, size, viewWidth, 180f, false, .25f);
+
+ mCaneMainSmallAngleNine =
+ resizeImage(res, caneMainAngleNine, sizes, size, viewWidth, 180f, true, 1f);
+ mCaneMainSmallAngleSix =
+ resizeImage(res, caneMainAngleSix, sizes, size, viewWidth, 180f, true, 1f);
+ mCaneMainSmallAngleTwelve =
+ resizeImage(res, caneMainAngleTwelve, sizes, size, viewWidth, 180f, true, 1f);
+ mCaneMainReverseTinyAngleTwelve =
+ resizeImage(
+ res, caneMainTinyReverseAngleSix, sizes, size, viewWidth, 180f, true, 1f);
+ mCaneMainLargeAngleSix =
+ resizeImage(res, caneMainLargeAngleSix, sizes, size, viewWidth, 180f, true, 1f);
+ mCaneMainMedAngleSix =
+ resizeImage(res, caneMainMedAngleSix, sizes, size, viewWidth, 180f, true, 1f);
+
+ mCaneHook = resizeImage(res, caneHook, sizes, size, viewWidth, 180f, false, 1);
+ mCaneHookFlip = resizeImage(res, caneHook, sizes, size, viewWidth, 180f, true, 1);
+ mCaneHookReverse =
+ resizeImage(res, caneHookReverse, sizes, size, viewWidth, 180f, false, 1);
+ mCaneHookReverseFlip =
+ resizeImage(res, caneHookReverse, sizes, size, viewWidth, 180f, true, 1);
+ mCaneEnd = resizeImage(res, caneEnd, sizes, size, viewWidth, 180f, false, 1);
+ mCaneEndFlip = resizeImage(res, caneEnd, sizes, size, viewWidth, 180f, true, 1);
+ mCaneEndReverse = resizeImage(res, caneEndReverse, sizes, size, viewWidth, 180f, false, 1);
+ mCaneEndReverseFlip =
+ resizeImage(res, caneEndReverse, sizes, size, viewWidth, 180f, true, 1);
+ mPipeSides = resizeImage(res, pipes, sizes, size, viewWidth, 180f, true, 1);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ // Advance the countdown
+ if (mGameCountDown != null) {
+ mGameCountDown.tick();
+ }
+
+ // Load bitmaps if they haven't been initialised yet
+ if (mGumballBlue == null) {
+ loadBitmaps();
+ }
+ // reset and initialise the canvas for a fresh draw
+ canvas.drawColor(Color.TRANSPARENT);
+ canvas.translate(0, getHeight());
+ canvas.scale(1.0f, -1.0f);
+ float scale = getWidth() / 10.0f;
+ mPaint.setAntiAlias(true);
+
+ if (isInEditMode()) {
+ return;
+ }
+
+ // Iterate through all of the bodies in the game world and draw the corresponding bitmaps
+ Body body = mWorld.getWorld().getBodyList();
+ while (body != null) {
+ if (body.m_userData == null || body.m_userData.equals(PIPE_BOTTOM)) {
+ body = body.getNext();
+ continue;
+ }
+ // Skip bodies with empty fixtures or shapes
+ Fixture fixture = body.getFixtureList();
+ if (fixture == null) {
+ body = body.getNext();
+ continue;
+ }
+ Shape shape = fixture.getShape();
+ if (shape == null) {
+ body = body.getNext();
+ continue;
+ }
+
+ // Get the position.
+ Vec2 position = body.getPosition();
+
+ // Get the bitmap of this body.
+ Bitmap bitmap = null;
+ if (body.getUserData() instanceof Gumball) {
+ // For a gumball, load the correct color
+ Gumball gumball = (Gumball) body.getUserData();
+ if (gumball.mGumballColorId == GUMBALL_BLUE) {
+ bitmap = mGumballBlue;
+ } else if (gumball.mGumballColorId == GUMBALL_YELLOW) {
+ bitmap = mGumballYellow;
+ } else if (gumball.mGumballColorId == GUMBALL_RED) {
+ bitmap = mGumballRed;
+ } else if (gumball.mGumballColorId == GUMBALL_GREEN) {
+ bitmap = mGumballGreen;
+ } else if (gumball.mGumballColorId == GUMBALL_ORANGE) {
+ bitmap = mGumballOrange;
+ } else if (gumball.mGumballColorId == GUMBALL_PURPLE) {
+ bitmap = mGumballPurple;
+ }
+ } else if (body.m_userData.equals(CANE_MAIN_LONG)) {
+ bitmap = mCaneMainLong;
+ } else if (body.m_userData.equals(CANE_MAIN_LONG_REVERSE)) {
+ bitmap = mCaneMainLongReverse;
+ } else if (body.m_userData.equals(CANE_MAIN_MEDIUM)) {
+ bitmap = mCaneMainMed;
+ } else if (body.m_userData.equals(CANE_MAIN_MEDIUM_REVERSE)) {
+ bitmap = mCaneMainMedReverse;
+ } else if (body.m_userData.equals(CANE_MAIN_SMALL)) {
+ bitmap = mCaneMainSmall;
+ } else if (body.m_userData.equals(CANE_MAIN_SMALL_REVERSE)) {
+ bitmap = mCaneMainSmallReverse;
+ } else if (body.m_userData.equals(CANE_MAIN_TINY)) {
+ bitmap = mCaneMainTiny;
+ } else if (body.m_userData.equals(CANE_MAIN_TINY_REVERSE)) {
+ bitmap = mCaneMainTinyReverse;
+ } else if (body.m_userData.equals(CANE_HOOK)) {
+ bitmap = mCaneHook;
+ } else if (body.m_userData.equals(CANE_HOOK_FLIP)) {
+ bitmap = mCaneHookFlip;
+ } else if (body.m_userData.equals(CANE_HOOK_REVERSE)) {
+ bitmap = mCaneHookReverse;
+ } else if (body.m_userData.equals(CANE_HOOK_REVERSE_FLIP)) {
+ bitmap = mCaneHookReverseFlip;
+ } else if (body.m_userData.equals(CANE_END)) {
+ bitmap = mCaneEnd;
+ } else if (body.m_userData.equals(CANE_END_FLIP)) {
+ bitmap = mCaneEndFlip;
+ } else if (body.m_userData.equals(CANE_END_REVERSE)) {
+ bitmap = mCaneEndReverse;
+ } else if (body.m_userData.equals(CANE_END_REVERSE_FLIP)) {
+ bitmap = mCaneEndReverseFlip;
+ } else if (body.m_userData.equals(PIPE_SIDES)) {
+ bitmap = mPipeSides;
+ } else if (body.m_userData.equals(CANE_MAIN_SMALL_ANGLE_NINE)) {
+ bitmap = mCaneMainSmallAngleNine;
+ } else if (body.m_userData.equals(CANE_MAIN_SMALL_ANGLE_SIX)) {
+ bitmap = mCaneMainSmallAngleSix;
+ } else if (body.m_userData.equals(CANE_MAIN_SMALL_ANGLE_TWELVE)) {
+ bitmap = mCaneMainSmallAngleTwelve;
+ } else if (body.m_userData.equals(CANE_MAIN_REVERSE_TINY_ANGLE_SIX)) {
+ bitmap = mCaneMainReverseTinyAngleTwelve;
+ } else if (body.m_userData.equals(CANE_MAIN_LARGE_ANGLE_SIX)) {
+ bitmap = mCaneMainLargeAngleSix;
+ } else if (body.m_userData.equals(CANE_MAIN_MED_ANGLE_SIX)) {
+ bitmap = mCaneMainMedAngleSix;
+ }
+
+ if (shape instanceof CircleShape && bitmap != null) {
+ // Draw a gumball
+ CircleShape circleShape = (CircleShape) shape;
+ canvas.save();
+ canvas.rotate(
+ (float) (180 * body.getAngle() / Math.PI),
+ scale * position.x,
+ scale * position.y);
+ canvas.drawBitmap(
+ bitmap,
+ scale * (position.x - circleShape.m_radius),
+ scale * (position.y - circleShape.m_radius),
+ mPaint);
+ canvas.restore();
+
+ } else if (shape instanceof EdgeShape && bitmap != null) {
+ // Draw all other objects
+ final int saveCount = canvas.save();
+ canvas.rotate(
+ (float) (180 * body.getAngle() / Math.PI),
+ scale * position.x,
+ scale * position.y);
+ canvas.drawBitmap(bitmap, scale * (position.x), scale * (position.y), mPaint);
+ canvas.restoreToCount(saveCount);
+ }
+
+ // Continue drawing with the next body in the world
+ body = body.getNext();
+ }
+ }
+
+ public void setGameCountDown(TiltGameFragment.GameCountdown gameCountDown) {
+ mGameCountDown = gameCountDown;
+ }
+
+ /** Returns the index of a randomly colored gumball. */
+ public static int getRandomGumballId() {
+ int index = sRandomGenerator.nextInt(GUMBALLS.length);
+ int id = GUMBALLS[index];
+ return id;
+ }
+
+ /** Gets the correct bitmap based on screen size and rotates and flips the image. */
+ private static Bitmap resizeImage(
+ Resources res,
+ int[] resourceId,
+ int[] sizes,
+ int size,
+ int viewWidth,
+ float rotationDegrees,
+ boolean isFlipped,
+ float caneScale) {
+
+ Matrix matrix = new Matrix();
+ Bitmap bmp = BitmapFactory.decodeResource(res, resourceId[size]);
+
+ if (rotationDegrees != 361f) {
+ matrix.setRotate(rotationDegrees, bmp.getWidth() / 2, bmp.getHeight() / 2);
+ }
+ if (isFlipped) {
+ matrix.preScale(-1, 1);
+ }
+ float scale = ((float) viewWidth) / sizes[size];
+ matrix.postScale(scale, scale);
+
+ bmp =
+ Bitmap.createBitmap(
+ bmp,
+ 0,
+ 0,
+ (int) (bmp.getWidth() * caneScale),
+ bmp.getHeight(),
+ matrix,
+ true);
+
+ return bmp;
+ }
+
+ /** Sets the Box 2D physics world to draw. */
+ public void setModel(PhysicsWorld world) {
+ mWorld = world;
+ }
+
+ /** Adds a gumball for drawing. */
+ public void addGumball(Gumball gumball) {
+ gumball.mGumballColorId = getRandomGumballId();
+ mWorld.addGumball(
+ gumball.mXInitPos,
+ gumball.mYInitPos,
+ gumball,
+ GUMBALL_DENSITY,
+ GUMBALL_RADIUS,
+ GUMBALL_BOUNCE,
+ GUMBALL_FRICTION,
+ BodyType.DYNAMIC);
+ }
+}
diff --git a/gumball/src/main/res/drawable-hdpi/gbg_bg_main_inner.webp b/gumball/src/main/res/drawable-hdpi/gbg_bg_main_inner.webp
new file mode 100644
index 000000000..f2ff12e32
Binary files /dev/null and b/gumball/src/main/res/drawable-hdpi/gbg_bg_main_inner.webp differ
diff --git a/gumball/src/main/res/drawable-hdpi/gbg_bg_main_outer_bottom.9.png b/gumball/src/main/res/drawable-hdpi/gbg_bg_main_outer_bottom.9.png
new file mode 100644
index 000000000..aeb5dfd33
Binary files /dev/null and b/gumball/src/main/res/drawable-hdpi/gbg_bg_main_outer_bottom.9.png differ
diff --git a/gumball/src/main/res/drawable-hdpi/gbg_bg_main_outer_top.9.png b/gumball/src/main/res/drawable-hdpi/gbg_bg_main_outer_top.9.png
new file mode 100644
index 000000000..8ac4c3d48
Binary files /dev/null and b/gumball/src/main/res/drawable-hdpi/gbg_bg_main_outer_top.9.png differ
diff --git a/gumball/src/main/res/drawable-hdpi/gbg_gumball_indicator_collected.webp b/gumball/src/main/res/drawable-hdpi/gbg_gumball_indicator_collected.webp
new file mode 100644
index 000000000..baea8af95
Binary files /dev/null and b/gumball/src/main/res/drawable-hdpi/gbg_gumball_indicator_collected.webp differ
diff --git a/gumball/src/main/res/drawable-hdpi/gbg_gumball_indicator_collected_disabled.webp b/gumball/src/main/res/drawable-hdpi/gbg_gumball_indicator_collected_disabled.webp
new file mode 100644
index 000000000..8ba03fb78
Binary files /dev/null and b/gumball/src/main/res/drawable-hdpi/gbg_gumball_indicator_collected_disabled.webp differ
diff --git a/gumball/src/main/res/drawable-hdpi/gbg_gumball_indicator_pending.webp b/gumball/src/main/res/drawable-hdpi/gbg_gumball_indicator_pending.webp
new file mode 100644
index 000000000..f61c7a3a4
Binary files /dev/null and b/gumball/src/main/res/drawable-hdpi/gbg_gumball_indicator_pending.webp differ
diff --git a/gumball/src/main/res/drawable-hdpi/gbg_gumball_outlet.9.png b/gumball/src/main/res/drawable-hdpi/gbg_gumball_outlet.9.png
new file mode 100644
index 000000000..fcb8a7fff
Binary files /dev/null and b/gumball/src/main/res/drawable-hdpi/gbg_gumball_outlet.9.png differ
diff --git a/gumball/src/main/res/drawable-mdpi/gbg_bg_main_inner.webp b/gumball/src/main/res/drawable-mdpi/gbg_bg_main_inner.webp
new file mode 100644
index 000000000..9f37d4ba1
Binary files /dev/null and b/gumball/src/main/res/drawable-mdpi/gbg_bg_main_inner.webp differ
diff --git a/gumball/src/main/res/drawable-mdpi/gbg_bg_main_outer_bottom.webp b/gumball/src/main/res/drawable-mdpi/gbg_bg_main_outer_bottom.webp
new file mode 100644
index 000000000..84f33bd0d
Binary files /dev/null and b/gumball/src/main/res/drawable-mdpi/gbg_bg_main_outer_bottom.webp differ
diff --git a/gumball/src/main/res/drawable-mdpi/gbg_bg_main_outer_top.webp b/gumball/src/main/res/drawable-mdpi/gbg_bg_main_outer_top.webp
new file mode 100644
index 000000000..f0f7edd47
Binary files /dev/null and b/gumball/src/main/res/drawable-mdpi/gbg_bg_main_outer_top.webp differ
diff --git a/gumball/src/main/res/drawable-mdpi/gbg_gumball_indicator_collected.webp b/gumball/src/main/res/drawable-mdpi/gbg_gumball_indicator_collected.webp
new file mode 100644
index 000000000..b4bca6090
Binary files /dev/null and b/gumball/src/main/res/drawable-mdpi/gbg_gumball_indicator_collected.webp differ
diff --git a/gumball/src/main/res/drawable-mdpi/gbg_gumball_indicator_collected_disabled.webp b/gumball/src/main/res/drawable-mdpi/gbg_gumball_indicator_collected_disabled.webp
new file mode 100644
index 000000000..2deeec63b
Binary files /dev/null and b/gumball/src/main/res/drawable-mdpi/gbg_gumball_indicator_collected_disabled.webp differ
diff --git a/gumball/src/main/res/drawable-mdpi/gbg_gumball_indicator_pending.webp b/gumball/src/main/res/drawable-mdpi/gbg_gumball_indicator_pending.webp
new file mode 100644
index 000000000..a481de006
Binary files /dev/null and b/gumball/src/main/res/drawable-mdpi/gbg_gumball_indicator_pending.webp differ
diff --git a/gumball/src/main/res/drawable-mdpi/gbg_gumball_outlet.9.png b/gumball/src/main/res/drawable-mdpi/gbg_gumball_outlet.9.png
new file mode 100644
index 000000000..091d4022f
Binary files /dev/null and b/gumball/src/main/res/drawable-mdpi/gbg_gumball_outlet.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_bg_gumball_indicatorp.9.png b/gumball/src/main/res/drawable-nodpi/gbg_bg_gumball_indicatorp.9.png
new file mode 100644
index 000000000..23eb77ddf
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_bg_gumball_indicatorp.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_1920.9.png
new file mode 100644
index 000000000..bd8783cec
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_480.9.png
new file mode 100644
index 000000000..920a8ee04
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_800.9.png
new file mode 100644
index 000000000..9f91acad3
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_reverse_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_reverse_1920.9.png
new file mode 100644
index 000000000..989132caa
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_reverse_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_reverse_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_reverse_480.9.png
new file mode 100644
index 000000000..a5e49c7d2
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_reverse_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_reverse_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_reverse_800.9.png
new file mode 100644
index 000000000..bae58266a
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_end_reverse_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_1920.9.png
new file mode 100644
index 000000000..14666d527
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_480.9.png
new file mode 100644
index 000000000..802109e54
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_800.9.png
new file mode 100644
index 000000000..45b3f8374
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_reverse_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_reverse_1920.9.png
new file mode 100644
index 000000000..94b9a2c8b
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_reverse_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_reverse_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_reverse_480.9.png
new file mode 100644
index 000000000..99825a240
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_reverse_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_reverse_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_reverse_800.9.png
new file mode 100644
index 000000000..c43227f20
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_hook_reverse_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_large_angle_six_1920.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_large_angle_six_1920.webp
new file mode 100644
index 000000000..01891833e
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_large_angle_six_1920.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_large_angle_six_480.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_large_angle_six_480.webp
new file mode 100644
index 000000000..af55d0adf
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_large_angle_six_480.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_large_angle_six_960.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_large_angle_six_960.webp
new file mode 100644
index 000000000..0ce76b482
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_large_angle_six_960.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_1920.9.png
new file mode 100644
index 000000000..2032f05e9
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_480.9.png
new file mode 100644
index 000000000..118fd7f22
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_800.9.png
new file mode 100644
index 000000000..a81c5e31c
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_angle_nine_1920.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_angle_nine_1920.webp
new file mode 100644
index 000000000..2665cf76d
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_angle_nine_1920.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_angle_nine_480.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_angle_nine_480.webp
new file mode 100644
index 000000000..8409b1e95
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_angle_nine_480.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_angle_nine_960.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_angle_nine_960.webp
new file mode 100644
index 000000000..65989f949
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_angle_nine_960.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_reverse_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_reverse_1920.9.png
new file mode 100644
index 000000000..b1abfa100
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_reverse_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_reverse_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_reverse_480.9.png
new file mode 100644
index 000000000..52c661d3e
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_reverse_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_reverse_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_reverse_800.9.png
new file mode 100644
index 000000000..170d22b0a
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_main_reverse_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_med_angle_six_1920.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_med_angle_six_1920.webp
new file mode 100644
index 000000000..d2df25075
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_med_angle_six_1920.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_med_angle_six_480.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_med_angle_six_480.webp
new file mode 100644
index 000000000..41e646292
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_med_angle_six_480.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_med_angle_six_960.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_med_angle_six_960.webp
new file mode 100644
index 000000000..b37738954
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_med_angle_six_960.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_six_1920.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_six_1920.webp
new file mode 100644
index 000000000..3cc8f2e24
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_six_1920.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_six_480.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_six_480.webp
new file mode 100644
index 000000000..d010e646e
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_six_480.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_six_960.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_six_960.webp
new file mode 100644
index 000000000..4a46b8611
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_six_960.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_twelve_1920.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_twelve_1920.webp
new file mode 100644
index 000000000..4e94c7378
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_twelve_1920.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_twelve_480.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_twelve_480.webp
new file mode 100644
index 000000000..06ae70c0c
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_twelve_480.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_twelve_960.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_twelve_960.webp
new file mode 100644
index 000000000..b060de01b
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_small_angle_twelve_960.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_tiny_reverse_angle_six_1920.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_tiny_reverse_angle_six_1920.webp
new file mode 100644
index 000000000..e1102a712
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_tiny_reverse_angle_six_1920.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_tiny_reverse_angle_six_480.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_tiny_reverse_angle_six_480.webp
new file mode 100644
index 000000000..2e7bbb130
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_tiny_reverse_angle_six_480.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_candycane_tiny_reverse_angle_six_960.webp b/gumball/src/main/res/drawable-nodpi/gbg_candycane_tiny_reverse_angle_six_960.webp
new file mode 100644
index 000000000..94f4e92eb
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_candycane_tiny_reverse_angle_six_960.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_blue_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_blue_1920.9.png
new file mode 100644
index 000000000..517d915d0
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_blue_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_blue_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_blue_480.9.png
new file mode 100644
index 000000000..0e5d0aa6a
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_blue_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_blue_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_blue_800.9.png
new file mode 100644
index 000000000..e697afd6b
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_blue_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_funnel_1920.webp b/gumball/src/main/res/drawable-nodpi/gbg_gumball_funnel_1920.webp
new file mode 100644
index 000000000..e658c7f03
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_funnel_1920.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_funnel_480.webp b/gumball/src/main/res/drawable-nodpi/gbg_gumball_funnel_480.webp
new file mode 100644
index 000000000..b29f3a2e2
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_funnel_480.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_funnel_800.webp b/gumball/src/main/res/drawable-nodpi/gbg_gumball_funnel_800.webp
new file mode 100644
index 000000000..7bae780a6
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_funnel_800.webp differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_green_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_green_1920.9.png
new file mode 100644
index 000000000..785e80b7d
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_green_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_green_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_green_480.9.png
new file mode 100644
index 000000000..0ea8fc465
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_green_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_green_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_green_800.9.png
new file mode 100644
index 000000000..237375fff
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_green_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_orange_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_orange_1920.9.png
new file mode 100644
index 000000000..db2fbeaee
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_orange_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_orange_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_orange_480.9.png
new file mode 100644
index 000000000..d565fa99a
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_orange_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_orange_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_orange_800.9.png
new file mode 100644
index 000000000..6989cc091
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_orange_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_purple_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_purple_1920.9.png
new file mode 100644
index 000000000..d8003ac8c
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_purple_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_purple_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_purple_480.9.png
new file mode 100644
index 000000000..68389d2fd
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_purple_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_purple_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_purple_800.9.png
new file mode 100644
index 000000000..d4ae2bd04
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_purple_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_red_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_red_1920.9.png
new file mode 100644
index 000000000..1da1563af
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_red_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_red_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_red_480.9.png
new file mode 100644
index 000000000..7528483b2
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_red_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_red_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_red_800.9.png
new file mode 100644
index 000000000..2e63fb626
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_red_800.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_yellow_1920.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_yellow_1920.9.png
new file mode 100644
index 000000000..f91252d44
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_yellow_1920.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_yellow_480.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_yellow_480.9.png
new file mode 100644
index 000000000..456f6b25f
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_yellow_480.9.png differ
diff --git a/gumball/src/main/res/drawable-nodpi/gbg_gumball_yellow_800.9.png b/gumball/src/main/res/drawable-nodpi/gbg_gumball_yellow_800.9.png
new file mode 100644
index 000000000..45eda98f2
Binary files /dev/null and b/gumball/src/main/res/drawable-nodpi/gbg_gumball_yellow_800.9.png differ
diff --git a/gumball/src/main/res/drawable-xhdpi/gbg_bg_main_inner.webp b/gumball/src/main/res/drawable-xhdpi/gbg_bg_main_inner.webp
new file mode 100644
index 000000000..d6ea96604
Binary files /dev/null and b/gumball/src/main/res/drawable-xhdpi/gbg_bg_main_inner.webp differ
diff --git a/gumball/src/main/res/drawable-xhdpi/gbg_bg_main_outer_bottom.9.png b/gumball/src/main/res/drawable-xhdpi/gbg_bg_main_outer_bottom.9.png
new file mode 100644
index 000000000..38e98e42a
Binary files /dev/null and b/gumball/src/main/res/drawable-xhdpi/gbg_bg_main_outer_bottom.9.png differ
diff --git a/gumball/src/main/res/drawable-xhdpi/gbg_bg_main_outer_top.9.png b/gumball/src/main/res/drawable-xhdpi/gbg_bg_main_outer_top.9.png
new file mode 100644
index 000000000..9fc7186f0
Binary files /dev/null and b/gumball/src/main/res/drawable-xhdpi/gbg_bg_main_outer_top.9.png differ
diff --git a/gumball/src/main/res/drawable-xhdpi/gbg_gumball_indicator_collected.webp b/gumball/src/main/res/drawable-xhdpi/gbg_gumball_indicator_collected.webp
new file mode 100644
index 000000000..00e7d1855
Binary files /dev/null and b/gumball/src/main/res/drawable-xhdpi/gbg_gumball_indicator_collected.webp differ
diff --git a/gumball/src/main/res/drawable-xhdpi/gbg_gumball_indicator_collected_disabled.webp b/gumball/src/main/res/drawable-xhdpi/gbg_gumball_indicator_collected_disabled.webp
new file mode 100644
index 000000000..1d031d67f
Binary files /dev/null and b/gumball/src/main/res/drawable-xhdpi/gbg_gumball_indicator_collected_disabled.webp differ
diff --git a/gumball/src/main/res/drawable-xhdpi/gbg_gumball_indicator_pending.webp b/gumball/src/main/res/drawable-xhdpi/gbg_gumball_indicator_pending.webp
new file mode 100644
index 000000000..e51a90079
Binary files /dev/null and b/gumball/src/main/res/drawable-xhdpi/gbg_gumball_indicator_pending.webp differ
diff --git a/gumball/src/main/res/drawable-xhdpi/gbg_gumball_outlet.9.png b/gumball/src/main/res/drawable-xhdpi/gbg_gumball_outlet.9.png
new file mode 100644
index 000000000..168782801
Binary files /dev/null and b/gumball/src/main/res/drawable-xhdpi/gbg_gumball_outlet.9.png differ
diff --git a/gumball/src/main/res/drawable-xxhdpi/gbg_bg_main_inner.webp b/gumball/src/main/res/drawable-xxhdpi/gbg_bg_main_inner.webp
new file mode 100644
index 000000000..0fd356921
Binary files /dev/null and b/gumball/src/main/res/drawable-xxhdpi/gbg_bg_main_inner.webp differ
diff --git a/gumball/src/main/res/drawable-xxhdpi/gbg_bg_main_outer_top.9.png b/gumball/src/main/res/drawable-xxhdpi/gbg_bg_main_outer_top.9.png
new file mode 100644
index 000000000..2b9368d23
Binary files /dev/null and b/gumball/src/main/res/drawable-xxhdpi/gbg_bg_main_outer_top.9.png differ
diff --git a/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_indicator_collected.webp b/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_indicator_collected.webp
new file mode 100644
index 000000000..a67112d75
Binary files /dev/null and b/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_indicator_collected.webp differ
diff --git a/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_indicator_collected_disabled.webp b/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_indicator_collected_disabled.webp
new file mode 100644
index 000000000..fca1fa60b
Binary files /dev/null and b/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_indicator_collected_disabled.webp differ
diff --git a/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_indicator_pending.webp b/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_indicator_pending.webp
new file mode 100644
index 000000000..df98e690d
Binary files /dev/null and b/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_indicator_pending.webp differ
diff --git a/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_outlet.9.png b/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_outlet.9.png
new file mode 100644
index 000000000..680deb856
Binary files /dev/null and b/gumball/src/main/res/drawable-xxhdpi/gbg_gumball_outlet.9.png differ
diff --git a/gumball/src/main/res/layout/activity_gumball.xml b/gumball/src/main/res/layout/activity_gumball.xml
new file mode 100644
index 000000000..768ee97a8
--- /dev/null
+++ b/gumball/src/main/res/layout/activity_gumball.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/gumball/src/main/res/layout/fragment_gumball.xml b/gumball/src/main/res/layout/fragment_gumball.xml
new file mode 100644
index 000000000..304ed68ee
--- /dev/null
+++ b/gumball/src/main/res/layout/fragment_gumball.xml
@@ -0,0 +1,286 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level1.json b/gumball/src/main/res/raw-sw600dp/level1.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level1.json
rename to gumball/src/main/res/raw-sw600dp/level1.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level10.json b/gumball/src/main/res/raw-sw600dp/level10.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level10.json
rename to gumball/src/main/res/raw-sw600dp/level10.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level11.json b/gumball/src/main/res/raw-sw600dp/level11.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level11.json
rename to gumball/src/main/res/raw-sw600dp/level11.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level12.json b/gumball/src/main/res/raw-sw600dp/level12.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level12.json
rename to gumball/src/main/res/raw-sw600dp/level12.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level13.json b/gumball/src/main/res/raw-sw600dp/level13.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level13.json
rename to gumball/src/main/res/raw-sw600dp/level13.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level2.json b/gumball/src/main/res/raw-sw600dp/level2.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level2.json
rename to gumball/src/main/res/raw-sw600dp/level2.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level3.json b/gumball/src/main/res/raw-sw600dp/level3.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level3.json
rename to gumball/src/main/res/raw-sw600dp/level3.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level4.json b/gumball/src/main/res/raw-sw600dp/level4.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level4.json
rename to gumball/src/main/res/raw-sw600dp/level4.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level5.json b/gumball/src/main/res/raw-sw600dp/level5.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level5.json
rename to gumball/src/main/res/raw-sw600dp/level5.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level6.json b/gumball/src/main/res/raw-sw600dp/level6.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level6.json
rename to gumball/src/main/res/raw-sw600dp/level6.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level7.json b/gumball/src/main/res/raw-sw600dp/level7.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level7.json
rename to gumball/src/main/res/raw-sw600dp/level7.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level8.json b/gumball/src/main/res/raw-sw600dp/level8.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level8.json
rename to gumball/src/main/res/raw-sw600dp/level8.json
diff --git a/santa-tracker/src/main/res/raw-sw600dp/level9.json b/gumball/src/main/res/raw-sw600dp/level9.json
similarity index 100%
rename from santa-tracker/src/main/res/raw-sw600dp/level9.json
rename to gumball/src/main/res/raw-sw600dp/level9.json
diff --git a/gumball/src/main/res/raw/gbg_ball_bounce_1.m4a b/gumball/src/main/res/raw/gbg_ball_bounce_1.m4a
new file mode 100644
index 000000000..007aada74
Binary files /dev/null and b/gumball/src/main/res/raw/gbg_ball_bounce_1.m4a differ
diff --git a/gumball/src/main/res/raw/gbg_ball_bounce_2.m4a b/gumball/src/main/res/raw/gbg_ball_bounce_2.m4a
new file mode 100644
index 000000000..b6ccf87fe
Binary files /dev/null and b/gumball/src/main/res/raw/gbg_ball_bounce_2.m4a differ
diff --git a/gumball/src/main/res/raw/gbg_ball_bounce_3.m4a b/gumball/src/main/res/raw/gbg_ball_bounce_3.m4a
new file mode 100644
index 000000000..1d3e84333
Binary files /dev/null and b/gumball/src/main/res/raw/gbg_ball_bounce_3.m4a differ
diff --git a/gumball/src/main/res/raw/gbg_ball_fall_out.m4a b/gumball/src/main/res/raw/gbg_ball_fall_out.m4a
new file mode 100644
index 000000000..cdfb7c1e0
Binary files /dev/null and b/gumball/src/main/res/raw/gbg_ball_fall_out.m4a differ
diff --git a/gumball/src/main/res/raw/gbg_ball_into_machine.m4a b/gumball/src/main/res/raw/gbg_ball_into_machine.m4a
new file mode 100644
index 000000000..745d9207e
Binary files /dev/null and b/gumball/src/main/res/raw/gbg_ball_into_machine.m4a differ
diff --git a/gumball/src/main/res/raw/gbg_new_ball_bounce_drop.m4a b/gumball/src/main/res/raw/gbg_new_ball_bounce_drop.m4a
new file mode 100644
index 000000000..10569b7ab
Binary files /dev/null and b/gumball/src/main/res/raw/gbg_new_ball_bounce_drop.m4a differ
diff --git a/santa-tracker/src/main/res/raw/level1.json b/gumball/src/main/res/raw/level1.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level1.json
rename to gumball/src/main/res/raw/level1.json
diff --git a/santa-tracker/src/main/res/raw/level10.json b/gumball/src/main/res/raw/level10.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level10.json
rename to gumball/src/main/res/raw/level10.json
diff --git a/santa-tracker/src/main/res/raw/level11.json b/gumball/src/main/res/raw/level11.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level11.json
rename to gumball/src/main/res/raw/level11.json
diff --git a/santa-tracker/src/main/res/raw/level12.json b/gumball/src/main/res/raw/level12.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level12.json
rename to gumball/src/main/res/raw/level12.json
diff --git a/santa-tracker/src/main/res/raw/level13.json b/gumball/src/main/res/raw/level13.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level13.json
rename to gumball/src/main/res/raw/level13.json
diff --git a/santa-tracker/src/main/res/raw/level2.json b/gumball/src/main/res/raw/level2.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level2.json
rename to gumball/src/main/res/raw/level2.json
diff --git a/santa-tracker/src/main/res/raw/level3.json b/gumball/src/main/res/raw/level3.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level3.json
rename to gumball/src/main/res/raw/level3.json
diff --git a/santa-tracker/src/main/res/raw/level4.json b/gumball/src/main/res/raw/level4.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level4.json
rename to gumball/src/main/res/raw/level4.json
diff --git a/santa-tracker/src/main/res/raw/level5.json b/gumball/src/main/res/raw/level5.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level5.json
rename to gumball/src/main/res/raw/level5.json
diff --git a/santa-tracker/src/main/res/raw/level6.json b/gumball/src/main/res/raw/level6.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level6.json
rename to gumball/src/main/res/raw/level6.json
diff --git a/santa-tracker/src/main/res/raw/level7.json b/gumball/src/main/res/raw/level7.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level7.json
rename to gumball/src/main/res/raw/level7.json
diff --git a/santa-tracker/src/main/res/raw/level8.json b/gumball/src/main/res/raw/level8.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level8.json
rename to gumball/src/main/res/raw/level8.json
diff --git a/santa-tracker/src/main/res/raw/level9.json b/gumball/src/main/res/raw/level9.json
similarity index 100%
rename from santa-tracker/src/main/res/raw/level9.json
rename to gumball/src/main/res/raw/level9.json
diff --git a/gumball/src/main/res/values-af/strings.xml b/gumball/src/main/res/values-af/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-af/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-ar-rXB/strings.xml b/gumball/src/main/res/values-ar-rXB/strings.xml
new file mode 100644
index 000000000..d232ee873
--- /dev/null
+++ b/gumball/src/main/res/values-ar-rXB/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-bg/strings.xml b/gumball/src/main/res/values-bg/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-bg/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-ca/strings.xml b/gumball/src/main/res/values-ca/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-ca/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-da/strings.xml b/gumball/src/main/res/values-da/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-da/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-de-rAT/strings.xml b/gumball/src/main/res/values-de-rAT/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-de-rAT/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-de-rCH/strings.xml b/gumball/src/main/res/values-de-rCH/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-de-rCH/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-de/strings.xml b/gumball/src/main/res/values-de/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-de/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-en-rGB/strings.xml b/gumball/src/main/res/values-en-rGB/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-en-rGB/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-en-rIE/strings.xml b/gumball/src/main/res/values-en-rIE/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-en-rIE/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-en-rIN/strings.xml b/gumball/src/main/res/values-en-rIN/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-en-rIN/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-en-rSG/strings.xml b/gumball/src/main/res/values-en-rSG/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-en-rSG/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-en-rXA/strings.xml b/gumball/src/main/res/values-en-rXA/strings.xml
new file mode 100644
index 000000000..a59153e39
--- /dev/null
+++ b/gumball/src/main/res/values-en-rXA/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ [Ĝûmбåļļ one]
+
diff --git a/gumball/src/main/res/values-en-rXC/strings.xml b/gumball/src/main/res/values-en-rXC/strings.xml
new file mode 100644
index 000000000..d8297c59b
--- /dev/null
+++ b/gumball/src/main/res/values-en-rXC/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-en-rZA/strings.xml b/gumball/src/main/res/values-en-rZA/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-en-rZA/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rAR/strings.xml b/gumball/src/main/res/values-es-rAR/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rAR/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rBO/strings.xml b/gumball/src/main/res/values-es-rBO/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rBO/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rCL/strings.xml b/gumball/src/main/res/values-es-rCL/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rCL/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rCO/strings.xml b/gumball/src/main/res/values-es-rCO/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rCO/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rCR/strings.xml b/gumball/src/main/res/values-es-rCR/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rCR/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rDO/strings.xml b/gumball/src/main/res/values-es-rDO/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rDO/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rEC/strings.xml b/gumball/src/main/res/values-es-rEC/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rEC/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rGT/strings.xml b/gumball/src/main/res/values-es-rGT/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rGT/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rHN/strings.xml b/gumball/src/main/res/values-es-rHN/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rHN/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rMX/strings.xml b/gumball/src/main/res/values-es-rMX/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rMX/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rNI/strings.xml b/gumball/src/main/res/values-es-rNI/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rNI/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rPA/strings.xml b/gumball/src/main/res/values-es-rPA/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rPA/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rPE/strings.xml b/gumball/src/main/res/values-es-rPE/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rPE/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rPR/strings.xml b/gumball/src/main/res/values-es-rPR/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rPR/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rPY/strings.xml b/gumball/src/main/res/values-es-rPY/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rPY/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rSV/strings.xml b/gumball/src/main/res/values-es-rSV/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rSV/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rUS/strings.xml b/gumball/src/main/res/values-es-rUS/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rUS/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rUY/strings.xml b/gumball/src/main/res/values-es-rUY/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rUY/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es-rVE/strings.xml b/gumball/src/main/res/values-es-rVE/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-es-rVE/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-es/strings.xml b/gumball/src/main/res/values-es/strings.xml
new file mode 100644
index 000000000..58c3a50fb
--- /dev/null
+++ b/gumball/src/main/res/values-es/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Piruletas
+
diff --git a/gumball/src/main/res/values-et/strings.xml b/gumball/src/main/res/values-et/strings.xml
new file mode 100644
index 000000000..5724ff99a
--- /dev/null
+++ b/gumball/src/main/res/values-et/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Nätsukomm
+
diff --git a/gumball/src/main/res/values-fi/strings.xml b/gumball/src/main/res/values-fi/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-fi/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-fil/strings.xml b/gumball/src/main/res/values-fil/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-fil/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-fr-rCA/strings.xml b/gumball/src/main/res/values-fr-rCA/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-fr-rCA/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-fr-rCH/strings.xml b/gumball/src/main/res/values-fr-rCH/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-fr-rCH/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-fr/strings.xml b/gumball/src/main/res/values-fr/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-fr/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-gsw/strings.xml b/gumball/src/main/res/values-gsw/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-gsw/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-hr/strings.xml b/gumball/src/main/res/values-hr/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-hr/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-id/strings.xml b/gumball/src/main/res/values-id/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-id/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-in/strings.xml b/gumball/src/main/res/values-in/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-in/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-it/strings.xml b/gumball/src/main/res/values-it/strings.xml
new file mode 100644
index 000000000..851344ee6
--- /dev/null
+++ b/gumball/src/main/res/values-it/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Palline di zucchero
+
diff --git a/gumball/src/main/res/values-ja/strings.xml b/gumball/src/main/res/values-ja/strings.xml
new file mode 100644
index 000000000..f9e783b50
--- /dev/null
+++ b/gumball/src/main/res/values-ja/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ ガムボール
+
diff --git a/gumball/src/main/res/values-ko/strings.xml b/gumball/src/main/res/values-ko/strings.xml
new file mode 100644
index 000000000..ce1c45765
--- /dev/null
+++ b/gumball/src/main/res/values-ko/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ 풍선껌
+
diff --git a/gumball/src/main/res/values-ln/strings.xml b/gumball/src/main/res/values-ln/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-ln/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-lt/strings.xml b/gumball/src/main/res/values-lt/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-lt/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-lv/strings.xml b/gumball/src/main/res/values-lv/strings.xml
new file mode 100644
index 000000000..3f64e96e6
--- /dev/null
+++ b/gumball/src/main/res/values-lv/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Spēle Gumball
+
diff --git a/gumball/src/main/res/values-ml/strings.xml b/gumball/src/main/res/values-ml/strings.xml
new file mode 100644
index 000000000..9eac4ea03
--- /dev/null
+++ b/gumball/src/main/res/values-ml/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ ഗംബോൾ
+
diff --git a/gumball/src/main/res/values-mo/strings.xml b/gumball/src/main/res/values-mo/strings.xml
new file mode 100644
index 000000000..38fe689bc
--- /dev/null
+++ b/gumball/src/main/res/values-mo/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Acadele buclucașe
+
diff --git a/gumball/src/main/res/values-nb/strings.xml b/gumball/src/main/res/values-nb/strings.xml
new file mode 100644
index 000000000..47f07bd28
--- /dev/null
+++ b/gumball/src/main/res/values-nb/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Rulledrops
+
diff --git a/gumball/src/main/res/values-no/strings.xml b/gumball/src/main/res/values-no/strings.xml
new file mode 100644
index 000000000..47f07bd28
--- /dev/null
+++ b/gumball/src/main/res/values-no/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Rulledrops
+
diff --git a/gumball/src/main/res/values-pl/strings.xml b/gumball/src/main/res/values-pl/strings.xml
new file mode 100644
index 000000000..20f56b3cc
--- /dev/null
+++ b/gumball/src/main/res/values-pl/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Guma w kulkach
+
diff --git a/gumball/src/main/res/values-pt-rBR/strings.xml b/gumball/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 000000000..e501bcf6e
--- /dev/null
+++ b/gumball/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Ladeira dos chicletes
+
diff --git a/gumball/src/main/res/values-pt-rPT/strings.xml b/gumball/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-pt-rPT/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-pt/strings.xml b/gumball/src/main/res/values-pt/strings.xml
new file mode 100644
index 000000000..e501bcf6e
--- /dev/null
+++ b/gumball/src/main/res/values-pt/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Ladeira dos chicletes
+
diff --git a/gumball/src/main/res/values-ro/strings.xml b/gumball/src/main/res/values-ro/strings.xml
new file mode 100644
index 000000000..38fe689bc
--- /dev/null
+++ b/gumball/src/main/res/values-ro/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Acadele buclucașe
+
diff --git a/gumball/src/main/res/values-ru/strings.xml b/gumball/src/main/res/values-ru/strings.xml
new file mode 100644
index 000000000..e53d985ba
--- /dev/null
+++ b/gumball/src/main/res/values-ru/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Жвачка
+
diff --git a/gumball/src/main/res/values-sl/strings.xml b/gumball/src/main/res/values-sl/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-sl/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-sv/strings.xml b/gumball/src/main/res/values-sv/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-sv/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-ta/strings.xml b/gumball/src/main/res/values-ta/strings.xml
new file mode 100644
index 000000000..589812fc0
--- /dev/null
+++ b/gumball/src/main/res/values-ta/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ கம்பால்
+
diff --git a/gumball/src/main/res/values-th/strings.xml b/gumball/src/main/res/values-th/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-th/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-tl/strings.xml b/gumball/src/main/res/values-tl/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-tl/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-uk/strings.xml b/gumball/src/main/res/values-uk/strings.xml
new file mode 100644
index 000000000..b953f5bf2
--- /dev/null
+++ b/gumball/src/main/res/values-uk/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Жувальна гумка
+
diff --git a/gumball/src/main/res/values-vi/strings.xml b/gumball/src/main/res/values-vi/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-vi/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-zh-rCN/strings.xml b/gumball/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values-zh-rHK/strings.xml b/gumball/src/main/res/values-zh-rHK/strings.xml
new file mode 100644
index 000000000..707c284e3
--- /dev/null
+++ b/gumball/src/main/res/values-zh-rHK/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ 口香糖
+
diff --git a/gumball/src/main/res/values-zh-rTW/strings.xml b/gumball/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 000000000..d8d4a11d1
--- /dev/null
+++ b/gumball/src/main/res/values-zh-rTW/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ 口香糖球
+
diff --git a/gumball/src/main/res/values-zh/strings.xml b/gumball/src/main/res/values-zh/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values-zh/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values/colors.xml b/gumball/src/main/res/values/colors.xml
new file mode 100644
index 000000000..56165f71c
--- /dev/null
+++ b/gumball/src/main/res/values/colors.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/gumball/src/main/res/values/strings.xml b/gumball/src/main/res/values/strings.xml
new file mode 100644
index 000000000..8bb704db6
--- /dev/null
+++ b/gumball/src/main/res/values/strings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Gumball
+
diff --git a/gumball/src/main/res/values/styles.xml b/gumball/src/main/res/values/styles.xml
new file mode 100644
index 000000000..6c65774ee
--- /dev/null
+++ b/gumball/src/main/res/values/styles.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/jetpack/build.gradle b/jetpack/build.gradle
new file mode 100644
index 000000000..bb459cb2d
--- /dev/null
+++ b/jetpack/build.gradle
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
+apply plugin: 'com.android.dynamic-feature'
+apply plugin: 'kotlin-android'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.tools
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
+ }
+}
+
+dependencies {
+ // Using api dependency to use some dependencies defined in santa-tracker. e.g. core-ktx
+ api project(':santa-tracker')
+}
diff --git a/jetpack/src/dogfood/res/values/game_ids.xml b/jetpack/src/dogfood/res/values/game_ids.xml
new file mode 100644
index 000000000..4006364f3
--- /dev/null
+++ b/jetpack/src/dogfood/res/values/game_ids.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ 80719462666
+ CgkIioKF2qwCEAIQEw
+ CgkIioKF2qwCEAIQFA
+
diff --git a/jetpack/src/dogfood/res/values/game_ids_jetpack.xml b/jetpack/src/dogfood/res/values/game_ids_jetpack.xml
new file mode 100644
index 000000000..25085dcc3
--- /dev/null
+++ b/jetpack/src/dogfood/res/values/game_ids_jetpack.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+CgkIioKF2qwCEAIQAg
+CgkIioKF2qwCEAIQAw
+CgkIioKF2qwCEAIQBA
+CgkIioKF2qwCEAIQBg
+CgkIioKF2qwCEAIQBw
+CgkIioKF2qwCEAIQCA
+CgkIioKF2qwCEAIQCQ
+CgkIioKF2qwCEAIQCg
+CgkIioKF2qwCEAIQCw
+CgkIioKF2qwCEAIQDA
+CgkIioKF2qwCEAIQDQ
+CgkIioKF2qwCEAIQDg
+CgkIioKF2qwCEAIQDw
+CgkIioKF2qwCEAIQEA
+CgkIioKF2qwCEAIQEQ
+CgkIioKF2qwCEAIQEg
+
+
diff --git a/jetpack/src/main/AndroidManifest.xml b/jetpack/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..de1ffc56f
--- /dev/null
+++ b/jetpack/src/main/AndroidManifest.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/BaseScene.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/BaseScene.kt
new file mode 100644
index 000000000..0c48b2e52
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/BaseScene.kt
@@ -0,0 +1,667 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+import android.app.UiModeManager
+import android.content.Context
+import android.content.res.Configuration
+import com.google.android.apps.playgames.simpleengine.Renderer
+import com.google.android.apps.playgames.simpleengine.Scene
+import com.google.android.apps.playgames.simpleengine.SceneManager
+import com.google.android.apps.playgames.simpleengine.SmoothValue
+import com.google.android.apps.playgames.simpleengine.game.GameObject
+import com.google.android.apps.playgames.simpleengine.game.World
+import com.google.android.apps.playgames.simpleengine.ui.Button
+import com.google.android.apps.playgames.simpleengine.ui.SimpleUI
+import com.google.android.apps.playgames.simpleengine.ui.Widget
+import com.google.android.apps.santatracker.util.ImmersiveModeHelper
+import java.util.Random
+
+abstract class BaseScene : Scene(), Widget.WidgetTriggerListener, GameEndedListener {
+
+ // digit object factory (to display score, etc)
+ protected lateinit var digitFactory: DigitObjectFactory
+ protected lateinit var objectFactory: GameObjectFactory
+
+ protected lateinit var world: World
+ protected lateinit var renderer: Renderer
+ protected val random = Random()
+
+ // score bar object
+ private var scoreBarObj: GameObject? = null
+
+ // score bar label object
+ private var scoreBarLabelObj: GameObject? = null
+
+ // score digit objects
+ private var scoreDigitObj = arrayOfNulls(GameConfig.ScoreDisplay.DIGIT_COUNT)
+
+ // timer digit objects
+ private var timeDigitObj = arrayOfNulls(GameConfig.TimeDisplay.DIGIT_COUNT)
+
+ // countdown objects
+ var countdownDigitObj: GameObject? = null
+
+ // player's current score
+ override var score = 0
+ protected set
+ protected var displayedScore = SmoothValue(0.0f, GameConfig.ScoreDisplay.UPDATE_SPEED)
+
+ // game ended?
+ protected var gameEnded = false
+
+ protected var isInGameEndingTransition = false
+
+ // our UI (buttons, etc)
+ private lateinit var simpleUI: SimpleUI
+
+ // sfx IDs
+ private var gameOverSfx: Int = 0
+
+ // paused?
+ protected var paused = false
+
+ // in start countdown?
+ protected var inStartCountdown = false
+ protected var startCountdownTimeRemaining: Float = 0.toFloat()
+
+ // back key pressed?
+ private var backKeyPending = false
+
+ // DPAD_CENTER key pressed?
+ private var confirmKeyPending: Boolean = false
+ private var confirmKeyEventTime: Long = 0
+
+ // isRunning on Tv?
+ protected var isTv: Boolean = false
+
+ // pause button
+ private var pauseButton: Button? = null
+
+ // speaker on and mute buttons
+ private var speakerOnButton: Button? = null
+ private var speakerMuteButton: Button? = null
+
+ // pause curtain, that is, the full screen object we display as a translucent
+ // screen over the whole display when the game is paused
+ private lateinit var pauseCurtain: GameObject
+
+ // the big play button
+ private lateinit var bigPlayButton: Button
+ private var bigStartGameButton: Button? = null
+
+ // quit button
+ private var quitButton: Button? = null
+ private var quitBarLabel: GameObject? = null
+
+ // game objects that compose the Sign In ui
+ private var signInBarObj: GameObject? = null
+ private var signInButton: Button? = null
+ private var signInTextObj: GameObject? = null
+
+ // to be implemented by subclasses
+ protected abstract val bgmResId: Int
+
+ protected abstract val displayedTime: Float
+
+ // are we signed in
+ private var signedIn = false
+
+ private val scoreDigitVisibleObj: Array
+ get() {
+ val numDigits = Math.max(
+ (displayedScore.value.toInt() + 1).toString().length,
+ GameConfig.ScoreBar.MIN_DIGITS_VISIBLE)
+ val scoreDigitVisibleObj = arrayOfNulls(numDigits)
+ for (i in scoreDigitObj.size - numDigits until scoreDigitObj.size) {
+ scoreDigitVisibleObj[i - (scoreDigitObj.size - numDigits)] = scoreDigitObj[i]
+ }
+ return scoreDigitVisibleObj
+ }
+
+ protected abstract fun makeNewScene(): BaseScene
+
+ override fun onInstall() {
+
+ // are we signed in?
+ val act = SceneManager.getInstance().activity as SceneActivity?
+ act?.let {
+ signedIn = act.isSignedIn
+ val manger = act.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
+ isTv = Configuration.UI_MODE_TYPE_TELEVISION == manger.currentModeType
+ }
+
+ renderer = SceneManager.getInstance().renderer
+ world = World(renderer)
+ digitFactory = DigitObjectFactory(renderer, world)
+ digitFactory.requestWhiteTextures(GameConfig.ScoreDisplay.DIGIT_SIZE)
+ objectFactory = GameObjectFactory(renderer, world)
+ objectFactory.requestTextures()
+
+ simpleUI = SimpleUI(renderer)
+
+ if (isTv) {
+ digitFactory.makeDigitObjects(
+ GameConfig.ScoreDisplay.DIGIT_COUNT,
+ GameConfig.TYPE_DECOR,
+ renderer.getRelativePos(
+ GameConfig.ScoreDisplay.POS_X_REL, GameConfig.ScoreDisplay.POS_X_DELTA),
+ renderer.getRelativePos(
+ GameConfig.ScoreDisplay.POS_Y_REL_TV,
+ GameConfig.ScoreDisplay.POS_Y_DELTA_TV),
+ GameConfig.ScoreDisplay.DIGIT_SIZE,
+ GameConfig.ScoreDisplay.DIGIT_SPACING,
+ scoreDigitObj)
+ bigPlayButton = objectFactory.makeBigPlayButton(this, MSG_RESUME)
+ bigPlayButton.hide()
+ simpleUI.add(bigPlayButton)
+
+ val x = GameConfig.TimeDisplay.POS_X_DELTA + GameConfig.TimeDisplay.ICON_SIZE
+ digitFactory.makeDigitObjects(
+ GameConfig.TimeDisplay.DIGIT_COUNT,
+ GameConfig.TYPE_DECOR,
+ renderer.getRelativePos(GameConfig.TimeDisplay.POS_X_REL, x),
+ renderer.getRelativePos(
+ GameConfig.TimeDisplay.POS_Y_REL_TV,
+ GameConfig.TimeDisplay.POS_Y_DELTA_TV),
+ GameConfig.TimeDisplay.DIGIT_SIZE,
+ GameConfig.TimeDisplay.DIGIT_SPACING,
+ timeDigitObj)
+
+ pauseCurtain = objectFactory.makePauseCurtain()
+ pauseCurtain.hide()
+ } else {
+ scoreBarObj = objectFactory.makeScoreBar()
+ scoreBarLabelObj = objectFactory.makeScoreBarLabel()
+ digitFactory.makeDigitObjects(
+ GameConfig.ScoreDisplay.DIGIT_COUNT,
+ GameConfig.TYPE_DECOR,
+ renderer.getRelativePos(
+ GameConfig.ScoreDisplay.POS_X_REL, GameConfig.ScoreDisplay.POS_X_DELTA),
+ renderer.getRelativePos(
+ GameConfig.ScoreDisplay.POS_Y_REL, GameConfig.ScoreDisplay.POS_Y_DELTA),
+ GameConfig.ScoreDisplay.DIGIT_SIZE,
+ GameConfig.ScoreDisplay.DIGIT_SPACING,
+ scoreDigitObj)
+ hideObjects(scoreDigitObj)
+ bringObjectsToFront(scoreDigitVisibleObj)
+ val x = GameConfig.TimeDisplay.POS_X_DELTA + GameConfig.TimeDisplay.ICON_SIZE
+ digitFactory.makeDigitObjects(
+ GameConfig.TimeDisplay.DIGIT_COUNT,
+ GameConfig.TYPE_DECOR,
+ renderer.getRelativePos(GameConfig.TimeDisplay.POS_X_REL, x),
+ renderer.getRelativePos(
+ GameConfig.TimeDisplay.POS_Y_REL, GameConfig.TimeDisplay.POS_Y_DELTA),
+ GameConfig.TimeDisplay.DIGIT_SIZE,
+ GameConfig.TimeDisplay.DIGIT_SPACING,
+ timeDigitObj)
+ countdownDigitObj = digitFactory.makeDigitObject(
+ GameConfig.TYPE_DECOR, 0.0f, 0.0f, GameConfig.Countdown.DIGIT_SIZE)
+ countdownDigitObj?.hide()
+ quitButton = objectFactory.makeQuitButton(this, MSG_QUIT)
+ quitBarLabel = objectFactory.makeQuitBarLabel()
+ quitButton?.hide()
+ quitBarLabel?.hide()
+ simpleUI.add(quitButton)
+
+ pauseButton = objectFactory.makePauseButton(this, MSG_PAUSE)
+ simpleUI.add(pauseButton)
+
+ speakerMuteButton = objectFactory.makeSpeakerMuteButton(this, MSG_UNMUTE)
+ speakerOnButton = objectFactory.makeSpeakerOnButton(this, MSG_MUTE)
+ simpleUI.add(speakerMuteButton)
+ simpleUI.add(speakerOnButton)
+ pauseCurtain = objectFactory.makePauseCurtain()
+ pauseCurtain.hide()
+
+ bigPlayButton = objectFactory.makeBigPlayButton(this, MSG_RESUME)
+ bigPlayButton.hide()
+ simpleUI.add(bigPlayButton)
+ bigStartGameButton = objectFactory.makeBigPlayButton(this, MSG_START)
+ bigStartGameButton?.hide()
+ simpleUI.add(bigStartGameButton)
+ }
+
+ val soundManager = SceneManager.getInstance().soundManager
+ if (soundManager != null) {
+ soundManager.requestBackgroundMusic(bgmResId)
+ gameOverSfx = soundManager.requestSfx(com.google.android.apps.playgames.R.raw.gameover)
+ if (soundManager.isMuted) {
+ muteSpeaker()
+ } else {
+ unmuteSpeaker()
+ }
+ }
+ }
+
+ override fun onUninstall() {}
+
+ override fun doStandbyFrame(deltaT: Float) {}
+
+ override fun doFrame(deltaT: Float) {
+ var deltaT = deltaT
+ if (paused) {
+ deltaT = 0.0f
+ }
+
+ if (backKeyPending) {
+ processBackKey()
+ }
+
+ if (confirmKeyPending) {
+ // TODO: move a focus based on KeyEvent
+ processCenterKey()
+ }
+
+ // If Activity lost focus and we're playing the game, pause
+ if (!SceneManager.getInstance().shouldBePlaying() && !gameEnded && !paused) {
+ pauseGame()
+ }
+
+ if (!gameEnded) {
+ updateScore(deltaT)
+ updateTime(deltaT)
+ } else {
+ updateScore(deltaT)
+ checkSignInWidgetsNeeded()
+ }
+
+ world.doFrame(deltaT)
+ }
+
+ private fun processBackKey() {
+ backKeyPending = false
+ if (gameEnded || paused && isTv) {
+ quitGame()
+ } else if (paused) {
+ unPauseGame()
+ } else {
+ pauseGame()
+ }
+ }
+
+ private fun processCenterKey() {
+ val currTime = System.currentTimeMillis()
+ if (currTime - confirmKeyEventTime < CENTER_KEY_DELAY_MS) {
+ bigPlayButton.setPressed(true)
+ } else {
+ confirmKeyPending = false
+ bigPlayButton.setPressed(false)
+ if (paused) {
+ unPauseGame()
+ } else if (gameEnded) {
+ // re-start new game
+ SceneManager.getInstance().requestNewScene(makeNewScene())
+ }
+ }
+ }
+
+ private fun updateScore(deltaT: Float) {
+ if (gameEnded) {
+ displayedScore.value = score.toFloat()
+ } else {
+ displayedScore.target = score.toFloat()
+ displayedScore.update(deltaT)
+ }
+ digitFactory.setDigits(Math.round(displayedScore.value), scoreDigitObj)
+ bringObjectsToFront(scoreDigitVisibleObj)
+ }
+
+ protected open fun endGame() {
+ gameEnded = true
+ // show the podium object
+ objectFactory.makePodium()
+
+ // move score to final position
+ val x = renderer.getRelativePos(
+ GameConfig.Podium.ScoreDisplay.X_REL,
+ GameConfig.Podium.ScoreDisplay.X_DELTA)
+ val y = renderer.getRelativePos(
+ GameConfig.Podium.ScoreDisplay.Y_REL,
+ GameConfig.Podium.ScoreDisplay.Y_DELTA)
+ displaceObjectsTo(scoreDigitObj, x, y)
+ bringObjectsToFront(scoreDigitVisibleObj)
+
+ // hide time counter
+ hideObjects(timeDigitObj)
+
+ // make the "your score is" label
+ objectFactory.makeScoreLabel()
+
+ // create the end of game UI and add the "play again" button to it
+ simpleUI.add(objectFactory.makeReturnToMapButton(this, MSG_RETURN_WITH_VALUE))
+
+ if (isTv) {
+ // TODO: tv specific ui layout
+ } else {
+ // hide the score bar
+ scoreBarObj?.hide()
+ scoreBarLabelObj?.hide()
+ pauseButton?.hide()
+ speakerMuteButton?.hide()
+ speakerOnButton?.hide()
+ // TODO: real message
+
+ // create the sign in bar and sign in button
+ if (!signedIn) {
+ signInBarObj = objectFactory.makeSignInBar()
+ signInTextObj = objectFactory.makeSignInText()
+ signInButton = objectFactory.makeSignInButton(this, MSG_SIGN_IN)
+ simpleUI.add(signInButton)
+ }
+ }
+
+ // disable the background music
+ SceneManager.getInstance().soundManager.enableBgm(false)
+
+ // play the game over sfx
+ SceneManager.getInstance().soundManager.playSfx(gameOverSfx)
+ }
+
+ private fun displaceObjectsTo(objs: Array, x: Float, y: Float) {
+ val first = objs[0] ?: throw IllegalStateException()
+ val deltaX = x - first.x
+ val deltaY = y - first.y
+ var i = 0
+ while (i < objs.size) {
+ objs[i]?.displaceBy(deltaX, deltaY)
+ i++
+ }
+ }
+
+ private fun bringObjectsToFront(objs: Array) {
+ var i = 0
+ while (i < objs.size) {
+ objs[i]?.show()
+ objs[i]?.bringToFront()
+ i++
+ }
+ }
+
+ private fun hideObjects(objs: Array) {
+ var i = 0
+ while (i < objs.size) {
+ objs[i]?.hide()
+ i++
+ }
+ }
+
+ private fun updateTime(deltaT: Float) {
+ var seconds = Math.ceil(displayedTime.toDouble()).toInt()
+ seconds = if (seconds < 0) 0 else if (seconds > 99) 99 else seconds
+ digitFactory.setDigits(seconds, timeDigitObj)
+ bringObjectsToFront(timeDigitObj)
+ }
+
+ override fun onScreenResized(width: Int, height: Int) {}
+
+ override fun onPointerDown(pointerId: Int, x: Float, y: Float) {
+ super.onPointerDown(pointerId, x, y)
+ simpleUI.onPointerDown(pointerId, x, y)
+ }
+
+ override fun onPointerUp(pointerId: Int, x: Float, y: Float) {
+ super.onPointerUp(pointerId, x, y)
+ simpleUI.onPointerUp(pointerId, x, y)
+ }
+
+ protected fun startGameScreen() {
+ paused = true
+ SceneManager.getInstance().soundManager.stopSound()
+ if (isTv) {
+ pauseCurtain.show()
+ pauseCurtain.bringToFront()
+
+ bigPlayButton.show()
+ bigPlayButton.bringToFront()
+ } else {
+ pauseButton?.hide()
+
+ pauseCurtain.show()
+ pauseCurtain.bringToFront()
+
+ quitButton?.hide()
+ quitBarLabel?.hide()
+ speakerOnButton?.bringToFront()
+ speakerMuteButton?.bringToFront()
+ speakerMuteButton?.setEnabled(true)
+ speakerOnButton?.setEnabled(true)
+ bigStartGameButton?.show()
+ bigStartGameButton?.bringToFront()
+ }
+
+ if (SceneManager.getInstance().activity != null) {
+ SceneManager.getInstance()
+ .activity
+ .runOnUiThread {
+ ImmersiveModeHelper.setImmersiveStickyWithActionBar(
+ SceneManager.getInstance().activity.window)
+ }
+ }
+ }
+
+ private fun pauseGame() {
+ if (!paused && !gameEnded) {
+ paused = true
+ SceneManager.getInstance().soundManager.stopSound()
+
+ if (isTv) {
+ pauseCurtain.show()
+ pauseCurtain.bringToFront()
+
+ bigPlayButton.show()
+ bigPlayButton.bringToFront()
+ } else {
+ pauseButton?.hide()
+
+ pauseCurtain.show()
+ pauseCurtain.bringToFront()
+
+ bigPlayButton.show()
+ bigPlayButton.bringToFront()
+
+ quitButton?.show()
+ quitBarLabel?.show()
+ quitButton?.bringToFront()
+ quitBarLabel?.bringToFront()
+
+ speakerMuteButton?.setEnabled(false)
+ speakerOnButton?.setEnabled(false)
+ }
+
+ if (SceneManager.getInstance().activity != null) {
+ SceneManager.getInstance()
+ .activity
+ .runOnUiThread {
+ val activity = SceneManager.getInstance().activity
+ if (activity != null) {
+ ImmersiveModeHelper.setImmersiveStickyWithActionBar(
+ activity.window)
+ }
+ }
+ }
+ }
+ }
+
+ private fun muteSpeaker() {
+ if (!gameEnded) {
+ SceneManager.getInstance().soundManager.mute()
+ speakerOnButton?.hide()
+ speakerMuteButton?.show()
+ speakerMuteButton?.bringToFront()
+ }
+ }
+
+ private fun unmuteSpeaker() {
+ if (!gameEnded) {
+ SceneManager.getInstance().soundManager.unmute()
+ speakerMuteButton?.hide()
+ speakerOnButton?.show()
+ speakerOnButton?.bringToFront()
+ }
+ }
+
+ private fun startCountdown() {
+ inStartCountdown = true
+ startCountdownTimeRemaining = GameConfig.Countdown.TIME.toFloat()
+ bigStartGameButton?.hide()
+ digitFactory.setDigit(countdownDigitObj, GameConfig.Countdown.TIME)
+ countdownDigitObj?.show()
+ countdownDigitObj?.bringToFront()
+ }
+
+ protected fun unPauseGame() {
+ if (!paused) {
+ return
+ }
+ paused = false
+ SceneManager.getInstance().soundManager.enableBgm(true)
+ SceneManager.getInstance().soundManager.resumeSound()
+ if (isTv) {
+ pauseCurtain.hide()
+ bigPlayButton.hide()
+ } else {
+ pauseButton?.show()
+ pauseCurtain.hide()
+ quitButton?.hide()
+ quitBarLabel?.hide()
+ bigPlayButton.hide()
+ countdownDigitObj?.hide()
+ speakerMuteButton?.setEnabled(true)
+ speakerOnButton?.setEnabled(true)
+ }
+
+ if (SceneManager.getInstance().activity != null) {
+ SceneManager.getInstance()
+ .activity
+ .runOnUiThread {
+ ImmersiveModeHelper.setImmersiveSticky(
+ SceneManager.getInstance().activity.window)
+ }
+ }
+ }
+
+ override fun onPointerMove(pointerId: Int, x: Float, y: Float, deltaX: Float, deltaY: Float) {
+ simpleUI.onPointerMove(pointerId, x, y, deltaX, deltaY)
+ }
+
+ override fun onWidgetTriggered(message: Int) {
+ when (message) {
+ MSG_RETURN_WITH_VALUE -> returnWithScore()
+ MSG_REPLAY -> SceneManager.getInstance().requestNewScene(makeNewScene())
+ MSG_SIGN_IN -> {
+ (SceneManager.getInstance().activity as SceneActivity).beginUserInitiatedSignIn()
+ }
+ MSG_PAUSE -> pauseGame()
+ MSG_RESUME -> unPauseGame()
+ MSG_QUIT -> quitGame()
+ MSG_SHARE -> share()
+ MSG_MUTE -> muteSpeaker()
+ MSG_UNMUTE -> unmuteSpeaker()
+ MSG_START -> startCountdown()
+ MSG_GO_TO_END_GAME -> goToEndGameWithDelay(GameConfig.EndGame.DELAY)
+ }
+ }
+
+ private fun quitGame() {
+ val act = SceneManager.getInstance().activity
+ if (act != null && act is SceneActivity) {
+ act.postQuitGame()
+ }
+ }
+
+ private fun returnWithScore() {
+ val act = SceneManager.getInstance().activity
+ if (act != null && act is SceneActivity) {
+ act.postReturnWithScore(score)
+ }
+ }
+
+ private fun goToEndGameWithDelay(delay: Int) {
+ val act = SceneManager.getInstance().activity
+ (act as SceneActivity).setGameEndedListener(this)
+ act.postDelayedGoToEndGame(delay)
+ }
+
+ protected fun goToEndGame() {
+ val act = SceneManager.getInstance().activity
+ if (act != null && act is SceneActivity) {
+ act.setGameEndedListener(this)
+ act.postGoToEndGame()
+ }
+ }
+
+ override fun onGameEnded() {
+ gameEnded = true
+ }
+
+ private fun share() {
+ val act = SceneManager.getInstance().activity
+ if (act != null && act is SceneActivity) {
+ act.share()
+ }
+ }
+
+ private fun checkSignInWidgetsNeeded() {
+ if (signedIn) {
+ signInBarObj?.hide()
+ signInTextObj?.hide()
+ signInButton?.hide()
+ }
+ }
+
+ // Caution: Called from the UI thread!
+ fun setSignedIn(signedIn: Boolean) {
+ this.signedIn = signedIn
+ }
+
+ // Caution: Called from the UI thread!
+ fun onBackKeyPressed(): Boolean {
+ // raise a flag and process later (on the game thread)
+ backKeyPending = true
+ return true
+ }
+
+ // Caution: Called from the UI thread!
+ fun onConfirmKeyPressed(): Boolean {
+ // raise a flag and process later (on the game thread)
+ if (confirmKeyPending) {
+ return true
+ }
+
+ confirmKeyPending = true
+ confirmKeyEventTime = System.currentTimeMillis()
+ return true
+ }
+
+ companion object {
+
+ // widget trigger messages
+ private const val MSG_RETURN_WITH_VALUE = 1001
+ private const val MSG_SIGN_IN = 1002
+ private const val MSG_PAUSE = 1003
+ private const val MSG_RESUME = 1004
+ private const val MSG_QUIT = 1005
+ private const val MSG_SHARE = 1006
+ private const val MSG_REPLAY = 1007
+ private const val MSG_MUTE = 1008
+ private const val MSG_UNMUTE = 1009
+ private const val MSG_START = 1010
+ const val MSG_GO_TO_END_GAME = 1011
+ private const val CENTER_KEY_DELAY_MS: Long = 500
+ }
+}
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/DigitObjectFactory.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/DigitObjectFactory.kt
new file mode 100644
index 000000000..bcdc10bc2
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/DigitObjectFactory.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+import com.google.android.apps.playgames.simpleengine.Renderer
+import com.google.android.apps.playgames.simpleengine.game.GameObject
+import com.google.android.apps.playgames.simpleengine.game.World
+
+class DigitObjectFactory(private var renderer: Renderer, private var world: World) {
+
+ private var whiteDigitTex = IntArray(10)
+ private var negativeTex = IntArray(1)
+
+ fun requestWhiteTextures(maxDigitWidth: Float) {
+ val res = intArrayOf(
+ com.google.android.apps.playgames.R.drawable.games_digit_0,
+ com.google.android.apps.playgames.R.drawable.games_digit_1,
+ com.google.android.apps.playgames.R.drawable.games_digit_2,
+ com.google.android.apps.playgames.R.drawable.games_digit_3,
+ com.google.android.apps.playgames.R.drawable.games_digit_4,
+ com.google.android.apps.playgames.R.drawable.games_digit_5,
+ com.google.android.apps.playgames.R.drawable.games_digit_6,
+ com.google.android.apps.playgames.R.drawable.games_digit_7,
+ com.google.android.apps.playgames.R.drawable.games_digit_8,
+ com.google.android.apps.playgames.R.drawable.games_digit_9
+ )
+ for (i in 0..9) {
+ whiteDigitTex[i] = renderer.requestImageTex(
+ res[i], "white_digit_$i", Renderer.DIM_WIDTH, maxDigitWidth)
+ }
+ negativeTex[0] = renderer.requestImageTex(
+ com.google.android.apps.playgames.R.drawable.games_digit_negative,
+ "digit_negative",
+ Renderer.DIM_WIDTH,
+ maxDigitWidth)
+ }
+
+ fun makeDigitObject(type: Int, x: Float, y: Float, size: Float): GameObject {
+ return world.newGameObjectWithImage(type, x, y, whiteDigitTex[0], size, size)
+ }
+
+ fun setDigit(digitObject: GameObject?, digit: Int) {
+ var digit = digit
+ digit = if (digit > 9) 9 else if (digit < 0) 0 else digit
+ digitObject?.getSprite(0)?.texIndex = whiteDigitTex[digit]
+ }
+
+ fun makeDigitObjects(
+ count: Int,
+ type: Int,
+ x: Float,
+ y: Float,
+ size: Float,
+ stride: Float,
+ result: Array
+ ) {
+ var x = x
+ var i = 0
+ while (i < count) {
+ result[i] = makeDigitObject(type, x, y, size)
+ x += stride
+ i++
+ }
+ }
+
+ fun setDigits(
+ valueToShow: Int,
+ digitObjects: Array,
+ start: Int = 0,
+ length: Int = digitObjects.size
+ ) {
+ var valueToShow = valueToShow
+ if (valueToShow >= 0) {
+ var i: Int = start + length - 1
+ while (i >= start) {
+ setDigit(digitObjects[i], valueToShow % 10)
+ valueToShow /= 10
+ --i
+ }
+ } else {
+ valueToShow = -valueToShow
+ var i: Int = start + length - 1
+ while (i >= start) {
+ if (i == start) {
+ digitObjects[i]?.getSprite(0)!!.texIndex = negativeTex[0]
+ } else {
+ setDigit(digitObjects[i], valueToShow % 10)
+ valueToShow /= 10
+ }
+ --i
+ }
+ }
+ }
+}
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/GameConfig.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/GameConfig.kt
new file mode 100644
index 000000000..c1dd32d90
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/GameConfig.kt
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+import com.google.android.apps.playgames.simpleengine.Renderer
+
+class GameConfig {
+
+ // score popup settings
+ object ScorePopup {
+ const val DIGIT_SIZE = 0.04f
+ const val DIGIT_SPACING = 0.022f
+ const val POPUP_VEL_Y = 0.1f
+ const val POPUP_EXPIRE = 0.8f
+ }
+
+ // score bar settings
+ object ScoreBar {
+ object PauseButton {
+ const val X_REL = Renderer.REL_RIGHT
+ const val X_DELTA = -0.23f
+ const val Y_REL = Renderer.REL_TOP
+ const val Y_DELTA = -0.09f
+ const val WIDTH = 0.2f
+ const val HEIGHT = 0.2f
+ const val SPRITE_WIDTH = 0.15f
+ const val SPRITE_HEIGHT = 0.15f
+ }
+
+ object ScoreBarLabel {
+ const val WIDTH = ScoreBar.WIDTH
+ const val X_REL = Renderer.REL_LEFT
+ const val X_DELTA = 0.58f * WIDTH
+ const val Y_REL = Renderer.REL_TOP
+ const val Y_DELTA = -0.13f
+ const val FONT_SIZE = 20.0f
+ }
+
+ const val WIDTH = 0.42f
+ const val X_REL = Renderer.REL_LEFT
+ const val X_DELTA = 0.6f * WIDTH
+ const val Y_REL = Renderer.REL_TOP
+ const val Y_DELTA = -0.08f
+ const val MIN_DIGITS_VISIBLE = 2
+ }
+
+ object Countdown {
+ const val TIME = 3
+ const val DIGIT_SIZE = PauseScreen.BigPlayButton.WIDTH
+ }
+
+ object EndGame {
+ const val DELAY = 2000
+ }
+
+ // sound display settings
+ object Speaker {
+ const val WIDTH = 0.2f
+ const val HEIGHT = 0.2f
+ const val X_REL = Renderer.REL_RIGHT
+ const val X_DELTA = -.07f
+ const val Y_REL = Renderer.REL_TOP
+ const val Y_DELTA = ScoreBar.PauseButton.Y_DELTA
+ const val SPRITE_WIDTH = 0.15f
+ const val SPRITE_HEIGHT = 0.15f
+ }
+
+ // score display settings
+ object ScoreDisplay {
+
+ const val DIGIT_SIZE = 0.09f
+ const val DIGIT_SPACING = DIGIT_SIZE * 0.5f
+ const val DIGIT_COUNT = 6
+ const val POS_X_REL = Renderer.REL_LEFT
+ const val POS_X_DELTA = 0.04f
+ const val POS_Y_REL = Renderer.REL_TOP
+ const val POS_Y_DELTA = -0.062f
+
+ const val POS_Y_REL_TV = Renderer.REL_TOP
+ const val POS_Y_DELTA_TV = -0.093f
+
+ const val UPDATE_SPEED = 1000.0f
+ }
+
+ // time display settings
+ object TimeDisplay {
+
+ const val ICON_SIZE = 0.06f
+ const val DIGIT_SIZE = ScoreDisplay.DIGIT_SIZE
+ const val DIGIT_SPACING = ScoreDisplay.DIGIT_SPACING
+ const val DIGIT_COUNT = 2
+ const val POS_X_REL = Renderer.REL_LEFT
+ const val POS_X_DELTA = ScoreBar.WIDTH / 2 + ScoreBar.X_DELTA + 0.1f
+ const val POS_Y_REL = Renderer.REL_TOP
+ const val POS_Y_DELTA = ScoreDisplay.POS_Y_DELTA
+ const val POS_Y_REL_TV = Renderer.REL_TOP
+ const val POS_Y_DELTA_TV = ScoreDisplay.POS_Y_DELTA_TV
+ }
+
+ // podium (level end) screen settings
+ object Podium {
+
+ // score label (the static text that says "Score")
+ object ScoreLabel {
+
+ const val X_REL = Renderer.REL_CENTER
+ const val X_DELTA = 0.15f
+ const val Y_REL = Renderer.REL_CENTER
+ const val Y_DELTA = 0.2f
+ const val FONT_SIZE = 25.0f
+ }
+
+ // where do we display the score in the podium screen
+ object ScoreDisplay {
+
+ const val X_REL = Renderer.REL_CENTER
+ const val X_DELTA = 0.07f
+ const val Y_REL = Renderer.REL_CENTER
+ const val Y_DELTA = 0.1f
+ }
+
+ // "play again" button
+ object ReplayButton {
+
+ const val FONT_SIZE = 25.0f
+ const val X_REL = Renderer.REL_CENTER
+ const val X_DELTA = 0.0f
+ const val Y_REL = Renderer.REL_CENTER
+ const val Y_DELTA = -0.13f
+ const val WIDTH = 0.6f
+ const val HEIGHT = 0.12f
+ const val NORMAL_COLOR = -0xd961bd
+ const val HIGHLIGHT_COLOR = -0xd24fb5
+ }
+
+ const val WIDTH = 0.8f
+ const val X_REL = Renderer.REL_CENTER
+ const val X_DELTA = 0.0f
+ const val Y_REL = Renderer.REL_CENTER
+ const val Y_DELTA = 0.1f
+ }
+
+ // Sign in bar
+ object SignInBar {
+
+ const val COLOR = -0x7f000001
+ const val X_REL = Renderer.REL_CENTER
+ const val X_DELTA = 0.0f
+ const val Y_REL = Renderer.REL_BOTTOM
+ const val HEIGHT = 0.2f
+ const val WIDTH = 10.0f
+ const val Y_DELTA = 0.5f * HEIGHT
+ }
+
+ // Sign in button
+ object SignInButton {
+
+ const val WIDTH = 0.4f
+ // (120/402 is the height/width of the image asset)
+ const val HEIGHT = WIDTH * (120.0f / 402.0f)
+ const val X_REL = Renderer.REL_LEFT
+ const val X_DELTA = WIDTH * 0.5f + 0.05f
+ const val Y_REL = Renderer.REL_BOTTOM
+ const val Y_DELTA = 0.1f
+
+ const val TEXT_DELTA_X = 0.05f
+
+ const val FONT_SIZE = 20.0f
+ }
+
+ // Sign in encouragement text
+ object SignInText {
+
+ const val COLOR = -0xda50cf
+ const val X_REL = Renderer.REL_LEFT
+ const val X_DELTA =
+ SignInButton.X_DELTA + SignInButton.WIDTH * 0.5f + 0.05f
+ const val Y_REL = Renderer.REL_BOTTOM
+ const val Y_DELTA = 0.1f
+ const val ANCHOR = Renderer.TEXT_ANCHOR_MIDDLE or Renderer.TEXT_ANCHOR_LEFT
+ const val FONT_SIZE = 20.0f
+ }
+
+ // mute screen settings
+ object PauseScreen {
+
+ object BigPlayButton {
+
+ const val X_REL = Renderer.REL_CENTER
+ const val X_DELTA = 0.02f
+ const val Y_REL = Renderer.REL_CENTER
+ const val Y_DELTA = 0.0f
+ const val WIDTH = 0.4f
+ const val HEIGHT = 0.4f
+ const val SPRITE_WIDTH = 0.4f
+ }
+
+ object QuitBar {
+
+ object QuitBarLabel {
+ const val X_REL = Renderer.REL_CENTER
+ const val X_DELTA = 0.0f
+ const val Y_REL = Renderer.REL_CENTER
+ const val Y_DELTA = -0.35f
+ const val WIDTH = .7f
+ const val FONT_SIZE = 35.0f
+ }
+
+ const val X_REL = Renderer.REL_CENTER
+ const val X_DELTA = 0.0f
+ const val Y_REL = Renderer.REL_CENTER
+ const val Y_DELTA = -0.35f
+ const val WIDTH = .7f
+ const val HEIGHT = WIDTH * 0.33f
+ const val SPRITE_WIDTH = WIDTH
+ }
+
+ const val CURTAIN_COLOR = -0x7f000001
+ }
+
+ companion object {
+
+ // type code for decorative objects (HUD, etc)
+ const val TYPE_DECOR = 9999
+ }
+}
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/GameEndedListener.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/GameEndedListener.kt
new file mode 100644
index 000000000..b88abd5e9
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/GameEndedListener.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+interface GameEndedListener {
+
+ val score: Int
+ fun onGameEnded()
+}
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/GameFragment.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/GameFragment.kt
new file mode 100644
index 000000000..da1df0dfc
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/GameFragment.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import com.google.android.apps.playgames.simpleengine.GameView
+
+class GameFragment : Fragment() {
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return GameView(activity).apply {
+ isFocusable = true
+ isFocusableInTouchMode = true
+ keepScreenOn = true
+ }
+ }
+}
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/GameObjectFactory.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/GameObjectFactory.kt
new file mode 100644
index 000000000..dc21e7c3c
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/GameObjectFactory.kt
@@ -0,0 +1,481 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+import com.google.android.apps.playgames.simpleengine.Renderer
+import com.google.android.apps.playgames.simpleengine.game.GameObject
+import com.google.android.apps.playgames.simpleengine.game.World
+import com.google.android.apps.playgames.simpleengine.ui.Button
+import com.google.android.apps.playgames.simpleengine.ui.Widget
+import java.util.Arrays
+
+class GameObjectFactory(private var renderer: Renderer, private var world: World) {
+
+ // Textures
+ private var texClock: Int = 0
+ private var texPodium: Int = 0
+ private var playAgainTex: Int = 0
+ private var scoreLabelTex: Int = 0
+ private var signInLabelTex: Int = 0
+ private var signInNormalTex: Int = 0
+ private var signInHighlightTex: Int = 0
+ private var signInTextTex: Int = 0
+ private var scoreBarTex: Int = 0
+ private var scoreBarLabelTex: Int = 0
+ private var pauseIconTex: Int = 0
+ private var pauseIconPressedTex: Int = 0
+ private var speakerMuteIconTex: Int = 0
+ private var speakerOnIconTex: Int = 0
+ private var bigPlayButtonNormalTex: Int = 0
+ private var bigPlayButtonHighlightTex: Int = 0
+ private var quitBarTex: Int = 0
+ private var quitBarPressedTex: Int = 0
+ private var quitBarLabelTex: Int = 0
+ private var inviteBarTex: Int = 0
+ private var inviteBarPressedTex: Int = 0
+
+ private var tmpDigits = arrayOfNulls(5)
+
+ fun makeScorePopup(x: Float, y: Float, score: Int, df: DigitObjectFactory) {
+ val digits: Int = if (score >= 0) {
+ when {
+ score >= 10000 -> 5
+ score >= 1000 -> 4
+ score >= 100 -> 3
+ score >= 10 -> 2
+ else -> 1
+ }
+ } else {
+ when {
+ score <= -10000 -> 6
+ score <= -1000 -> 5
+ score <= -100 -> 4
+ score <= -10 -> 3
+ else -> 2
+ }
+ }
+
+ Arrays.fill(tmpDigits, null)
+ df.makeDigitObjects(
+ digits,
+ GameConfig.TYPE_DECOR,
+ x,
+ y,
+ GameConfig.ScorePopup.DIGIT_SIZE,
+ GameConfig.ScorePopup.DIGIT_SPACING,
+ tmpDigits)
+ df.setDigits(score, tmpDigits, 0, digits)
+
+ var i = 0
+ while (i < digits) {
+ val o = tmpDigits[i]
+ o?.velY = GameConfig.ScorePopup.POPUP_VEL_Y
+ o?.timeToLive = GameConfig.ScorePopup.POPUP_EXPIRE
+ i++
+ }
+ }
+
+ fun requestTextures() {
+ texClock = renderer.requestImageTex(
+ R.drawable.jetpack_clock,
+ "jetpack_clock",
+ Renderer.DIM_WIDTH,
+ GameConfig.TimeDisplay.ICON_SIZE)
+ texPodium = renderer.requestImageTex(
+ R.drawable.jetpack_podium,
+ "jetpack_podium",
+ Renderer.DIM_WIDTH,
+ GameConfig.Podium.WIDTH)
+
+ playAgainTex = renderer.requestTextTex(
+ com.google.android.apps.santatracker.common.R.string.return_to_map,
+ "return_to_map",
+ GameConfig.Podium.ReplayButton.FONT_SIZE)
+ scoreLabelTex = renderer.requestTextTex(
+ com.google.android.apps.santatracker.common.R.string.score,
+ "score",
+ GameConfig.Podium.ScoreLabel.FONT_SIZE)
+
+ signInLabelTex = renderer.requestTextTex(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .string
+ .common_signin_button_text,
+ "jetpack_sign_in",
+ GameConfig.SignInButton.FONT_SIZE)
+ signInNormalTex = renderer.requestImageTex(
+ R.drawable.jetpack_signin,
+ "jetpack_siginin",
+ Renderer.DIM_WIDTH,
+ GameConfig.SignInButton.WIDTH)
+ signInHighlightTex = renderer.requestImageTex(
+ R.drawable.jetpack_signin_pressed,
+ "jetpack_signin_pressed",
+ Renderer.DIM_WIDTH,
+ GameConfig.SignInButton.WIDTH)
+ signInTextTex = renderer.requestTextTex(
+ com.google.android.apps.santatracker.common.R.string.why_sign_in,
+ "jetpack_why_sign_in",
+ GameConfig.SignInText.FONT_SIZE,
+ GameConfig.SignInText.ANCHOR,
+ GameConfig.SignInText.COLOR)
+ scoreBarTex = renderer.requestImageTex(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .drawable
+ .icon_ribbon_upsidedown_short,
+ "games_scorebar",
+ Renderer.DIM_WIDTH,
+ GameConfig.ScoreBar.WIDTH)
+ scoreBarLabelTex = renderer.requestTextTex(
+ com.google.android.apps.santatracker.common.R.string.score,
+ "score_bar_label",
+ GameConfig.ScoreBar.ScoreBarLabel.FONT_SIZE)
+ pauseIconTex = renderer.requestImageTex(
+ com.google.android.apps.santatracker.common.R.drawable.common_btn_pause,
+ "games_pause",
+ Renderer.DIM_WIDTH,
+ GameConfig.ScoreBar.PauseButton.SPRITE_WIDTH)
+ pauseIconPressedTex = renderer.requestImageTex(
+ com.google.android.apps.santatracker.common.R.drawable.common_btn_pause,
+ "games_pause_pressed",
+ Renderer.DIM_WIDTH,
+ GameConfig.ScoreBar.PauseButton.SPRITE_WIDTH)
+ speakerMuteIconTex = renderer.requestImageTex(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .drawable
+ .common_btn_speaker_off,
+ "speaker_mute",
+ Renderer.DIM_WIDTH,
+ GameConfig.Speaker.SPRITE_WIDTH)
+ speakerOnIconTex = renderer.requestImageTex(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .drawable
+ .common_btn_speaker_on,
+ "speaker_on",
+ Renderer.DIM_WIDTH,
+ GameConfig.Speaker.SPRITE_WIDTH)
+ bigPlayButtonNormalTex = renderer.requestImageTex(
+ com.google.android.apps.santatracker.common.R.drawable.btn_play_yellow,
+ "btn_play_yellow",
+ Renderer.DIM_WIDTH,
+ GameConfig.PauseScreen.BigPlayButton.SPRITE_WIDTH)
+ bigPlayButtonHighlightTex = renderer.requestImageTex(
+ com.google.android.apps.santatracker.common.R.drawable.btn_play_yellow,
+ "btn_play_pressed",
+ Renderer.DIM_WIDTH,
+ GameConfig.PauseScreen.BigPlayButton.SPRITE_WIDTH)
+ quitBarTex = renderer.requestImageTex(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .drawable
+ .purple_rectangle_button,
+ "quit_button",
+ Renderer.DIM_WIDTH,
+ GameConfig.PauseScreen.QuitBar.SPRITE_WIDTH)
+ quitBarLabelTex = renderer.requestTextTex(
+ com.google.android.apps.santatracker.common.R.string.back_to_village,
+ "quit_bar_label",
+ GameConfig.PauseScreen.QuitBar.QuitBarLabel.FONT_SIZE)
+ quitBarPressedTex = renderer.requestImageTex(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .drawable
+ .purple_rectangle_button,
+ "quit_button_pressed",
+ Renderer.DIM_WIDTH,
+ GameConfig.PauseScreen.QuitBar.SPRITE_WIDTH)
+ inviteBarTex = renderer.requestImageTex(
+ com.google.android.apps.santatracker.common.R.drawable.games_share,
+ "games_share",
+ Renderer.DIM_WIDTH,
+ GameConfig.PauseScreen.QuitBar.SPRITE_WIDTH)
+ inviteBarPressedTex = renderer.requestImageTex(
+ com.google.android.apps.santatracker.common.R.drawable.games_share_pressed,
+ "games_share_pressed",
+ Renderer.DIM_WIDTH,
+ GameConfig.PauseScreen.QuitBar.SPRITE_WIDTH)
+ }
+
+ fun makePodium(): GameObject {
+ val x = renderer.getRelativePos(GameConfig.Podium.X_REL, GameConfig.Podium.X_DELTA)
+ val y = renderer.getRelativePos(GameConfig.Podium.Y_REL, GameConfig.Podium.Y_DELTA)
+ return world.newGameObjectWithImage(
+ GameConfig.TYPE_DECOR, x, y, texPodium, GameConfig.Podium.WIDTH,
+ java.lang.Float.NaN)
+ }
+
+ fun makeScoreBar(): GameObject {
+ val x = renderer.getRelativePos(GameConfig.ScoreBar.X_REL, GameConfig.ScoreBar.X_DELTA)
+ val y = renderer.getRelativePos(GameConfig.ScoreBar.Y_REL, GameConfig.ScoreBar.Y_DELTA)
+ return world.newGameObjectWithImage(
+ GameConfig.TYPE_DECOR, x, y, scoreBarTex, GameConfig.ScoreBar.WIDTH,
+ java.lang.Float.NaN)
+ }
+
+ fun makeScoreBarLabel(): GameObject {
+ val x = renderer.getRelativePos(
+ GameConfig.ScoreBar.ScoreBarLabel.X_REL,
+ GameConfig.ScoreBar.ScoreBarLabel.X_DELTA)
+ val y = renderer.getRelativePos(
+ GameConfig.ScoreBar.ScoreBarLabel.Y_REL,
+ GameConfig.ScoreBar.ScoreBarLabel.Y_DELTA)
+ return world.newGameObjectWithImage(
+ GameConfig.TYPE_DECOR,
+ x,
+ y,
+ scoreBarLabelTex,
+ GameConfig.ScoreBar.ScoreBarLabel.WIDTH,
+ java.lang.Float.NaN)
+ }
+
+ fun makeQuitBarLabel(): GameObject {
+ val x = renderer.getRelativePos(
+ GameConfig.PauseScreen.QuitBar.QuitBarLabel.X_REL,
+ GameConfig.PauseScreen.QuitBar.QuitBarLabel.X_DELTA)
+ val y = renderer.getRelativePos(
+ GameConfig.PauseScreen.QuitBar.QuitBarLabel.Y_REL,
+ GameConfig.PauseScreen.QuitBar.QuitBarLabel.Y_DELTA)
+ return world.newGameObjectWithImage(
+ GameConfig.TYPE_DECOR,
+ x,
+ y,
+ quitBarLabelTex,
+ GameConfig.PauseScreen.QuitBar.QuitBarLabel.WIDTH,
+ java.lang.Float.NaN)
+ }
+
+ fun makeScoreLabel(): GameObject {
+ // create the "score" static label
+ val x = renderer.getRelativePos(
+ GameConfig.Podium.ScoreLabel.X_REL, GameConfig.Podium.ScoreLabel.X_DELTA)
+ val y = renderer.getRelativePos(
+ GameConfig.Podium.ScoreLabel.Y_REL, GameConfig.Podium.ScoreLabel.Y_DELTA)
+ return world.newGameObjectWithImage(
+ GameConfig.TYPE_DECOR, x, y, scoreLabelTex, java.lang.Float.NaN,
+ java.lang.Float.NaN)
+ }
+
+ fun makeReturnToMapButton(listener: Widget.WidgetTriggerListener, message: Int): Button {
+ val x = renderer.getRelativePos(
+ GameConfig.Podium.ReplayButton.X_REL,
+ GameConfig.Podium.ReplayButton.X_DELTA)
+ val y = renderer.getRelativePos(
+ GameConfig.Podium.ReplayButton.Y_REL,
+ GameConfig.Podium.ReplayButton.Y_DELTA)
+ val returnToMapButton = Button(
+ renderer,
+ x,
+ y,
+ GameConfig.Podium.ReplayButton.WIDTH,
+ GameConfig.Podium.ReplayButton.HEIGHT)
+ returnToMapButton.addFlatBackground(
+ GameConfig.Podium.ReplayButton.NORMAL_COLOR,
+ GameConfig.Podium.ReplayButton.HIGHLIGHT_COLOR)
+ returnToMapButton.addTex(playAgainTex)
+ returnToMapButton.setClickListener(listener, message)
+ return returnToMapButton
+ }
+
+ fun makeSignInBar(): GameObject {
+ val x = renderer.getRelativePos(GameConfig.SignInBar.X_REL, GameConfig.SignInBar.X_DELTA)
+ val y = renderer.getRelativePos(GameConfig.SignInBar.Y_REL, GameConfig.SignInBar.Y_DELTA)
+ return world.newGameObjectWithColor(
+ GameConfig.TYPE_DECOR,
+ x,
+ y,
+ GameConfig.SignInBar.COLOR,
+ GameConfig.SignInBar.WIDTH,
+ GameConfig.SignInBar.HEIGHT)
+ }
+
+ fun makeSignInText(): GameObject {
+ val x = renderer.getRelativePos(
+ GameConfig.SignInText.X_REL, GameConfig.SignInText.X_DELTA)
+ val y = renderer.getRelativePos(
+ GameConfig.SignInText.Y_REL, GameConfig.SignInText.Y_DELTA)
+ return world.newGameObjectWithImage(
+ GameConfig.TYPE_DECOR, x, y, signInTextTex, java.lang.Float.NaN,
+ java.lang.Float.NaN)
+ }
+
+ fun makeSignInButton(listener: Widget.WidgetTriggerListener, message: Int): Button {
+ val x = renderer.getRelativePos(
+ GameConfig.SignInButton.X_REL, GameConfig.SignInButton.X_DELTA)
+ val y = renderer.getRelativePos(
+ GameConfig.SignInButton.Y_REL, GameConfig.SignInButton.Y_DELTA)
+ val signInButton = Button(
+ renderer,
+ x,
+ y,
+ GameConfig.SignInButton.WIDTH,
+ GameConfig.SignInButton.HEIGHT)
+ signInButton.addNormalTex(signInNormalTex)
+ signInButton.addHighlightTex(signInHighlightTex)
+ signInButton.addTex(
+ signInLabelTex, GameConfig.SignInButton.TEXT_DELTA_X, 0.0f, java.lang.Float.NaN,
+ java.lang.Float.NaN)
+ signInButton.setClickListener(listener, message)
+ return signInButton
+ }
+
+ private fun makeSpeakerOnOrMuteButton(
+ isMute: Boolean,
+ listener: Widget.WidgetTriggerListener,
+ message: Int
+ ): Button {
+ val x = renderer.getRelativePos(GameConfig.Speaker.X_REL, GameConfig.Speaker.X_DELTA)
+ val y = renderer.getRelativePos(GameConfig.Speaker.Y_REL, GameConfig.Speaker.Y_DELTA)
+ val button = Button(renderer, x, y, GameConfig.Speaker.WIDTH, GameConfig.Speaker.HEIGHT)
+ button.addNormalTex(
+ if (isMute) speakerMuteIconTex else speakerOnIconTex,
+ 0.0f,
+ 0.0f,
+ GameConfig.Speaker.SPRITE_WIDTH,
+ GameConfig.Speaker.SPRITE_HEIGHT)
+ button.setClickListener(listener, message)
+ return button
+ }
+
+ fun makePauseButton(listener: Widget.WidgetTriggerListener, message: Int): Button {
+ val x = renderer.getRelativePos(
+ GameConfig.ScoreBar.PauseButton.X_REL,
+ GameConfig.ScoreBar.PauseButton.X_DELTA)
+ val y = renderer.getRelativePos(
+ GameConfig.ScoreBar.PauseButton.Y_REL,
+ GameConfig.ScoreBar.PauseButton.Y_DELTA)
+ val button = Button(
+ renderer,
+ x,
+ y,
+ GameConfig.ScoreBar.PauseButton.WIDTH,
+ GameConfig.ScoreBar.PauseButton.HEIGHT)
+ button.addNormalTex(
+ pauseIconTex,
+ 0.0f,
+ 0.0f,
+ GameConfig.ScoreBar.PauseButton.SPRITE_WIDTH,
+ GameConfig.ScoreBar.PauseButton.SPRITE_HEIGHT)
+ button.addHighlightTex(
+ pauseIconPressedTex,
+ 0.0f,
+ 0.0f,
+ GameConfig.ScoreBar.PauseButton.SPRITE_WIDTH,
+ GameConfig.ScoreBar.PauseButton.SPRITE_HEIGHT)
+ button.setClickListener(listener, message)
+ return button
+ }
+
+ fun makeSpeakerOnButton(listener: Widget.WidgetTriggerListener, message: Int): Button {
+ return makeSpeakerOnOrMuteButton(false, listener, message)
+ }
+
+ fun makeSpeakerMuteButton(listener: Widget.WidgetTriggerListener, message: Int): Button {
+ return makeSpeakerOnOrMuteButton(true, listener, message)
+ }
+
+ fun makePauseCurtain(): GameObject {
+ val o = world.newGameObject(GameConfig.TYPE_DECOR, 0.0f, 0.0f)
+ val sp = o.getSprite(o.addSprite())
+ sp!!.width = renderer.width + 0.1f // safety margin
+ sp.height = renderer.height + 0.1f // safety margin
+ sp.color = GameConfig.PauseScreen.CURTAIN_COLOR
+ sp.tintFactor = 0.0f
+ return o
+ }
+
+ fun makeBigPlayButton(listener: Widget.WidgetTriggerListener, message: Int): Button {
+ val x = renderer.getRelativePos(
+ GameConfig.PauseScreen.BigPlayButton.X_REL,
+ GameConfig.PauseScreen.BigPlayButton.X_DELTA)
+ val y = renderer.getRelativePos(
+ GameConfig.PauseScreen.BigPlayButton.Y_REL,
+ GameConfig.PauseScreen.BigPlayButton.Y_DELTA)
+ val button = Button(
+ renderer,
+ x,
+ y,
+ GameConfig.PauseScreen.BigPlayButton.WIDTH,
+ GameConfig.PauseScreen.BigPlayButton.HEIGHT)
+ button.addNormalTex(
+ bigPlayButtonNormalTex,
+ 0.0f,
+ 0.0f,
+ GameConfig.PauseScreen.BigPlayButton.SPRITE_WIDTH,
+ java.lang.Float.NaN)
+ button.addHighlightTex(
+ bigPlayButtonHighlightTex,
+ 0.0f,
+ 0.0f,
+ GameConfig.PauseScreen.BigPlayButton.SPRITE_WIDTH,
+ java.lang.Float.NaN)
+ button.setClickListener(listener, message)
+ return button
+ }
+
+ fun makeQuitButton(listener: Widget.WidgetTriggerListener, message: Int): Button {
+ val x = renderer.getRelativePos(
+ GameConfig.PauseScreen.QuitBar.X_REL,
+ GameConfig.PauseScreen.QuitBar.X_DELTA)
+ val y = renderer.getRelativePos(
+ GameConfig.PauseScreen.QuitBar.Y_REL,
+ GameConfig.PauseScreen.QuitBar.Y_DELTA)
+ val button = Button(
+ renderer,
+ x,
+ y,
+ GameConfig.PauseScreen.QuitBar.WIDTH,
+ GameConfig.PauseScreen.QuitBar.HEIGHT)
+ button.addNormalTex(
+ quitBarTex, 0.0f, 0.0f, GameConfig.PauseScreen.QuitBar.SPRITE_WIDTH,
+ java.lang.Float.NaN)
+ button.addHighlightTex(
+ quitBarPressedTex,
+ 0.0f,
+ 0.0f,
+ GameConfig.PauseScreen.QuitBar.SPRITE_WIDTH,
+ java.lang.Float.NaN)
+ button.setClickListener(listener, message)
+ return button
+ }
+}
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackActivity.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackActivity.kt
new file mode 100644
index 000000000..5214d0d30
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackActivity.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.os.Bundle
+import com.google.android.apps.playgames.simpleengine.Scene
+import com.google.android.apps.playgames.simpleengine.SceneManager
+import com.google.android.apps.santatracker.util.MeasurementManager
+import com.google.firebase.analytics.FirebaseAnalytics
+
+class JetpackActivity : SceneActivity(), SensorEventListener {
+ private lateinit var firebaseAnalytics: FirebaseAnalytics
+ private lateinit var sensorManager: SensorManager
+
+ override val gameScene: Scene
+ get() = JetpackScene()
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // App Measurement
+ firebaseAnalytics = FirebaseAnalytics.getInstance(this)
+ MeasurementManager.recordScreenView(
+ firebaseAnalytics,
+ getString(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .string
+ .analytics_screen_jetpack))
+
+ var presentIsLarge = false
+ if (intent != null && intent.extras != null) {
+ presentIsLarge = intent
+ .extras!!
+ .getBoolean(
+ getString(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .string
+ .extra_large_present_key),
+ false)
+ }
+
+ SceneManager.getInstance().largePresentMode = presentIsLarge
+
+ sensorManager = getSystemService(android.app.Activity.SENSOR_SERVICE) as SensorManager
+ }
+
+ override fun getLayoutId(): Int {
+ return R.layout.activity_jetpack
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
+ if (sensor != null) {
+ sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST)
+ }
+ }
+
+ override fun onPause() {
+ super.onPause()
+ sensorManager.unregisterListener(this)
+ }
+
+ override fun onBackPressed() {
+ var handled = false
+ val scene = SceneManager.getInstance().currentScene
+ if (scene is JetpackScene) {
+ handled = scene.onBackKeyPressed()
+ }
+ if (!handled) {
+ super.onBackPressed()
+ }
+ }
+
+ override fun onSensorChanged(event: SensorEvent) {
+ SceneManager.getInstance().onSensorChanged(event)
+ }
+
+ override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) = Unit
+
+ override fun getGameId(): String {
+ return getString(com.google.android.apps.playgames.R.string.jetpack_game_id)
+ }
+
+ override fun getGameTitle(): String {
+ return getString(com.google.android.apps.santatracker.common.R.string.elf_jetpack)
+ }
+
+ companion object {
+ internal const val JETPACK_SCORE = "jetpack_score"
+ }
+}
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackConfig.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackConfig.kt
new file mode 100644
index 000000000..a38b98823
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackConfig.kt
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+object JetpackConfig {
+
+ // background music resource id
+ const val BGM_RES_ID = com.google.android.apps.santatracker.R.raw.santatracker_musicloop
+
+ // leaderboard
+ const val LEADERBOARD = R.string.leaderboard_jetpack_high_scores
+
+ // player settings
+ object Player {
+ const val WIDTH = 0.15f
+ const val INJURED_WIDTH = 0.26f
+ const val COLLIDER_WIDTH = 0.15f
+ const val COLLIDER_HEIGHT = 0.20f
+ const val MAX_SPEED = 20.0f
+
+ // how large is the "no fly zone" near the edges of the screen, where
+ // the player can't go
+ const val HORIZ_MOVEMENT_MARGIN = COLLIDER_WIDTH / 2
+ const val VERT_MOVEMENT_MARGIN = COLLIDER_HEIGHT / 2 + 0.08f
+
+ object SpriteAngle {
+ // the sprite angle is proportional to how far the player is from the target position
+ const val ANGLE_CONST = 5000.0f
+ // per 1.0 units of distance from target
+ const val MAX_ANGLE = 22.0f
+ const val MAX_CHANGE_RATE = 600.0f
+ const val FILTER_SAMPLES = 2
+ }
+
+ // jetpack fire animation
+ object Fire {
+ const val WIDTH = 0.4f * Player.WIDTH
+ const val ANIM_PERIOD = 0.5f
+ const val ANIM_AMPLITUDE = 0.05f
+ }
+ }
+
+ // input settings
+ object Input {
+ const val SENSOR_SENSITIVITY = 0.002f
+ const val KEY_SENSIVITY = 0.05f
+ const val X_ZERO_BUFFER_ZONE = 0.1f
+
+ object Sensor {
+ fun transformX(x: Float): Float {
+ var sensorX = x
+ sensorX = Math.max(Math.min(6f, sensorX), -6f)
+ when {
+ Math.abs(sensorX) < X_ZERO_BUFFER_ZONE -> sensorX = 0f
+ sensorX > 0 -> sensorX -= X_ZERO_BUFFER_ZONE
+ sensorX < 0 -> sensorX += X_ZERO_BUFFER_ZONE
+ }
+ return sensorX * JetpackConfig.Input.SENSOR_SENSITIVITY
+ }
+ }
+ }
+
+ // item settings
+ object Items {
+ const val CANDY_WIDTH = 0.05f
+ const val CANDY_COLLIDER_HEIGHT = CANDY_WIDTH * 2
+ const val CANDY_COLLIDER_WIDTH = 0.1f
+ const val PRESENT_WIDTH = 0.12f
+ const val PRESENT_COLLIDER_WIDTH = 0.10f
+ const val PRESENT_COLLIDER_HEIGHT = PRESENT_COLLIDER_WIDTH * 2
+ const val SMALL_WIDTH = 0.05f
+ const val SMALL_COLLIDER_WIDTH = 0.05f
+ const val SMALL_COLLIDER_HEIGHT = SMALL_COLLIDER_WIDTH * 2
+
+ // item spawn settings
+ const val SPAWN_INTERVAL = 0.4f
+ const val SPAWN_Y = 0.8f
+ const val FALL_SPEED_MIN = 0.2f
+ const val FALL_SPEED_MAX = 0.35f
+ const val FALL_SPEED_LEVEL_MULT = 1.05f
+ const val DELETE_Y = -0.8f
+
+ // what's the initial value for the small items?
+ const val BASE_VALUE = 1
+
+ // index of the "base value" variable of an item
+ const val IVAR_BASE_VALUE = 0
+
+ // index of the "item type" integer variable of an item
+ const val IVAR_TYPE = 1
+
+ // candy rotational speed
+ const val CANDY_ROTATE_SPEED = 180.0f
+
+ // maximum interval between two item collections for them to be
+ // considered a combo
+ const val COMBO_INTERVAL = 0.25f
+ }
+
+ object ComboPopup {
+ const val SIZE = 0.1f
+ const val VEL_Y = GameConfig.ScorePopup.POPUP_VEL_Y * 0.3f
+ }
+
+ object Clouds {
+ const val COUNT = 6
+ const val WIDTH = 0.2f
+ const val SPAWN_Y = 0.8f
+ const val SPEED_MIN = 0.3f
+ const val SPEED_MAX = 0.5f
+ const val DELETE_Y = -0.8f
+ }
+
+ object Time {
+ // how much time the player has at the beginning
+ const val INITIAL = 10.0f
+
+ // maximum remaining time player can have
+ const val MAX = INITIAL * 3
+
+ // how many seconds are recovered by picking up an item, at the beginning of the game
+ const val RECOVERED_BY_ITEM = 2.0f
+
+ // by how many seconds the time reward decreases per level gained
+ const val RECOVERED_DECREASE_PER_LEVEL = 0.5f
+
+ // the minimum # of seconds recovered by catching a present
+ const val RECOVERED_MIN = 1.0f
+
+ // the # of seconds that hitting coal reduces the time by
+ const val COAL_TIME_PENALTY = 5.0f
+
+ // the # of seconds that a player looks injured after getting hit by a bad item
+ const val HIT_TIME = 0.5f
+
+ // the # of millis that device vibrates - SMALL
+ const val VIBRATE_SMALL: Long = 40
+ }
+
+ object Progression {
+ // how many items must be collected to go up a level?
+ const val ITEMS_PER_LEVEL = 10
+ // by how much the score multiplier increases when we go up a level?
+ const val SCORE_LEVEL_MULT = 1.5f
+ }
+
+ // Achievements
+ object Achievements {
+
+ // combo-based achievements
+ val COMBO_ACHS = intArrayOf(R.string.achievement_jetpack_2_combo,
+ R.string.achievement_jetpack_3_combo, R.string.achievement_jetpack_4_combo)
+
+ // score-based
+ val SCORE_ACHS = intArrayOf(R.string.achievement_jetpack_beginner_score_500,
+ R.string.achievement_jetpack_intermediate_score_1000,
+ R.string.achievement_jetpack_pro_score_5000,
+ R.string.achievement_jetpack_advanced_score_10000,
+ R.string.achievement_jetpack_expert_score_50000)
+
+ // score necessary for the corresponding SCORE_ACHS achievement
+ val SCORE_FOR_ACH = intArrayOf(500, 1000, 5000, 10000, 50000)
+
+ // flight time achievements (one increment = one second)
+ val TOTAL_TIME_ACHS = intArrayOf(R.string.achievement_jetpack_flight_time_15,
+ R.string.achievement_jetpack_flight_time_30,
+ R.string.achievement_jetpack_flight_time_60)
+
+ // total presents achievements
+ val TOTAL_PRESENTS_ACHS = intArrayOf(R.string.achievement_jetpack_a_dozen_presents,
+ R.string.achievement_jetpack_a_dozen_dozen_presents)
+
+ // total candy achievements
+ val TOTAL_CANDY_ACHS = intArrayOf(R.string.achievement_jetpack_candy_for_one_month_30,
+ R.string.achievement_jetpack_candy_for_one_year_365)
+
+ // interval between consecutive sending of incremental achievements
+ val INC_ACH_SEND_INTERVAL = 15.0f
+ }
+}
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackObjectFactory.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackObjectFactory.kt
new file mode 100644
index 000000000..f2d59167a
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackObjectFactory.kt
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+import com.google.android.apps.playgames.simpleengine.Renderer
+import com.google.android.apps.playgames.simpleengine.game.GameObject
+import com.google.android.apps.playgames.simpleengine.game.World
+import java.util.GregorianCalendar
+import java.util.Random
+
+class JetpackObjectFactory internal constructor(
+ private var renderer: Renderer,
+ private var world: World
+) {
+ private val random = Random()
+
+ // Textures
+ private var texPlayer: Int = 0
+ private var texItemCandy: IntArray? = null
+ private var texItemCoal: IntArray? = null
+ private var texItemPresent: IntArray? = null
+ private var texCloud: Int = 0
+ private var comboTex: IntArray? = null
+ private var texFire: Int = 0
+ private var texPlayerHitOverlay: Int = 0
+ private var texPlayerHit: Int = 0
+ private var texBackground: Int = 0
+
+ private val backgroundFromCurrentTime: Int
+ get() {
+ val calendar = GregorianCalendar()
+ val hour = calendar.get(GregorianCalendar.HOUR_OF_DAY)
+ return if (hour in 6..20) {
+ com.google.android.apps.santatracker.common.R.drawable.jetpack_background_day
+ } else {
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .drawable
+ .jetpack_background_evening
+ }
+ }
+
+ internal fun makePlayer(): GameObject {
+ val p = world.newGameObjectWithImage(
+ JetpackScene.TYPE_PLAYER,
+ 0.0f,
+ renderer.bottom + JetpackConfig.Player.VERT_MOVEMENT_MARGIN,
+ texPlayer,
+ JetpackConfig.Player.WIDTH,
+ java.lang.Float.NaN)
+ p.setBoxCollider(JetpackConfig.Player.COLLIDER_WIDTH, JetpackConfig.Player.COLLIDER_HEIGHT)
+
+ p.getSprite(p.addSprite()).apply {
+ texIndex = texFire
+ width = JetpackConfig.Player.Fire.WIDTH
+ height = java.lang.Float.NaN
+ tintFactor = 0.0f
+ }
+ return p
+ }
+
+ internal fun makePlayerHit(p: GameObject) {
+ p.deleteSprites()
+
+ p.getSprite(p.addSprite()).apply {
+ texIndex = texPlayerHit
+ width = JetpackConfig.Player.INJURED_WIDTH
+ height = java.lang.Float.NaN
+ tintFactor = 0.0f
+ }
+
+ p.getSprite(p.addSprite()).apply {
+ texIndex = texFire
+ width = JetpackConfig.Player.Fire.WIDTH
+ height = java.lang.Float.NaN
+ tintFactor = 0.0f
+ }
+ }
+
+ internal fun recoverPlayerHit(p: GameObject) {
+ p.deleteSprites()
+
+ p.getSprite(p.addSprite()).apply {
+ texIndex = texPlayer
+ width = JetpackConfig.Player.WIDTH
+ height = java.lang.Float.NaN
+ tintFactor = 0.0f
+ }
+
+ p.getSprite(p.addSprite()).apply {
+ texIndex = texFire
+ width = JetpackConfig.Player.Fire.WIDTH
+ height = java.lang.Float.NaN
+ tintFactor = 0.0f
+ }
+ }
+
+ private fun getItemTypeGivenProbs(coal: Float, candy: Float, presents: Float): Int {
+ val randFloat = random.nextFloat()
+ return when {
+ randFloat < coal -> ITEM_COAL
+ randFloat < coal + candy -> ITEM_CANDY
+ else -> ITEM_PRESENT
+ }
+ }
+
+ private fun getItemType(bigPresentMode: Boolean, currentScore: Float): Int {
+ return if (bigPresentMode) {
+ when {
+ currentScore < 10 -> getItemTypeGivenProbs(0f, 0f, 1.00f)
+ currentScore < 20 -> getItemTypeGivenProbs(.1f, .4f, .5f)
+ currentScore < 30 -> getItemTypeGivenProbs(.15f, .45f, .40f)
+ currentScore < 40 -> getItemTypeGivenProbs(.2f, .45f, .35f)
+ currentScore < 50 -> getItemTypeGivenProbs(.25f, .45f, .3f)
+ else -> getItemTypeGivenProbs(.3f, .4f, .30f)
+ }
+ } else {
+ when {
+ currentScore < 10 -> getItemTypeGivenProbs(0f, 0.25f, 0.75f)
+ currentScore < 20 -> getItemTypeGivenProbs(.1f, .55f, .35f)
+ currentScore < 30 -> getItemTypeGivenProbs(.15f, .60f, .25f)
+ currentScore < 40 -> getItemTypeGivenProbs(.2f, .60f, .20f)
+ currentScore < 50 -> getItemTypeGivenProbs(.25f, .55f, .2f)
+ else -> getItemTypeGivenProbs(.3f, .50f, .2f)
+ }
+ }
+ }
+
+ fun makeBackground(): GameObject {
+ return world.newGameObjectWithImage(
+ GameConfig.TYPE_DECOR,
+ 0.0f,
+ 0.0f,
+ texBackground,
+ renderer.width + 0.02f,
+ renderer.height + 0.02f)
+ }
+
+ internal fun makeRandomItem(
+ fallSpeedMultiplier: Float,
+ bigPresentMode: Boolean,
+ currentScore: Float
+ ): GameObject {
+ val minX = renderer.left + 2 * JetpackConfig.Items.PRESENT_WIDTH
+ val maxX = renderer.right - 2 * JetpackConfig.Items.PRESENT_WIDTH
+ val x = minX + random.nextFloat() * (maxX - minX)
+ // 0 is candy, 1 is coal, 2 is present
+ val itemType = getItemType(bigPresentMode, currentScore)
+ val itemSubtype = random.nextInt(4) // one of the 4 subtypes
+
+ val tex: Int
+ val width: Float
+ val colliderWidth: Float
+ val colliderHeight: Float
+ var p: GameObject?
+ when (itemType) {
+ ITEM_CANDY -> {
+ val texItemCandySnapshot = texItemCandy ?: throw IllegalStateException()
+ tex = texItemCandySnapshot[itemSubtype]
+ width = JetpackConfig.Items.CANDY_WIDTH
+ colliderWidth = JetpackConfig.Items.CANDY_COLLIDER_WIDTH
+ colliderHeight = JetpackConfig.Items.CANDY_COLLIDER_HEIGHT
+ p = world.newGameObjectWithImage(
+ JetpackScene.TYPE_GOOD_ITEM,
+ x,
+ JetpackConfig.Items.SPAWN_Y,
+ tex,
+ width,
+ java.lang.Float.NaN).apply {
+ ivar[JetpackConfig.Items.IVAR_BASE_VALUE] = JetpackConfig.Items.BASE_VALUE
+ }
+ }
+ ITEM_COAL -> {
+ val texItemCoalSnapshot = texItemCoal ?: throw IllegalStateException()
+ tex = texItemCoalSnapshot[0]
+ width = JetpackConfig.Items.SMALL_WIDTH
+ colliderWidth = JetpackConfig.Items.SMALL_COLLIDER_WIDTH
+ colliderHeight = JetpackConfig.Items.SMALL_COLLIDER_HEIGHT
+ p = world.newGameObjectWithImage(
+ JetpackScene.TYPE_BAD_ITEM,
+ x,
+ JetpackConfig.Items.SPAWN_Y,
+ tex,
+ width,
+ java.lang.Float.NaN).apply {
+ ivar[JetpackConfig.Items.IVAR_BASE_VALUE] = -JetpackConfig.Items.BASE_VALUE
+ }
+ }
+ ITEM_PRESENT -> {
+ val texItemPresentSnapshot = texItemPresent ?: throw IllegalStateException()
+ tex = texItemPresentSnapshot[itemSubtype]
+ width = JetpackConfig.Items.PRESENT_WIDTH
+ colliderWidth = JetpackConfig.Items.PRESENT_COLLIDER_WIDTH
+ colliderHeight = JetpackConfig.Items.PRESENT_COLLIDER_HEIGHT
+ p = world.newGameObjectWithImage(
+ JetpackScene.TYPE_GOOD_ITEM,
+ x,
+ JetpackConfig.Items.SPAWN_Y,
+ tex,
+ width,
+ java.lang.Float.NaN).apply {
+ ivar[JetpackConfig.Items.IVAR_BASE_VALUE] = JetpackConfig.Items.BASE_VALUE * 2
+ }
+ }
+ else -> {
+ val texItemPresentSnapshot = texItemPresent ?: throw IllegalStateException()
+ tex = texItemPresentSnapshot[itemSubtype]
+ width = JetpackConfig.Items.PRESENT_WIDTH
+ colliderWidth = JetpackConfig.Items.PRESENT_COLLIDER_WIDTH
+ colliderHeight = JetpackConfig.Items.PRESENT_COLLIDER_HEIGHT
+ p = world.newGameObjectWithImage(JetpackScene.TYPE_GOOD_ITEM, x,
+ JetpackConfig.Items.SPAWN_Y, tex, width, java.lang.Float.NaN).apply {
+ ivar[JetpackConfig.Items.IVAR_BASE_VALUE] = JetpackConfig.Items.BASE_VALUE * 2
+ }
+ }
+ }
+
+ p.velY =
+ -(JetpackConfig.Items.FALL_SPEED_MIN + random.nextFloat() * (JetpackConfig.Items.FALL_SPEED_MAX - JetpackConfig.Items.FALL_SPEED_MIN))
+ p.velY *= fallSpeedMultiplier
+ p.setBoxCollider(colliderWidth, colliderHeight)
+ p.ivar[JetpackConfig.Items.IVAR_TYPE] = itemType
+ p.bringToFront()
+ return p
+ }
+
+ internal fun makeCloud(): GameObject {
+ return world.newGameObjectWithImage(
+ GameConfig.TYPE_DECOR,
+ 0.0f,
+ 0.0f,
+ texCloud,
+ JetpackConfig.Clouds.WIDTH,
+ java.lang.Float.NaN)
+ }
+
+ internal fun makeComboPopup(comboItems: Int, x: Float, y: Float): GameObject {
+ val comboTex = comboTex ?: throw IllegalStateException()
+ var i = comboItems - 2
+ i = if (i < 0) 0 else if (i >= comboTex.size) comboTex.size - 1 else i
+ val o = world.newGameObjectWithImage(
+ GameConfig.TYPE_DECOR,
+ x,
+ y,
+ comboTex[i],
+ JetpackConfig.ComboPopup.SIZE,
+ java.lang.Float.NaN)
+ o.velY = JetpackConfig.ComboPopup.VEL_Y
+ o.timeToLive = GameConfig.ScorePopup.POPUP_EXPIRE
+ return o
+ }
+
+ fun requestTextures() {
+ // request player texture
+ texPlayer = renderer.requestImageTex(
+ R.drawable.jetpack_player,
+ "jetpack_player",
+ Renderer.DIM_WIDTH,
+ JetpackConfig.Player.WIDTH)
+
+ // request item textures
+ texItemCandy = IntArray(4)
+ val texItemCandySnapshot = texItemCandy ?: throw IllegalStateException()
+ var i = 0
+ for (resId in intArrayOf(R.drawable.jetpack_candy1, R.drawable.jetpack_candy2,
+ R.drawable.jetpack_candy3, R.drawable.jetpack_candy4)) {
+ texItemCandySnapshot[i++] = renderer.requestImageTex(
+ resId, "candy", Renderer.DIM_WIDTH, JetpackConfig.Items.CANDY_WIDTH)
+ }
+ texItemPresent = IntArray(4)
+ val texItemPresentSnapshot = texItemPresent ?: throw IllegalStateException()
+ i = 0
+ for (resId in intArrayOf(R.drawable.jetpack_present1, R.drawable.jetpack_present2,
+ R.drawable.jetpack_present3, R.drawable.jetpack_present4)) {
+ texItemPresentSnapshot[i++] = renderer.requestImageTex(
+ resId,
+ "present",
+ Renderer.DIM_WIDTH,
+ JetpackConfig.Items.PRESENT_WIDTH)
+ }
+
+ i = 0
+ val coalDrawables = intArrayOf(R.drawable.jetpack_coal)
+ texItemCoal = IntArray(coalDrawables.size)
+ val texItemCoalSnapshot = texItemCoal ?: throw IllegalStateException()
+ for (resId in coalDrawables) {
+ texItemCoalSnapshot[i++] = renderer.requestImageTex(
+ resId, "small", Renderer.DIM_WIDTH, JetpackConfig.Items.SMALL_WIDTH)
+ }
+
+ texCloud = renderer.requestImageTex(
+ R.drawable.jetpack_cloud,
+ "jetpack_cloud",
+ Renderer.DIM_WIDTH,
+ JetpackConfig.Clouds.WIDTH)
+
+ texBackground = renderer.requestImageTex(
+ backgroundFromCurrentTime,
+ "jetpack_background",
+ Renderer.DIM_WIDTH,
+ renderer.width)
+
+ comboTex = IntArray(3).apply {
+ this[0] = renderer.requestImageTex(
+ R.drawable.jetpack_combo_2x,
+ "jetpack_combo_2x",
+ Renderer.DIM_WIDTH,
+ JetpackConfig.ComboPopup.SIZE)
+ this[1] = renderer.requestImageTex(
+ R.drawable.jetpack_combo_3x,
+ "jetpack_combo_3x",
+ Renderer.DIM_WIDTH,
+ JetpackConfig.ComboPopup.SIZE)
+ this[2] = renderer.requestImageTex(
+ R.drawable.jetpack_combo_4x,
+ "jetpack_combo_4x",
+ Renderer.DIM_WIDTH,
+ JetpackConfig.ComboPopup.SIZE)
+ }
+
+ texFire = renderer.requestImageTex(
+ R.drawable.jetpack_fire,
+ "jetpack_fire",
+ Renderer.DIM_WIDTH,
+ JetpackConfig.Player.Fire.WIDTH)
+ texPlayerHit = renderer.requestImageTex(
+ R.drawable.jetpack_player_hit,
+ "jetpack_player_hit",
+ Renderer.DIM_WIDTH,
+ JetpackConfig.Player.WIDTH)
+ texPlayerHitOverlay = renderer.requestImageTex(
+ R.drawable.jetpack_player_hit_overlay,
+ "jetpack_player_hit_overlay",
+ Renderer.DIM_WIDTH,
+ JetpackConfig.Player.WIDTH)
+ }
+
+ companion object {
+
+ // item subtypes
+ const val ITEM_PRESENT = 0
+ const val ITEM_CANDY = 1
+ const val ITEM_COAL = 2
+ }
+}
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackScene.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackScene.kt
new file mode 100644
index 000000000..c88ef2a1d
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/JetpackScene.kt
@@ -0,0 +1,613 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+import android.view.KeyEvent
+import com.google.android.apps.playgames.simpleengine.Logger
+import com.google.android.apps.playgames.simpleengine.SceneManager
+import com.google.android.apps.playgames.simpleengine.SmoothValue
+import com.google.android.apps.playgames.simpleengine.game.GameObject
+import java.util.ArrayList
+import java.util.HashSet
+
+class JetpackScene : BaseScene() {
+
+ // player
+ private lateinit var playerObj: GameObject
+
+ // background
+ private lateinit var background: GameObject
+
+ // our object factory
+ private lateinit var factory: JetpackObjectFactory
+
+ // current difficulty level
+ private var level = 1
+
+ // player is currently injured
+ private var playerHit = false
+
+ // time remaining of player's injury
+ private var playerHitTime = JetpackConfig.Time.HIT_TIME
+
+ // total items collected
+ private var itemsCollected = 0
+
+ // item fall speed multipler (increases with level)
+ private var fallMult = 3.0f
+
+ // score multipler (increases with level)
+ private var scoreMult = 1.0f
+
+ private var spriteAngle = SmoothValue(
+ 0.0f,
+ JetpackConfig.Player.SpriteAngle.MAX_CHANGE_RATE,
+ -JetpackConfig.Player.SpriteAngle.MAX_ANGLE,
+ JetpackConfig.Player.SpriteAngle.MAX_ANGLE,
+ JetpackConfig.Player.SpriteAngle.FILTER_SAMPLES)
+
+ private var playerTargetX = 0.0f
+ private var playerTargetY = 0.0f
+
+ // working array
+ private var tmpList = ArrayList()
+
+ // how long til we spawn the next item?
+ private var spawnCountdown = JetpackConfig.Items.SPAWN_INTERVAL
+
+ // cloud sprites
+ private var cloudObj = arrayOfNulls(JetpackConfig.Clouds.COUNT)
+
+ // time remaining
+ override var displayedTime = JetpackConfig.Time.INITIAL
+
+ // sfx IDs
+ private lateinit var itemSfxSuccess: IntArray
+
+ private val combo = Combo()
+
+ // set of achievements we know we unlocked (to prevent repeated API calls)
+ private val unlockedAchievements = HashSet()
+
+ // achievement increments we are pending to send
+ private var achPendingPresents = 0
+ private var achPendingCandy = 0
+ private var achPendingSeconds = 0f
+
+ // countdown to next sending of incremental achievements
+ private var incAchCountdown = JetpackConfig.Achievements.INC_ACH_SEND_INTERVAL
+
+ // what pointer Id is the one that's steering the elf
+ private var activePointerId = -1
+
+ // accumulated play time
+ private var playTime = 0.0f
+
+ override val bgmResId = JetpackConfig.BGM_RES_ID
+
+ // current combo
+ private inner class Combo {
+
+ internal var items = 0
+ internal var countdown = 0.0f
+ internal var centroidX: Float = 0.toFloat()
+ internal var centroidY: Float = 0.toFloat()
+ internal var points: Float = 0.toFloat()
+ internal var timeRecovery: Float = 0.toFloat()
+
+ internal fun reset() {
+ items = 0
+ timeRecovery = 0.0f
+ points = timeRecovery
+ centroidY = points
+ centroidX = centroidY
+ countdown = centroidX
+ }
+ }
+
+ override fun makeNewScene(): BaseScene {
+ return JetpackScene()
+ }
+
+ override fun onInstall() {
+ super.onInstall()
+ factory = JetpackObjectFactory(renderer, world)
+ factory.requestTextures()
+ background = factory.makeBackground()
+ background.sendToBack()
+
+ playerObj = factory.makePlayer()
+ playerTargetX = 0.0f
+ playerTargetY = renderer.bottom + JetpackConfig.Player.VERT_MOVEMENT_MARGIN
+ val soundManager = SceneManager.getInstance().soundManager
+ itemSfxSuccess = IntArray(3).apply {
+ this[0] = soundManager.requestSfx(R.raw.jetpack_score1)
+ this[1] = soundManager.requestSfx(R.raw.jetpack_score2)
+ this[2] = soundManager.requestSfx(R.raw.jetpack_score3)
+ }
+ SceneManager.getInstance().vibrator
+ // start paused
+ startGameScreen()
+ }
+
+ override fun isGameEnded(): Boolean {
+ return gameEnded
+ }
+
+ override fun doFrame(deltaT: Float) {
+ if (!paused) {
+ if (!gameEnded) {
+ playTime += deltaT
+ updatePlayer(deltaT)
+ if (!playerHit) {
+ detectCollectedItems()
+ }
+ updatePlayerHit(deltaT)
+ updateTimeRemaining(deltaT)
+ updateCombo(deltaT)
+ checkLevelUp()
+ achPendingSeconds += deltaT
+ }
+ updateClouds()
+ updateCandy(deltaT)
+ killMissedPresents()
+
+ incAchCountdown -= deltaT
+ sendIncrementalAchievements(false)
+
+ spawnCountdown -= deltaT
+ if (!isInGameEndingTransition && spawnCountdown < 0.0f) {
+ spawnCountdown = JetpackConfig.Items.SPAWN_INTERVAL
+ factory.makeRandomItem(
+ fallMult,
+ SceneManager.getInstance().largePresentMode,
+ displayedScore.value)
+ }
+ super.doFrame(deltaT)
+ }
+ if (inStartCountdown) {
+ updatePlayer(deltaT)
+ val newCount = startCountdownTimeRemaining - deltaT
+ if (newCount <= 0) {
+ inStartCountdown = false
+ unPauseGame()
+ } else if (newCount.toInt() < startCountdownTimeRemaining.toInt()) {
+ digitFactory.setDigit(countdownDigitObj, Math.min(newCount.toInt() + 1, 3))
+ countdownDigitObj?.bringToFront()
+ }
+ startCountdownTimeRemaining = newCount
+ }
+ if (gameEnded) {
+ goToEndGame()
+ }
+ }
+
+ override fun endGame() {
+ isInGameEndingTransition = true
+
+ // force send all incremental achievements
+ sendIncrementalAchievements(true)
+
+ // submit our score
+ submitScore(JetpackConfig.LEADERBOARD, score)
+
+ // Start end game activity
+ onWidgetTriggered(BaseScene.MSG_GO_TO_END_GAME)
+ }
+
+ private fun updateTimeRemaining(deltaT: Float) {
+ displayedTime -= deltaT
+ if (displayedTime < 0.0f && !isInGameEndingTransition) {
+ endGame()
+ }
+ }
+
+ private fun updatePlayerHit(deltaT: Float) {
+ playerHitTime -= deltaT
+ if (playerHitTime < 0.0f && playerHit) {
+ factory.recoverPlayerHit(playerObj)
+ playerHit = false
+ }
+ }
+
+ private fun sineWave(period: Float, amplitude: Float, t: Float): Float {
+ return Math.sin(2.0 * Math.PI * t.toDouble() / period).toFloat() * amplitude
+ }
+
+ private fun updatePlayer(deltaT: Float) {
+ spriteAngle.target = (playerObj.x - playerTargetX) *
+ JetpackConfig.Player.SpriteAngle.ANGLE_CONST
+ spriteAngle.update(deltaT)
+ playerObj.getSprite(0)!!.rotation = spriteAngle.value
+ playerObj.getSprite(1)!!.rotation = spriteAngle.value
+ playerObj.getSprite(1)!!.width = JetpackConfig.Player.Fire.WIDTH * (1.0f + sineWave(
+ JetpackConfig.Player.Fire.ANIM_PERIOD,
+ JetpackConfig.Player.Fire.ANIM_AMPLITUDE,
+ playTime))
+ playerObj.getSprite(1)!!.height = java.lang.Float.NaN // proportional to width
+
+ if (isTv) {
+ // On TV, player moves based on its speed.
+ playerObj.displaceBy(playerObj.velX * deltaT, playerObj.velY * deltaT)
+ } else {
+ playerObj.displaceTowards(
+ playerTargetX, playerTargetY, deltaT * JetpackConfig.Player.MAX_SPEED)
+ }
+ }
+
+ private fun updateClouds() {
+ var i = 0
+ while (i < cloudObj.size) {
+ var o: GameObject? = cloudObj[i]
+ if (o == null) {
+ o = factory.makeCloud()
+ cloudObj[i] = o
+ setupNewCloud(o)
+ } else if (o.y < JetpackConfig.Clouds.DELETE_Y) {
+ setupNewCloud(o)
+ }
+ i++
+ }
+ }
+
+ private fun updateCombo(deltaT: Float) {
+ combo.countdown -= deltaT
+ if (combo.items > 0 && combo.countdown <= 0.0f) {
+ endCombo()
+ }
+ }
+
+ private fun isCandy(o: GameObject): Boolean {
+ return o.type == TYPE_GOOD_ITEM && o.ivar[JetpackConfig.Items.IVAR_TYPE] == JetpackObjectFactory.ITEM_CANDY
+ }
+
+ private fun isPresent(o: GameObject): Boolean {
+ return o.type == TYPE_GOOD_ITEM && o.ivar[JetpackConfig.Items.IVAR_TYPE] == JetpackObjectFactory.ITEM_PRESENT
+ }
+
+ private fun isCoal(o: GameObject): Boolean {
+ return o.type == TYPE_BAD_ITEM && o.ivar[JetpackConfig.Items.IVAR_TYPE] == JetpackObjectFactory.ITEM_COAL
+ }
+
+ private fun updateCandy(deltaT: Float) {
+ var i = 0
+ while (i < world.gameObjects.size) {
+ val o = world.gameObjects[i]
+ if (isCandy(o)) {
+ o.getSprite(0)!!.rotation += deltaT * JetpackConfig.Items.CANDY_ROTATE_SPEED
+ }
+ i++
+ }
+ }
+
+ private fun setupNewCloud(o: GameObject) {
+ o.displaceTo(
+ renderer.left + random.nextFloat() * (renderer.right - renderer.left),
+ JetpackConfig.Clouds.SPAWN_Y)
+ o.velY =
+ -(JetpackConfig.Clouds.SPEED_MIN + random.nextFloat() * (JetpackConfig.Clouds.SPEED_MAX - JetpackConfig.Clouds.SPEED_MIN))
+ }
+
+ private fun killMissedPresents() {
+ var i = 0
+ while (i < world.gameObjects.size) {
+ val o = world.gameObjects[i]
+ if ((o.type == TYPE_GOOD_ITEM || o.type == TYPE_BAD_ITEM) && o.y < JetpackConfig.Items.DELETE_Y) {
+ o.dead = true
+ }
+ i++
+ }
+ }
+
+ private fun addScore(score: Float) {
+ this.score += score.toInt()
+ unlockScoreBasedAchievements()
+ }
+
+ private fun addTime(time: Float) {
+ displayedTime += time
+ if (displayedTime > JetpackConfig.Time.MAX) {
+ displayedTime = JetpackConfig.Time.MAX
+ }
+ }
+
+ private fun pickUpItem(item: GameObject) {
+ val value = item.ivar[JetpackConfig.Items.IVAR_BASE_VALUE]
+ if (isCoal(item)) {
+ factory.makePlayerHit(playerObj)
+ playerHit = true
+ playerHitTime = JetpackConfig.Time.HIT_TIME
+ objectFactory.makeScorePopup(item.x, item.y, value, digitFactory)
+ SceneManager.getInstance()
+ .soundManager
+ .playSfx(itemSfxSuccess[random.nextInt(itemSfxSuccess.size)])
+ SceneManager.getInstance().vibrator.vibrate(JetpackConfig.Time.VIBRATE_SMALL)
+ addTime(-JetpackConfig.Time.COAL_TIME_PENALTY)
+ } else {
+ if (isCandy(item)) {
+ achPendingCandy++
+ } else if (isPresent(item)) {
+ achPendingPresents++
+ }
+ objectFactory.makeScorePopup(item.x, item.y, value, digitFactory)
+ SceneManager.getInstance()
+ .soundManager
+ .playSfx(itemSfxSuccess[random.nextInt(itemSfxSuccess.size)])
+
+ val timeRecovery = Math.max(JetpackConfig.Time.RECOVERED_BY_ITEM -
+ level * JetpackConfig.Time.RECOVERED_DECREASE_PER_LEVEL,
+ JetpackConfig.Time.RECOVERED_MIN)
+ addTime(timeRecovery)
+
+ combo.centroidX = (combo.centroidX * combo.items + item.x) / (combo.items + 1)
+ combo.centroidY = (combo.centroidY * combo.items + item.y) / (combo.items + 1)
+ combo.items++
+ combo.countdown = JetpackConfig.Items.COMBO_INTERVAL
+ combo.points += value
+ combo.timeRecovery = timeRecovery
+ }
+ item.dead = true
+ itemsCollected++
+
+ addScore(value.toFloat())
+
+ // play sfx
+ }
+
+ private fun detectCollectedItems() {
+ world.detectCollisions(playerObj, tmpList, true)
+ var i = 0
+ while (i < tmpList.size) {
+ val o = tmpList[i]
+ if (o.type == TYPE_GOOD_ITEM || o.type == TYPE_BAD_ITEM) {
+ pickUpItem(o)
+ }
+ i++
+ }
+ }
+
+ private fun endCombo() {
+ if (combo.items > 1) {
+ factory.makeComboPopup(combo.items, combo.centroidX, combo.centroidY)
+
+ // give bonus
+ addScore(combo.points * combo.items)
+ addTime(combo.timeRecovery * combo.items)
+
+ // unlock combo-based achievements
+ unlockComboBasedAchievements(combo.items)
+ }
+ combo.reset()
+ }
+
+ override fun onPointerDown(pointerId: Int, x: Float, y: Float) {
+ super.onPointerDown(pointerId, x, y)
+ if (activePointerId < 0) {
+ activePointerId = pointerId
+ }
+ }
+
+ override fun onPointerUp(pointerId: Int, x: Float, y: Float) {
+ super.onPointerUp(pointerId, x, y)
+ if (activePointerId == pointerId) {
+ activePointerId = -1
+ }
+ }
+
+ override fun onPointerMove(pointerId: Int, x: Float, y: Float, deltaX: Float, deltaY: Float) {
+ super.onPointerMove(pointerId, x, y, deltaX, deltaY)
+
+ // if paused, do nothing.
+ if (paused) {
+ return
+ }
+
+ // if no finger owns the steering of the elf, adopt this one.
+ if (activePointerId < 0) {
+ activePointerId = pointerId
+ }
+ }
+
+ override fun onKeyDown(keyCode: Int, repeatCount: Int) {
+
+ when (keyCode) {
+ KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_BUTTON_A -> onConfirmKeyPressed()
+ KeyEvent.KEYCODE_BUTTON_B -> onBackKeyPressed()
+ }
+
+ if (!paused) {
+ val absVelocity =
+ JetpackConfig.Player.WIDTH * (1.5f + repeatCount.toFloat() * JetpackConfig.Input.KEY_SENSIVITY)
+ when (keyCode) {
+ KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_LEFT -> {
+ playerTargetX -= 0.17f
+ playerObj.velX = -absVelocity
+ }
+ KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_RIGHT -> {
+ playerTargetX += 0.17f
+ playerObj.velX = absVelocity
+ }
+ }
+ // don't let the player wander off screen
+ limitPlayerMovement()
+ }
+ }
+
+ override fun onKeyUp(keyCode: Int) {
+ when (keyCode) {
+ KeyEvent.KEYCODE_DPAD_UP -> {
+ // if it's going up, stop it.
+ playerTargetY = playerObj.y
+ if (playerObj.velY > 0) {
+ playerObj.velY = 0f
+ }
+ }
+ KeyEvent.KEYCODE_DPAD_DOWN -> {
+ // if it's going down, stop it.
+ playerTargetY = playerObj.y
+ if (playerObj.velY < 0) {
+ playerObj.velY = 0f
+ }
+ }
+ KeyEvent.KEYCODE_DPAD_LEFT -> {
+ // if it's going left, stop it.
+ playerTargetX = playerObj.x
+ if (playerObj.velX < 0) {
+ playerObj.velX = 0f
+ }
+ }
+ KeyEvent.KEYCODE_DPAD_RIGHT -> {
+ // if it's going right, stop it.
+ playerTargetX = playerObj.x
+ if (playerObj.velX > 0) {
+ playerObj.velX = 0f
+ }
+ }
+ }
+
+ // don't let the player wander off screen
+ limitPlayerMovement()
+ }
+
+ override fun onSensorChanged(x: Float, y: Float, accuracy: Int) {
+ playerTargetX += JetpackConfig.Input.Sensor.transformX(x)
+ // don't let the player wander off screen
+ limitPlayerMovement()
+ }
+
+ private fun limitPlayerMovement() {
+ val minX = renderer.left + JetpackConfig.Player.HORIZ_MOVEMENT_MARGIN
+ val maxX = renderer.right - JetpackConfig.Player.HORIZ_MOVEMENT_MARGIN
+ val minY = renderer.bottom + JetpackConfig.Player.VERT_MOVEMENT_MARGIN
+ val maxY = renderer.top - JetpackConfig.Player.VERT_MOVEMENT_MARGIN
+
+ if (isTv) {
+ playerObj.velX = when {
+ playerObj.x + playerObj.velX < minX -> minX - playerObj.x
+ playerObj.x + playerObj.velX > maxX -> maxX - playerObj.x
+ else -> playerObj.velX
+ }
+
+ playerObj.velY = when {
+ playerObj.y + playerObj.velY < minY -> minY - playerObj.y
+ playerObj.y + playerObj.velY > maxY -> maxY - playerObj.y
+ else -> playerObj.velY
+ }
+ } else {
+ playerTargetX =
+ if (playerTargetX < minX) minX else if (playerTargetX > maxX) maxX else playerTargetX
+ playerTargetY =
+ if (playerTargetY < minY) minY else if (playerTargetY > maxY) maxY else playerTargetY
+ }
+ }
+
+ private fun checkLevelUp() {
+ val dueLevel = itemsCollected / JetpackConfig.Progression.ITEMS_PER_LEVEL
+ while (level < dueLevel) {
+ level++
+ Logger.d("Level up! Now at level $level")
+ fallMult *= JetpackConfig.Items.FALL_SPEED_LEVEL_MULT
+ scoreMult *= JetpackConfig.Progression.SCORE_LEVEL_MULT
+ }
+ }
+
+ private fun unlockScoreBasedAchievements() {
+ var i = 0
+ while (i < JetpackConfig.Achievements.SCORE_ACHS.size) {
+ if (score >= JetpackConfig.Achievements.SCORE_FOR_ACH[i]) {
+ unlockAchievement(JetpackConfig.Achievements.SCORE_ACHS[i])
+ }
+ i++
+ }
+ }
+
+ private fun unlockComboBasedAchievements(comboSize: Int) {
+ var i = 0
+ while (i < JetpackConfig.Achievements.COMBO_ACHS.size) {
+ // COMBO_ACHS[n] is the achievement to unlock for a combo of size n + 2
+ if (comboSize >= i + 2) {
+ unlockAchievement(JetpackConfig.Achievements.COMBO_ACHS[i])
+ }
+ i++
+ }
+ }
+
+ private fun sendIncrementalAchievements(force: Boolean) {
+ if (!force && incAchCountdown > 0.0f) {
+ // it's not time to send yet
+ return
+ }
+ if (SceneManager.getInstance().activity == null) {
+ // no Activity (maybe we're in the background), so can't send yet
+ return
+ }
+
+ if (achPendingCandy > 0) {
+ incrementAchievements(JetpackConfig.Achievements.TOTAL_CANDY_ACHS, achPendingCandy)
+ achPendingCandy = 0
+ }
+ if (achPendingPresents > 0) {
+ incrementAchievements(
+ JetpackConfig.Achievements.TOTAL_PRESENTS_ACHS, achPendingPresents)
+ achPendingPresents = 0
+ }
+ if (achPendingSeconds >= 1.0f) {
+ val seconds = Math.floor(achPendingSeconds.toDouble()).toInt()
+ incrementAchievements(JetpackConfig.Achievements.TOTAL_TIME_ACHS, seconds)
+ achPendingSeconds -= seconds.toFloat()
+ }
+
+ // submit score as well, since we're at it.
+ submitScore(JetpackConfig.LEADERBOARD, score)
+
+ // reset countdown
+ incAchCountdown = JetpackConfig.Achievements.INC_ACH_SEND_INTERVAL
+ }
+
+ private fun unlockAchievement(resId: Int) {
+ val act = SceneManager.getInstance().activity as SceneActivity
+ if (!unlockedAchievements.contains(resId)) {
+ act.postUnlockAchievement(resId)
+ unlockedAchievements.add(resId)
+ }
+ }
+
+ private fun incrementAchievements(resId: IntArray, steps: Int) {
+ for (i in resId) {
+ incrementAchievement(i, steps)
+ }
+ }
+
+ private fun incrementAchievement(resId: Int, steps: Int) {
+ val act = SceneManager.getInstance().activity as SceneActivity
+ if (steps > 0) {
+ act.postIncrementAchievement(resId, steps)
+ }
+ }
+
+ private fun submitScore(resId: Int, score: Int) {
+ val act = SceneManager.getInstance().activity as SceneActivity
+ act.postSubmitScore(resId, score.toLong())
+ }
+
+ companion object {
+ // GameObject types:
+ internal const val TYPE_PLAYER = 0
+ internal const val TYPE_GOOD_ITEM = 1
+ internal const val TYPE_BAD_ITEM = 2
+ }
+}
diff --git a/jetpack/src/main/java/com/google/android/apps/jetpack/SceneActivity.kt b/jetpack/src/main/java/com/google/android/apps/jetpack/SceneActivity.kt
new file mode 100644
index 000000000..415123787
--- /dev/null
+++ b/jetpack/src/main/java/com/google/android/apps/jetpack/SceneActivity.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.jetpack
+
+import android.app.Activity
+import android.os.Bundle
+import android.os.Handler
+import android.view.View
+import androidx.core.os.postDelayed
+import com.google.android.apps.jetpack.JetpackActivity.Companion.JETPACK_SCORE
+import com.google.android.apps.playgames.common.PlayGamesActivity
+import com.google.android.apps.playgames.simpleengine.Scene
+import com.google.android.apps.playgames.simpleengine.SceneManager
+import com.google.android.apps.santatracker.games.EndOfGameView
+import com.google.android.apps.santatracker.invites.AppInvitesFragment
+
+abstract class SceneActivity : PlayGamesActivity() {
+
+ private var invitesFragment: AppInvitesFragment? = null
+ private var gameEndedListener: GameEndedListener? = null
+
+ protected abstract val gameScene: Scene
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState == null) {
+ SceneManager.getInstance().requestNewScene(gameScene)
+ }
+
+ invitesFragment = AppInvitesFragment.getInstance(this)
+ }
+
+ override fun onWindowFocusChanged(hasFocus: Boolean) {
+ super.onWindowFocusChanged(hasFocus)
+ SceneManager.getInstance().onFocusChanged(hasFocus)
+ }
+
+ public override fun onPause() {
+ super.onPause()
+ SceneManager.getInstance().onPause()
+ }
+
+ public override fun onResume() {
+ super.onResume()
+ SceneManager.getInstance().onResume(this)
+ if (SceneManager.getInstance().currentScene?.isGameEnded == true) {
+ postGoToEndGame()
+ }
+ }
+
+ override fun onSignInFailed() {
+ super.onSignInFailed()
+
+ // communicate to the BaseScene that we are no longer signed in
+ val s = SceneManager.getInstance().currentScene
+ if (s is BaseScene) {
+ s.setSignedIn(false)
+ }
+ }
+
+ override fun onSignInSucceeded() {
+ super.onSignInSucceeded()
+
+ // communicate to the BaseScene that we are no longer signed in
+ val s = SceneManager.getInstance().currentScene
+ if (s is BaseScene) {
+ s.setSignedIn(true)
+ }
+ }
+
+ override fun launchStartupActivity() {
+ finish()
+ }
+
+ fun postQuitGame() {
+ runOnUiThread { launchStartupActivity() }
+ }
+
+ fun postReturnWithScore(score: Int) {
+ runOnUiThread { returnWithScore(score) }
+ }
+
+ private fun returnWithScore(score: Int) {
+ val intent = this.intent
+ intent.putExtra(JETPACK_SCORE, score)
+ this.setResult(Activity.RESULT_OK, intent)
+ finish()
+ }
+
+ fun setGameEndedListener(gameEndedListener: GameEndedListener) {
+ this.gameEndedListener = gameEndedListener
+ }
+
+ fun postDelayedGoToEndGame(delay: Int) {
+ runOnUiThread {
+ Handler().postDelayed(delay.toLong()) {
+ gameEndedListener?.let {
+ it.onGameEnded()
+ goToEndGame(it.score)
+ }
+ }
+ }
+ }
+
+ fun postGoToEndGame() {
+ runOnUiThread {
+ gameEndedListener?.let {
+ val score = it.score
+ it.onGameEnded()
+ goToEndGame(score)
+ }
+ }
+ }
+
+ private fun replay() {
+ val gameView = findViewById(R.id.jetpack_end_game_view)
+ gameView.visibility = View.INVISIBLE
+ SceneManager.getInstance().requestNewScene(gameScene)
+ }
+
+ private fun goToEndGame(score: Int) {
+ // Show the end-game view
+ val gameView = findViewById(R.id.jetpack_end_game_view)
+ gameView.initialize(
+ score,
+ { replay() },
+ { returnWithScore(score) })
+ gameView.visibility = View.VISIBLE
+ }
+
+ fun share() {
+ invitesFragment?.sendGenericInvite()
+ }
+}
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_candy1.png b/jetpack/src/main/res/drawable-nodpi/jetpack_candy1.png
new file mode 100644
index 000000000..43ef34a1e
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_candy1.png differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_candy2.png b/jetpack/src/main/res/drawable-nodpi/jetpack_candy2.png
new file mode 100644
index 000000000..27dc37b70
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_candy2.png differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_candy3.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_candy3.webp
new file mode 100644
index 000000000..2539c7cae
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_candy3.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_candy4.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_candy4.webp
new file mode 100644
index 000000000..9f66ba9d1
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_candy4.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_clock.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_clock.webp
new file mode 100644
index 000000000..b5194717e
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_clock.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_cloud.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_cloud.webp
new file mode 100644
index 000000000..724780b25
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_cloud.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_coal.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_coal.webp
new file mode 100644
index 000000000..ab16bd4b0
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_coal.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_combo_2x.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_combo_2x.webp
new file mode 100644
index 000000000..f731d81aa
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_combo_2x.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_combo_3x.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_combo_3x.webp
new file mode 100644
index 000000000..d83a47f4d
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_combo_3x.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_combo_4x.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_combo_4x.webp
new file mode 100644
index 000000000..b1aa2657b
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_combo_4x.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_fire.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_fire.webp
new file mode 100644
index 000000000..a3482baaa
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_fire.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_player.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_player.webp
new file mode 100644
index 000000000..32bd3e3d7
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_player.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_player_hit.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_player_hit.webp
new file mode 100644
index 000000000..351f8bfb6
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_player_hit.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_player_hit_overlay.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_player_hit_overlay.webp
new file mode 100644
index 000000000..124207d06
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_player_hit_overlay.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_podium.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_podium.webp
new file mode 100644
index 000000000..7b0944cf1
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_podium.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_present1.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_present1.webp
new file mode 100644
index 000000000..532476ea4
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_present1.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_present2.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_present2.webp
new file mode 100644
index 000000000..5b05b2c7d
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_present2.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_present3.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_present3.webp
new file mode 100644
index 000000000..64413382d
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_present3.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_present4.png b/jetpack/src/main/res/drawable-nodpi/jetpack_present4.png
new file mode 100644
index 000000000..2c85bf0a0
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_present4.png differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_signin.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_signin.webp
new file mode 100644
index 000000000..7c01dc87b
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_signin.webp differ
diff --git a/jetpack/src/main/res/drawable-nodpi/jetpack_signin_pressed.webp b/jetpack/src/main/res/drawable-nodpi/jetpack_signin_pressed.webp
new file mode 100644
index 000000000..dff705b0a
Binary files /dev/null and b/jetpack/src/main/res/drawable-nodpi/jetpack_signin_pressed.webp differ
diff --git a/jetpack/src/main/res/layout/activity_jetpack.xml b/jetpack/src/main/res/layout/activity_jetpack.xml
new file mode 100644
index 000000000..087daf675
--- /dev/null
+++ b/jetpack/src/main/res/layout/activity_jetpack.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/santa-tracker/src/main/res/raw/jetpack_score1.mp3 b/jetpack/src/main/res/raw/jetpack_score1.mp3
similarity index 100%
rename from santa-tracker/src/main/res/raw/jetpack_score1.mp3
rename to jetpack/src/main/res/raw/jetpack_score1.mp3
diff --git a/santa-tracker/src/main/res/raw/jetpack_score2.mp3 b/jetpack/src/main/res/raw/jetpack_score2.mp3
similarity index 100%
rename from santa-tracker/src/main/res/raw/jetpack_score2.mp3
rename to jetpack/src/main/res/raw/jetpack_score2.mp3
diff --git a/santa-tracker/src/main/res/raw/jetpack_score3.mp3 b/jetpack/src/main/res/raw/jetpack_score3.mp3
similarity index 100%
rename from santa-tracker/src/main/res/raw/jetpack_score3.mp3
rename to jetpack/src/main/res/raw/jetpack_score3.mp3
diff --git a/jetpack/src/main/res/values/colors.xml b/jetpack/src/main/res/values/colors.xml
new file mode 100644
index 000000000..56165f71c
--- /dev/null
+++ b/jetpack/src/main/res/values/colors.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/jetpack/src/main/res/values/game_ids_jetpack.xml b/jetpack/src/main/res/values/game_ids_jetpack.xml
new file mode 100644
index 000000000..f215d5b11
--- /dev/null
+++ b/jetpack/src/main/res/values/game_ids_jetpack.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+CgkIioKF2qwCEAIQAg
+CgkIioKF2qwCEAIQAw
+CgkIioKF2qwCEAIQBA
+CgkIioKF2qwCEAIQBg
+CgkIioKF2qwCEAIQBw
+CgkIioKF2qwCEAIQCA
+CgkIioKF2qwCEAIQCQ
+CgkIioKF2qwCEAIQCg
+CgkIioKF2qwCEAIQCw
+CgkIioKF2qwCEAIQDA
+CgkIioKF2qwCEAIQDQ
+CgkIioKF2qwCEAIQDg
+CgkIioKF2qwCEAIQDw
+CgkIioKF2qwCEAIQEA
+CgkIioKF2qwCEAIQEQ
+CgkIioKF2qwCEAIQEg
+
+
diff --git a/jetpack/src/main/res/values/styles.xml b/jetpack/src/main/res/values/styles.xml
new file mode 100644
index 000000000..6c65774ee
--- /dev/null
+++ b/jetpack/src/main/res/values/styles.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/jetpack/src/release/res/values/game_ids.xml b/jetpack/src/release/res/values/game_ids.xml
new file mode 100644
index 000000000..7b545187a
--- /dev/null
+++ b/jetpack/src/release/res/values/game_ids.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ 80719462666
+ CgkIioKF2qwCEAIQEw
+ CgkIioKF2qwCEAIQFA
+
diff --git a/jetpack/src/release/res/values/game_ids_jetpack.xml b/jetpack/src/release/res/values/game_ids_jetpack.xml
new file mode 100644
index 000000000..f215d5b11
--- /dev/null
+++ b/jetpack/src/release/res/values/game_ids_jetpack.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+CgkIioKF2qwCEAIQAg
+CgkIioKF2qwCEAIQAw
+CgkIioKF2qwCEAIQBA
+CgkIioKF2qwCEAIQBg
+CgkIioKF2qwCEAIQBw
+CgkIioKF2qwCEAIQCA
+CgkIioKF2qwCEAIQCQ
+CgkIioKF2qwCEAIQCg
+CgkIioKF2qwCEAIQCw
+CgkIioKF2qwCEAIQDA
+CgkIioKF2qwCEAIQDQ
+CgkIioKF2qwCEAIQDg
+CgkIioKF2qwCEAIQDw
+CgkIioKF2qwCEAIQEA
+CgkIioKF2qwCEAIQEQ
+CgkIioKF2qwCEAIQEg
+
+
diff --git a/memory/build.gradle b/memory/build.gradle
new file mode 100644
index 000000000..e4cd2fdcb
--- /dev/null
+++ b/memory/build.gradle
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
+apply plugin: 'com.android.dynamic-feature'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.tools
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
+ }
+}
+
+dependencies {
+ implementation project(':santa-tracker')
+}
diff --git a/memory/src/main/AndroidManifest.xml b/memory/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..c970988e5
--- /dev/null
+++ b/memory/src/main/AndroidManifest.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/memory/src/main/java/com/google/android/apps/memory/MemoryActivity.java b/memory/src/main/java/com/google/android/apps/memory/MemoryActivity.java
new file mode 100644
index 000000000..b430e7ec9
--- /dev/null
+++ b/memory/src/main/java/com/google/android/apps/memory/MemoryActivity.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.memory;
+
+import android.os.Bundle;
+import com.google.android.apps.playgames.common.PlayGamesActivity;
+import com.google.android.apps.santatracker.util.MeasurementManager;
+import com.google.firebase.analytics.FirebaseAnalytics;
+
+public class MemoryActivity extends PlayGamesActivity {
+
+ private MemoryMatchFragment mMemoryMatchFragment;
+ private FirebaseAnalytics mMeasurement;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mMemoryMatchFragment = MemoryMatchFragment.newInstance();
+ this.getSupportFragmentManager()
+ .beginTransaction()
+ .replace(
+ com.google.android.apps.playgames.R.id.mainFragmentContainer,
+ mMemoryMatchFragment)
+ .commit();
+
+ // App Measurement
+ mMeasurement = FirebaseAnalytics.getInstance(this);
+ MeasurementManager.recordScreenView(
+ mMeasurement,
+ getString(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .string
+ .analytics_screen_memory));
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mMemoryMatchFragment != null) {
+ mMemoryMatchFragment.onBackKeyPressed();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.activity_memory;
+ }
+
+ @Override
+ public void onSignInSucceeded() {
+ super.onSignInSucceeded();
+ mMemoryMatchFragment.onSignInSucceeded();
+ }
+
+ @Override
+ public String getGameId() {
+ return getResources().getString(com.google.android.apps.playgames.R.string.memory_game_id);
+ }
+
+ @Override
+ public String getGameTitle() {
+ return getString(com.google.android.apps.santatracker.common.R.string.memory);
+ }
+
+ @Override
+ public void onSignInFailed() {
+ super.onSignInFailed();
+ mMemoryMatchFragment.onSignInFailed();
+ }
+}
diff --git a/memory/src/main/java/com/google/android/apps/memory/MemoryCard.java b/memory/src/main/java/com/google/android/apps/memory/MemoryCard.java
new file mode 100644
index 000000000..0147b7608
--- /dev/null
+++ b/memory/src/main/java/com/google/android/apps/memory/MemoryCard.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.memory;
+
+import android.view.View;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Card in the memory game. Contains the front of the card (the card image) and its back (its
+ * cloak).
+ */
+public class MemoryCard {
+
+ public int mCardImageId;
+ public int mCardCloakId;
+ public View mView;
+
+ public MemoryCard(int cardImageId, int cardCloakId) {
+ mCardImageId = cardImageId;
+ mCardCloakId = cardCloakId;
+ }
+
+ /**
+ * Generate a randomised list of {@link
+ * com.google.android.apps.santatracker.games.matching.MemoryCard}s.
+ *
+ * @param numCards Number of cards to generate
+ * @param cardImages List of card image references
+ * @param cardCloaks List of card cloak image references
+ */
+ public static ArrayList getGameCards(
+ int numCards, List cardImages, List cardCloaks) {
+ Collections.shuffle(cardImages);
+ Collections.shuffle(cardCloaks);
+ ArrayList cards = new ArrayList();
+ for (int i = 0; i < (numCards / 2); i++) {
+ cards.add(new MemoryCard(cardImages.get(i), cardCloaks.get(i)));
+ cards.add(new MemoryCard(cardImages.get(i), cardCloaks.get(i)));
+ }
+ Collections.shuffle(cards);
+ return cards;
+ }
+}
diff --git a/memory/src/main/java/com/google/android/apps/memory/MemoryMatchFragment.java b/memory/src/main/java/com/google/android/apps/memory/MemoryMatchFragment.java
new file mode 100644
index 000000000..7ff9d02e8
--- /dev/null
+++ b/memory/src/main/java/com/google/android/apps/memory/MemoryMatchFragment.java
@@ -0,0 +1,1070 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.memory;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Drawable.Callback;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.SoundPool;
+import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationSet;
+import android.view.animation.AnimationUtils;
+import android.view.animation.TranslateAnimation;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+import androidx.fragment.app.Fragment;
+import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
+import com.google.android.apps.playgames.Utils;
+import com.google.android.apps.playgames.common.GameConstants;
+import com.google.android.apps.playgames.common.PlayGamesActivity;
+import com.google.android.apps.playgames.customviews.CircleView;
+import com.google.android.apps.playgames.customviews.LevelTextView;
+import com.google.android.apps.santatracker.common.CheckableImageButton;
+import com.google.android.apps.santatracker.data.SantaPreferences;
+import com.google.android.apps.santatracker.invites.AppInvitesFragment;
+import com.google.android.apps.santatracker.util.ImmersiveModeHelper;
+import com.google.android.apps.santatracker.util.SoundPoolUtils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/** Fragment that contains the memory match game. */
+public class MemoryMatchFragment extends Fragment
+ implements OnClickListener, AnimationListener, Callback {
+
+ /** Drawables for all card faces. */
+ private static final Integer[] CARD_FACE_DRAWABLES =
+ new Integer[] {
+ R.drawable.mmg_card_ball, R.drawable.mmg_card_balloon,
+ R.drawable.mmg_card_beachball,
+ R.drawable.mmg_card_candle, R.drawable.mmg_card_globe, R.drawable.mmg_card_gumball,
+ R.drawable.mmg_card_penguin, R.drawable.mmg_card_rabbit,
+ R.drawable.mmg_card_reindeer,
+ R.drawable.mmg_card_snowman, R.drawable.mmg_card_tree, R.drawable.mmg_card_trophy
+ };
+ /** Drawables for all card face cloaks (background color). */
+ private static final Integer[] CARD_CLOAK_DRAWABLES =
+ new Integer[] {
+ R.drawable.mmg_card_cloak_blue_dark, R.drawable.mmg_card_cloak_blue_light,
+ R.drawable.mmg_card_cloak_orange, R.drawable.mmg_card_cloak_purple,
+ R.drawable.mmg_card_cloak_red, R.drawable.mmg_card_cloak_orange
+ };
+
+ private static final int DOOR_CLOSE_DELAY_MILLIS = 1500;
+
+ /** Current game level. */
+ private int mLevelNumber = 1;
+
+ /** Number of correct moves required for this level. */
+ private int mCorrectMovesRequired = 0;
+
+ /** Count of correct moves in this level so far. */
+ private int mCurrentCorrectMoves = 0;
+
+ /** Total score of the game so far. */
+ private int mMatchScore = 0;
+
+ /** Count of the number of wrong selections in the level so far. */
+ private int mWrongAnswers = 0;
+
+ /** First card that has been selected and is visible. */
+ private View mVisibleCard1 = null;
+
+ /** Second card that has been selected and is visible. */
+ private View mVisibleCard2 = null;
+
+ /** First card that was visible and is being animated to become hidden again. */
+ private View mHiddenCard1;
+
+ /** Second card that was visible and is being animated to become hidden again. */
+ private View mHiddenCard2;
+
+ /** Views that represent the cards (doors) on screen. */
+ private View[] mViewCard = new View[12];
+
+ /** List of card faces. This list is shuffled before each level. */
+ private List mCardFaceIds = Arrays.asList(CARD_FACE_DRAWABLES);
+
+ /** List of card cloaks (backgrounds). This list is shuffled before each level. */
+ private List mCardCloakIds = Arrays.asList(CARD_CLOAK_DRAWABLES);
+
+ /** Time left in the game in milliseconds. */
+ private long mTimeLeftInMillis = GameConstants.MATCH_INIT_TIME;
+ /** Countdown timer refresh interval in milliseconds. */
+ private long mCountDownInterval = 1000;
+ /** Countdown timer that drives the game logic. */
+ private GameCountdown mCountDownTimer = null;
+ /**
+ * Flag to indicate the state of this Fragment and stop the game correctly when the countdown
+ * expires.
+ */
+ private boolean wasPaused = false;
+
+ private Animation mAnimationRightPaneSlideOut;
+ private Animation mAnimationLeftPaneSlideOut;
+ private Animation mAnimationLeftPaneSlideIn;
+ private Animation mAnimationRightPaneSlideIn;
+ private Animation mAnimationScaleLevelDown;
+ private Animation mAnimationLevelFadeOut;
+ private Animation mAnimationLevelScaleUp;
+ private Animation mAnimationPlayAgainBackground;
+ private Animation mAnimationPlayAgainMain;
+ private Animation mAnimationCardCover;
+ private TranslateAnimation mAnimationSnowman;
+ private Animation mAnimationTimerAlpha;
+ private TranslateAnimation mAnimationSnowmanBack;
+ private AnimationSet mAnimationSetSnowman;
+
+ private CircleView mEndLevelCircle;
+ private TextView mScoreText;
+ private LevelTextView mLevelNumberText;
+
+ private int mSoundDoorOpen = -1;
+ private int mSoundDoorClose = -1;
+ private int mSoundMatchWrong = -1;
+ private int mSoundMatchRight = -1;
+ private int mSoundBeep = -1;
+ private int mSoundGameOver = -1;
+ private MediaPlayer mBackgroundMusic;
+ private SoundPool mSoundPool;
+ private Handler mDoorCloseHandler;
+ private Runnable mDoorCloseRunnable;
+ private boolean mDoorCloseTimerTicking = false;
+ private long mDoorCloseTimerStart = 0;
+ private long mDoorCloseTimeRemaining = DOOR_CLOSE_DELAY_MILLIS;
+
+ private TextView mTimerTextView;
+ private View mViewPlayAgainBackground;
+ private View mViewPlayAgainMain;
+ private TextView mTextPlayAgainScore;
+ private TextView mTextPlayAgainLevel;
+ private ImageView mButtonPlay;
+ private ImageView mButtonPause;
+ private ImageButton mButtonBigPlay;
+ private Button mPlayAgainBtn;
+ private ImageButton mButtonCancelBar;
+ private ImageButton mButtonMenu;
+ private ImageView mInviteButton;
+ private ImageView mViewInstructions;
+ private View mViewPauseOverlay;
+ private View mViewBonusSnowman;
+ private AnimationDrawable mInstructionDrawable;
+ private ImageView mViewGPlusSignIn;
+ private View mLayoutGPlus;
+
+ /** Handler that dismisses the game instructions when the game is started for the first time. */
+ private Handler mDelayHandler = new Handler();
+
+ /**
+ * Handler and Runnable to fix the occasional "nothing is clickable" bug, The timeout is set as
+ * slightly longer than our max animation duration.
+ */
+ private static final long ANIMATION_TIMEOUT = 1005;
+
+ private Handler mClickabilityHandler = new Handler();
+ private Runnable mMakeClickableRunnable =
+ new Runnable() {
+ @Override
+ public void run() {
+ isClickable = true;
+ }
+ };
+
+ /** Preferences that store whether the game instructions have been viewed. */
+ private SharedPreferences mPreferences;
+
+ /**
+ * Indicates whether the screen is clickable. It is disabled when a full screen animation is in
+ * progress at the end of the level or at the end of the game.
+ */
+ private boolean isClickable = true;
+
+ private AppInvitesFragment mInvitesFragment;
+
+ private CheckableImageButton mMuteButton;
+ private SantaPreferences mSantaPreferences;
+
+ /** Create a new instance of this fragment. */
+ public static MemoryMatchFragment newInstance() {
+ return new MemoryMatchFragment();
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mSantaPreferences = new SantaPreferences(context);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_memory_match, container, false);
+ rootView.setKeepScreenOn(true);
+
+ // Initialise the sound pool and all sound effects
+ mSoundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
+ mSoundDoorOpen = mSoundPool.load(getActivity(), R.raw.mmg_open_door_3, 1);
+ mSoundDoorClose = mSoundPool.load(getActivity(), R.raw.mmg_close_door, 1);
+ mSoundMatchWrong = mSoundPool.load(getActivity(), R.raw.mmg_wrong, 1);
+ mSoundMatchRight = mSoundPool.load(getActivity(), R.raw.mmg_right, 1);
+ mSoundGameOver =
+ mSoundPool.load(getActivity(), com.google.android.apps.playgames.R.raw.gameover, 1);
+ mSoundBeep = mSoundPool.load(getActivity(), R.raw.mmg_open_door_2, 1);
+
+ mDoorCloseHandler = new Handler();
+ mDoorCloseRunnable =
+ new Runnable() {
+ @Override
+ public void run() {
+ hideBothPreviousCards();
+ mDoorCloseTimerTicking = false;
+ mDoorCloseTimerStart = 0;
+ mDoorCloseTimeRemaining = DOOR_CLOSE_DELAY_MILLIS;
+ }
+ };
+
+ // Set up all animations.
+ loadAnimations();
+
+ // G+ sign-in views
+ mViewGPlusSignIn =
+ rootView.findViewById(com.google.android.apps.santatracker.R.id.gplus_button);
+ mViewGPlusSignIn.setOnClickListener(this);
+ mLayoutGPlus =
+ rootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_gplus);
+ mLayoutGPlus.setVisibility(View.GONE);
+
+ // 'Play again' screen views
+ mTextPlayAgainScore =
+ rootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_score);
+ mTextPlayAgainScore.setText(String.valueOf(mMatchScore));
+ mTextPlayAgainLevel =
+ rootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_level);
+ mTextPlayAgainLevel.setText(String.valueOf(mLevelNumber));
+ mViewPlayAgainBackground =
+ rootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_bkgrd);
+ mViewPlayAgainMain =
+ rootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_main);
+ mPlayAgainBtn =
+ rootView.findViewById(com.google.android.apps.santatracker.R.id.play_again_btn);
+ mPlayAgainBtn.setOnClickListener(this);
+
+ // Level, countdown and score views at the bottom of the screen
+ mTimerTextView = rootView.findViewById(R.id.match_timer);
+ mLevelNumberText = rootView.findViewById(R.id.card_end_level_number);
+ mLevelNumberText.setVisibility(View.GONE);
+ mScoreText = rootView.findViewById(R.id.match_score);
+ mScoreText.setText(String.valueOf(mMatchScore));
+
+ // End of level animated circle
+ mEndLevelCircle = rootView.findViewById(R.id.card_end_level_circle);
+ mEndLevelCircle.setVisibility(View.GONE);
+
+ // The snowman that is animated as a bonus when the player is particularly awesome
+ mViewBonusSnowman = rootView.findViewById(R.id.match_snowman);
+
+ // 'Pause' screen views
+ mButtonMenu =
+ rootView.findViewById(com.google.android.apps.santatracker.R.id.main_menu_button);
+ mButtonMenu.setOnClickListener(this);
+ mButtonMenu.setVisibility(View.GONE);
+ mInviteButton =
+ rootView.findViewById(com.google.android.apps.santatracker.R.id.invite_button);
+ mInviteButton.setOnClickListener(this);
+ mInviteButton.setVisibility(View.GONE);
+ mButtonPlay = rootView.findViewById(R.id.match_play_button);
+ mButtonPlay.setOnClickListener(this);
+ mButtonPlay.setVisibility(View.GONE);
+ mButtonPause = rootView.findViewById(R.id.match_pause_button);
+ mButtonPause.setOnClickListener(this);
+ mButtonPause.setVisibility(View.VISIBLE);
+ mViewPauseOverlay = rootView.findViewById(R.id.match_pause_overlay);
+ mViewPauseOverlay.setVisibility(View.GONE);
+ mButtonBigPlay = rootView.findViewById(R.id.match_big_play_button);
+ mButtonBigPlay.setOnClickListener(this);
+ mButtonCancelBar = rootView.findViewById(R.id.match_cancel_bar);
+ mButtonCancelBar.setOnClickListener(this);
+ mButtonCancelBar.setVisibility(View.GONE);
+
+ // Playing cards (doors)
+ mViewCard[0] = rootView.findViewById(R.id.card_position_1);
+ mViewCard[1] = rootView.findViewById(R.id.card_position_2);
+ mViewCard[2] = rootView.findViewById(R.id.card_position_3);
+ mViewCard[3] = rootView.findViewById(R.id.card_position_4);
+ mViewCard[4] = rootView.findViewById(R.id.card_position_5);
+ mViewCard[5] = rootView.findViewById(R.id.card_position_6);
+ mViewCard[6] = rootView.findViewById(R.id.card_position_7);
+ mViewCard[7] = rootView.findViewById(R.id.card_position_8);
+ mViewCard[8] = rootView.findViewById(R.id.card_position_9);
+ mViewCard[9] = rootView.findViewById(R.id.card_position_10);
+ mViewCard[10] = rootView.findViewById(R.id.card_position_11);
+ mViewCard[11] = rootView.findViewById(R.id.card_position_12);
+
+ // Display the instructions if they haven't been seen by the player yet.
+ mPreferences =
+ getActivity()
+ .getSharedPreferences(
+ GameConstants.PREFERENCES_FILENAME, Context.MODE_PRIVATE);
+ if (!mPreferences.getBoolean(GameConstants.MATCH_INSTRUCTIONS_VIEWED, false)) {
+ // Instructions haven't been viewed yet. Construct an AnimationDrawable with
+ // instructions.
+ mInstructionDrawable = new AnimationDrawable();
+ mInstructionDrawable.addFrame(
+ VectorDrawableCompat.create(
+ getResources(),
+ com.google.android.apps.playgames.R.drawable.instructions_touch_1,
+ null),
+ 300);
+ mInstructionDrawable.addFrame(
+ VectorDrawableCompat.create(
+ getResources(),
+ com.google.android.apps.playgames.R.drawable.instructions_touch_2,
+ null),
+ 300);
+ mInstructionDrawable.setOneShot(false);
+ mViewInstructions =
+ rootView.findViewById(com.google.android.apps.playgames.R.id.instructions);
+ mViewInstructions.setImageDrawable(mInstructionDrawable);
+ mInstructionDrawable.start();
+
+ // Set a timer to hide the instructions after 2 seconds
+ mViewInstructions.postDelayed(new StartGameDelay(), 2000);
+ } else {
+ // Instructions have already been viewed. Start the first level.
+ setUpLevel();
+ }
+
+ mMuteButton = rootView.findViewById(R.id.mute_button);
+ mMuteButton.setChecked(!mSantaPreferences.isMuted());
+ mMuteButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mSantaPreferences.toggleMuted();
+ mMuteButton.setChecked(!mSantaPreferences.isMuted());
+ onMuteChanged(mSantaPreferences.isMuted());
+ }
+ });
+
+ return rootView;
+ }
+
+ /** Load and initialise all animations required for the game. */
+ private void loadAnimations() {
+ mAnimationTimerAlpha = new AlphaAnimation(0.0f, 1.0f);
+ mAnimationTimerAlpha.setDuration(1000);
+ mAnimationTimerAlpha.setRepeatMode(Animation.REVERSE);
+ mAnimationTimerAlpha.setRepeatCount(Animation.INFINITE);
+
+ mAnimationPlayAgainBackground =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.play_again_bkgrd_anim);
+ mAnimationPlayAgainBackground.setFillAfter(true);
+ mAnimationPlayAgainBackground.setAnimationListener(this);
+ mAnimationCardCover =
+ AnimationUtils.loadAnimation(
+ getActivity(), com.google.android.apps.playgames.R.anim.card_answer_flash);
+ mAnimationCardCover.setFillAfter(true);
+ mAnimationPlayAgainMain =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.play_again_main_anim);
+ mAnimationPlayAgainMain.setFillAfter(true);
+ mAnimationPlayAgainMain.setAnimationListener(this);
+ // Special bonus animation to play if the player is particularly awesome.
+ mAnimationSetSnowman = new AnimationSet(true);
+ mAnimationSnowman = new TranslateAnimation(150, 0, 150, 0);
+ mAnimationSnowman.setDuration(1000);
+ mAnimationSetSnowman.addAnimation(mAnimationSnowman);
+ mAnimationSnowmanBack = new TranslateAnimation(0, 150, 0, 150);
+ mAnimationSnowmanBack.setDuration(1000);
+ mAnimationSnowmanBack.setStartOffset(1500);
+ mAnimationSnowmanBack.setAnimationListener(this);
+ mAnimationSetSnowman.addAnimation(mAnimationSnowmanBack);
+ mAnimationSetSnowman.setAnimationListener(this);
+
+ mAnimationRightPaneSlideOut =
+ AnimationUtils.loadAnimation(getActivity(), android.R.anim.slide_out_right);
+ mAnimationRightPaneSlideOut.setFillAfter(true);
+ mAnimationLeftPaneSlideOut =
+ AnimationUtils.loadAnimation(getActivity(), R.anim.left_pane_slide_out);
+ mAnimationLeftPaneSlideOut.setFillAfter(true);
+ mAnimationLeftPaneSlideIn =
+ AnimationUtils.loadAnimation(getActivity(), android.R.anim.slide_in_left);
+ mAnimationLeftPaneSlideIn.setFillAfter(true);
+ mAnimationRightPaneSlideIn =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.right_pane_slide_in);
+ mAnimationRightPaneSlideIn.setFillAfter(true);
+ mAnimationScaleLevelDown =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.scale_level_anim_down);
+ mAnimationScaleLevelDown.setAnimationListener(this);
+ mAnimationLevelFadeOut =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.level_fade_out_anim);
+ mAnimationLevelFadeOut.setAnimationListener(this);
+ mAnimationLevelScaleUp =
+ AnimationUtils.loadAnimation(
+ getActivity(),
+ com.google.android.apps.playgames.R.anim.scale_up_level_anim);
+ mAnimationLevelScaleUp.setAnimationListener(this);
+ mAnimationRightPaneSlideOut.setAnimationListener(this);
+ mAnimationLeftPaneSlideOut.setAnimationListener(this);
+ }
+
+ /**
+ * Runnable that stars the game after the instructions have been viewed. It hides the
+ * instructions, marks them as viewed and starts the game.
+ */
+ private class StartGameDelay implements Runnable {
+
+ @Override
+ public void run() {
+ // Start the first level.
+ setUpLevel();
+
+ // Hide the instructions.
+ mInstructionDrawable.stop();
+ mViewInstructions.setVisibility(View.GONE);
+ // Mark the instructions as 'viewed'.
+ Editor edit = mPreferences.edit();
+ edit.putBoolean(GameConstants.MATCH_INSTRUCTIONS_VIEWED, true);
+ edit.commit();
+ }
+ }
+
+ public void onSignInSucceeded() {
+ setSignInButtonVisibility(false);
+ }
+
+ public void onSignInFailed() {}
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ mInvitesFragment = AppInvitesFragment.getInstance(getActivity());
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ isClickable = true;
+ if (wasPaused && mViewPauseOverlay.getVisibility() != View.VISIBLE) {
+ mCountDownTimer = new GameCountdown(mTimeLeftInMillis, mCountDownInterval);
+ mCountDownTimer.start();
+ wasPaused = false;
+ }
+ if (!mSantaPreferences.isMuted()) {
+ loadBackgroundMusic();
+ }
+ updateSignInButtonVisibility();
+ }
+
+ /** Toggles visibility of the G+ sign in layout if the user is not already signed in. */
+ private void setSignInButtonVisibility(boolean show) {
+ mLayoutGPlus.setVisibility(show && !Utils.isSignedIn(this) ? View.VISIBLE : View.GONE);
+ }
+
+ private void updateSignInButtonVisibility() {
+ if (mLayoutGPlus.getVisibility() == View.VISIBLE && Utils.isSignedIn(this)) {
+ setSignInButtonVisibility(false);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ pauseGame();
+ stopBackgroundMusic();
+ if (mCountDownTimer != null && mViewPauseOverlay.getVisibility() != View.VISIBLE) {
+ mCountDownTimer.cancel();
+ wasPaused = true;
+ }
+ }
+
+ private void stopBackgroundMusic() {
+ if (mBackgroundMusic != null) {
+ mBackgroundMusic.stop();
+ mBackgroundMusic.release();
+ mBackgroundMusic = null;
+ }
+ }
+
+ private void loadBackgroundMusic() {
+ mBackgroundMusic =
+ MediaPlayer.create(
+ getActivity(),
+ com.google.android.apps.santatracker.R.raw.santatracker_musicloop);
+ mBackgroundMusic.setLooping(true);
+ mBackgroundMusic.setVolume(.1f, .1f);
+ mBackgroundMusic.start();
+ }
+
+ /**
+ * Starts the next level. Shuffles the cards, sets up the views and starts the countdown for the
+ * next level.
+ */
+ private void setUpLevel() {
+ mCurrentCorrectMoves = 0;
+ mWrongAnswers = 0;
+ if (mCountDownTimer != null) {
+ mCountDownTimer.cancel();
+ }
+
+ // Display the level number
+ mTextPlayAgainLevel.setText(String.valueOf(mLevelNumber));
+
+ // Lock all doors, unlock them individually per level later
+ for (View card : mViewCard) {
+ setUpLockedCard(card);
+ }
+
+ if (mLevelNumber > 1) {
+ // Add the 'next level' bonus time
+ mTimeLeftInMillis += GameConstants.MATCH_ADD_TIME_NEXT_LEVEL;
+ }
+
+ int pairsRequired = Math.min(mLevelNumber, 5) + 1;
+ mCorrectMovesRequired = pairsRequired;
+ ArrayList memoryCards =
+ MemoryCard.getGameCards(pairsRequired * 2, mCardFaceIds, mCardCloakIds);
+ int[] cardSlots;
+
+ if (mLevelNumber == 1) {
+ cardSlots = new int[] {2, 3, 8, 9};
+ } else if (mLevelNumber == 2) {
+ cardSlots = new int[] {0, 1, 2, 3, 4, 5};
+ } else if (mLevelNumber == 3) {
+ cardSlots = new int[] {1, 2, 3, 4, 7, 8, 9, 10};
+ } else if (mLevelNumber == 4) {
+ cardSlots = new int[] {0, 1, 2, 3, 4, 5, 7, 8, 9, 10};
+ } else {
+ cardSlots = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+ }
+ for (int i = 0; i < cardSlots.length; i++) {
+ setUpMemoryCard(mViewCard[cardSlots[i]], memoryCards.get(i));
+ }
+
+ // Start the countdown for the new level
+ mCountDownTimer = new GameCountdown(mTimeLeftInMillis, mCountDownInterval);
+ mCountDownTimer.start();
+ }
+
+ /** Sets the card displayed by this view to the 'locked' state. */
+ private void setUpLockedCard(View view) {
+ view.setOnClickListener(null);
+ view.findViewById(R.id.card_locked).setVisibility(View.VISIBLE);
+ view.findViewById(R.id.card_cloak).setVisibility(View.GONE);
+ view.findViewById(R.id.card_frame).setVisibility(View.GONE);
+ view.findViewById(R.id.card_image).setVisibility(View.GONE);
+ view.findViewById(R.id.card_pane_right).clearAnimation();
+ view.findViewById(R.id.card_pane_left).clearAnimation();
+ view.findViewById(R.id.card_pane_left).setVisibility(View.GONE);
+ view.findViewById(R.id.card_pane_right).setVisibility(View.GONE);
+ view.findViewById(R.id.card_cover).setVisibility(View.GONE);
+ }
+
+ /**
+ * Sets the viewCard that displays a card to show the face and cloaking indicated by the {@link
+ * MemoryCard}.
+ */
+ private void setUpMemoryCard(View viewCard, MemoryCard card) {
+ viewCard.setOnClickListener(this);
+ card.mView = viewCard;
+ viewCard.setTag(card);
+ viewCard.findViewById(R.id.card_locked).setVisibility(View.GONE);
+ viewCard.findViewById(R.id.card_frame).setVisibility(View.VISIBLE);
+ ((ImageView) viewCard.findViewById(R.id.card_cloak)).setImageResource(card.mCardCloakId);
+ viewCard.findViewById(R.id.card_cloak).setVisibility(View.VISIBLE);
+ ((ImageView) viewCard.findViewById(R.id.card_image)).setImageResource(card.mCardImageId);
+ viewCard.findViewById(R.id.card_image).setVisibility(View.VISIBLE);
+ viewCard.findViewById(R.id.card_pane_right).clearAnimation();
+ viewCard.findViewById(R.id.card_pane_left).clearAnimation();
+ viewCard.findViewById(R.id.card_pane_left).setVisibility(View.VISIBLE);
+ viewCard.findViewById(R.id.card_pane_right).setVisibility(View.VISIBLE);
+ viewCard.findViewById(R.id.card_cover).setVisibility(View.INVISIBLE);
+ }
+
+ /** Plays a sound unveils the given card. */
+ private void showCard(View view) {
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundDoorOpen);
+ }
+ view.findViewById(R.id.card_pane_right).startAnimation(mAnimationRightPaneSlideOut);
+
+ view.findViewById(R.id.card_pane_left).startAnimation(mAnimationLeftPaneSlideOut);
+ }
+
+ /** Plays a sound and hides the given card. */
+ private void hideCard(View view) {
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundDoorClose);
+ }
+ view.findViewById(R.id.card_pane_left).startAnimation(mAnimationLeftPaneSlideIn);
+ view.findViewById(R.id.card_pane_right).startAnimation(mAnimationRightPaneSlideIn);
+ }
+
+ @Override
+ public void onClick(View view) {
+ // Check if the cards are not currently clickable and skip if necessary.
+ if (view.getTag() != null && isClickable) {
+ // A card has been clicked.
+ onCardClick(view);
+ } else if (view.equals(mPlayAgainBtn)) {
+ // The 'play again' button has been clicked. Stop the music and restart.
+ stopBackgroundMusic();
+ if (!mSantaPreferences.isMuted()) {
+ loadBackgroundMusic();
+ }
+
+ // Reset the game state.
+ resetGameState();
+
+ // Reset the UI and clear all animations.
+ mScoreText.setText(String.valueOf(mMatchScore));
+ mTextPlayAgainScore.setText(String.valueOf(mMatchScore));
+ mViewPlayAgainBackground.clearAnimation();
+ mViewPlayAgainMain.clearAnimation();
+ mViewPlayAgainBackground.setVisibility(View.GONE);
+ mViewPlayAgainMain.setVisibility(View.GONE);
+ mButtonMenu.setVisibility(View.GONE);
+ mInviteButton.setVisibility(View.GONE);
+ setSignInButtonVisibility(false);
+ } else if (view.equals(mButtonPause)) {
+ // Pause button.
+ pauseGame();
+ } else if (view.equals(mButtonPlay) || view.equals(mButtonBigPlay)) {
+ // Play button, unmute the game.
+ resumeGame();
+ } else if (view.equals(mButtonCancelBar) || view.equals(mButtonMenu)) {
+ // Exit the game.
+ exit();
+ } else if (view.equals(mViewGPlusSignIn)) {
+ // Start sign-in flow.
+ PlayGamesActivity activity = Utils.getPlayGamesActivity(this);
+ if (activity != null) {
+ activity.startSignIn();
+ }
+ } else if (view.equals(mInviteButton)) {
+ // Send app invite
+ mInvitesFragment.sendGameInvite(
+ getString(com.google.android.apps.santatracker.common.R.string.memory),
+ getString(com.google.android.apps.playgames.R.string.memory_game_id),
+ mMatchScore);
+ }
+ }
+
+ private void resetGameState() {
+ mLevelNumber = 1;
+ mTimeLeftInMillis = GameConstants.MATCH_INIT_TIME;
+ setUpLevel();
+ mMatchScore = 0;
+ }
+
+ /**
+ * Hides the cards of the previous turn. Should be called when the previous turn was an
+ * incorrect match.
+ */
+ private void hideBothPreviousCards() {
+ if (mVisibleCard1 != null && mVisibleCard2 != null) {
+ hideCard(mVisibleCard1);
+ hideCard(mVisibleCard2);
+ mVisibleCard2.setOnClickListener(this);
+ mVisibleCard1.setOnClickListener(this);
+ mVisibleCard1 = null;
+ mVisibleCard2 = null;
+ }
+ }
+
+ /**
+ * Handles onClick events for views that represent cards. Unveils the card and checks for a
+ * match if another card has already been unveiled.
+ */
+ private void onCardClick(View view) {
+ MemoryCard card1 = (MemoryCard) view.getTag();
+ if (mVisibleCard1 != null && mVisibleCard2 != null) {
+ // Two cards are already unveiled, hide them both
+ // This is also triggered by a timer but this occurs if the user
+ // plays the next turn before the timer is up.
+ hideBothPreviousCards();
+ mVisibleCard1 = view;
+ mVisibleCard1.setOnClickListener(null);
+ showCard(mVisibleCard1);
+ } else if (mVisibleCard1 != null && mVisibleCard2 == null) {
+ // One card is already unveiled and a second one has been selected
+ MemoryCard card2 = (MemoryCard) mVisibleCard1.getTag();
+
+ if (card1.mCardImageId == card2.mCardImageId) {
+ // The second card matches the face of the first one - we have a winner!
+ mVisibleCard2 = view;
+ mVisibleCard2.setOnClickListener(null);
+ mVisibleCard1.setOnClickListener(null);
+ showCard(view);
+ if (mVisibleCard1.findViewById(R.id.card_cover).getVisibility() != View.GONE) {
+ // Play an animation to flash the background of both cards in green
+ mVisibleCard1.findViewById(R.id.card_cover).setBackgroundColor(Color.GREEN);
+ mVisibleCard2.findViewById(R.id.card_cover).setBackgroundColor(Color.GREEN);
+ mVisibleCard1.findViewById(R.id.card_cover).clearAnimation();
+ mVisibleCard2.findViewById(R.id.card_cover).clearAnimation();
+ mVisibleCard1.findViewById(R.id.card_cover).setVisibility(View.VISIBLE);
+ mVisibleCard2.findViewById(R.id.card_cover).setVisibility(View.VISIBLE);
+ mAnimationCardCover.setAnimationListener(this);
+ mHiddenCard1 = mVisibleCard1;
+ mHiddenCard2 = mVisibleCard2;
+ mVisibleCard1.findViewById(R.id.card_cover).startAnimation(mAnimationCardCover);
+ mVisibleCard2.findViewById(R.id.card_cover).startAnimation(mAnimationCardCover);
+
+ mVisibleCard2 = null;
+ mVisibleCard1 = null;
+
+ // Add the cards to the tally of correct cards
+ mCurrentCorrectMoves++;
+ increaseScoreMatch();
+
+ // Check if this level is finished
+ checkNextLevel();
+ }
+ } else {
+ // The second card does not match the first one - this is not a match.
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundMatchWrong);
+ }
+ mWrongAnswers++;
+ mVisibleCard2 = view;
+ mVisibleCard2.setOnClickListener(null);
+ showCard(mVisibleCard2);
+ // Play an animation to flash the background of both cards in red
+ mVisibleCard1.findViewById(R.id.card_cover).setBackgroundColor(Color.RED);
+ mVisibleCard2.findViewById(R.id.card_cover).setBackgroundColor(Color.RED);
+ mVisibleCard1.findViewById(R.id.card_cover).clearAnimation();
+ mVisibleCard2.findViewById(R.id.card_cover).clearAnimation();
+ mVisibleCard1.findViewById(R.id.card_cover).setVisibility(View.VISIBLE);
+ mVisibleCard2.findViewById(R.id.card_cover).setVisibility(View.VISIBLE);
+ mAnimationCardCover.setAnimationListener(null);
+ mVisibleCard1.findViewById(R.id.card_cover).startAnimation(mAnimationCardCover);
+ mVisibleCard2.findViewById(R.id.card_cover).startAnimation(mAnimationCardCover);
+
+ // 1.5 seconds after this turn was deemed incorrect, hide both cards.
+ mDoorCloseHandler.postDelayed(mDoorCloseRunnable, DOOR_CLOSE_DELAY_MILLIS);
+ mDoorCloseTimerStart = System.currentTimeMillis();
+ mDoorCloseTimerTicking = true;
+ }
+ } else {
+ // This is the first card that has been unveiled.
+ mVisibleCard1 = view;
+ mVisibleCard1.setOnClickListener(null);
+ showCard(mVisibleCard1);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (mDoorCloseHandler != null && mDoorCloseRunnable != null) {
+ mDoorCloseHandler.removeCallbacks(mDoorCloseRunnable);
+ }
+ super.onStop();
+ }
+
+ /** Advances the game to the next level if all matching pairs have been unveiled. */
+ private void checkNextLevel() {
+ if (mCurrentCorrectMoves >= mCorrectMovesRequired) {
+ // Increment the level count
+ increaseScoreLevel();
+ mLevelNumber++;
+ mLevelNumberText.setLevelNumber(mLevelNumber);
+ // Start the 'next level' animation after a short delay.
+ mDelayHandler.postDelayed(
+ new Runnable() {
+ @Override
+ public void run() {
+ mLevelNumberText.startAnimation(mAnimationLevelScaleUp);
+ mEndLevelCircle.startAnimation(mAnimationScaleLevelDown);
+ setUpLevel();
+ }
+ },
+ 750);
+ }
+ }
+
+ private void exit() {
+ getActivity().finish();
+ }
+
+ private void resumeGame() {
+ mButtonPause.setVisibility(View.VISIBLE);
+ mButtonPlay.setVisibility(View.GONE);
+ mCountDownTimer = new GameCountdown(mTimeLeftInMillis, mCountDownInterval);
+
+ // If the user had gotten the previous turn incorrect and the CloseDoor timer was
+ // ticking before the mute, continue the timer.
+ if (mDoorCloseHandler != null && mDoorCloseRunnable != null && mDoorCloseTimerTicking) {
+ mDoorCloseHandler.postDelayed(mDoorCloseRunnable, mDoorCloseTimeRemaining);
+ mDoorCloseTimerStart = System.currentTimeMillis();
+ }
+ mCountDownTimer.start();
+ mViewPauseOverlay.setVisibility(View.GONE);
+ mButtonCancelBar.setVisibility(View.GONE);
+ ImmersiveModeHelper.setImmersiveSticky(getActivity().getWindow());
+ }
+
+ /** CountDownTimer that handles the game timing logic of the memory match game. */
+ public class GameCountdown extends CountDownTimer {
+
+ private Boolean animationStarted = false;
+
+ public GameCountdown(long millisInFuture, long countDownInterval) {
+ super(millisInFuture, countDownInterval);
+ }
+
+ @Override
+ public void onFinish() {
+ // When the countdown is over, end the game.
+ mTimerTextView.clearAnimation();
+ animationStarted = false;
+ mTimerTextView.setTextColor(Color.WHITE);
+ mTimerTextView.setTypeface(Typeface.DEFAULT);
+ if (mViewPlayAgainBackground.getVisibility() != View.VISIBLE && !wasPaused) {
+ submitScore(GameConstants.LEADERBOARDS_MATCH, mMatchScore);
+ stopBackgroundMusic();
+
+ // Show the 'play again' screen.
+ mTextPlayAgainScore.setText(String.valueOf(mMatchScore));
+ mViewPlayAgainBackground.startAnimation(mAnimationPlayAgainBackground);
+ mViewPlayAgainMain.startAnimation(mAnimationPlayAgainMain);
+ mViewPlayAgainBackground.setVisibility(View.VISIBLE);
+ mViewPlayAgainMain.setVisibility(View.VISIBLE);
+ mButtonMenu.setVisibility(View.VISIBLE);
+ mInviteButton.setVisibility(View.VISIBLE);
+ setSignInButtonVisibility(true);
+
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundGameOver, 0.2f);
+ }
+ }
+ }
+
+ @Override
+ public void onTick(long millisUntilFinished) {
+
+ long seconds = TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished);
+ if (seconds >= 6) {
+ animationStarted = false;
+ mTimerTextView.clearAnimation();
+ mTimerTextView.setTypeface(Typeface.DEFAULT);
+ mTimerTextView.setTextColor(Color.WHITE);
+ } else if (!animationStarted) {
+ // Start flashing the countdown time
+ animationStarted = true;
+ mTimerTextView.setTypeface(Typeface.DEFAULT_BOLD);
+ mTimerTextView.setTextColor(Color.RED);
+ mTimerTextView.clearAnimation();
+ mTimerTextView.startAnimation(mAnimationTimerAlpha);
+ }
+
+ // Update the displayed countdown time
+ mTimeLeftInMillis = millisUntilFinished;
+ mTimerTextView.setText(
+ String.format(
+ "%d:%02d",
+ TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished),
+ seconds
+ - TimeUnit.MINUTES.toSeconds(
+ TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished))));
+ }
+ }
+
+ /**
+ * Increases the current score when a match is found. The score is based on the current level.
+ */
+ private void increaseScoreMatch() {
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundMatchRight);
+ }
+ mMatchScore += (50 * (Math.pow(1.1, mLevelNumber - 1)));
+ mScoreText.setText(String.valueOf(mMatchScore));
+ mTextPlayAgainScore.setText(String.valueOf(mMatchScore));
+ }
+
+ /** Increases the current score when advancing to the next level. */
+ private void increaseScoreLevel() {
+ mMatchScore += (500 * (Math.pow(1.1, mLevelNumber - 1)));
+ if (mLevelNumber > 2 && mWrongAnswers == 0) {
+ // Show an amazing bonus animation if this the player is particularly skillful ;)
+ mViewBonusSnowman.startAnimation(mAnimationSnowman);
+ }
+ mScoreText.setText(String.valueOf(mMatchScore));
+ mTextPlayAgainScore.setText(String.valueOf(mMatchScore));
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ // The game is clickable again now that the animation has ended
+ isClickable = true;
+ mClickabilityHandler.removeCallbacksAndMessages(null);
+
+ if (animation == mAnimationScaleLevelDown) {
+ // After the scale level down animation, fade out the end level circle
+ mLevelNumberText.startAnimation(mAnimationLevelFadeOut);
+ mEndLevelCircle.startAnimation(mAnimationLevelFadeOut);
+ } else if (animation == mAnimationLevelFadeOut) {
+ // Hide the end level circle after the animation has finished
+ mEndLevelCircle.clearAnimation();
+ mLevelNumberText.clearAnimation();
+ mLevelNumberText.setVisibility(View.GONE);
+ mEndLevelCircle.setVisibility(View.GONE);
+ } else if (animation == mAnimationSetSnowman) {
+ mViewBonusSnowman.clearAnimation();
+ mViewBonusSnowman.setVisibility(View.GONE);
+ } else if (animation == mAnimationCardCover) {
+ // Reset the state and animations of both cards after they have been hidden again
+ mHiddenCard1.clearAnimation();
+ mHiddenCard2.clearAnimation();
+
+ mHiddenCard1.findViewById(R.id.card_pane_right).clearAnimation();
+ mHiddenCard1.findViewById(R.id.card_pane_left).clearAnimation();
+ mHiddenCard2.findViewById(R.id.card_pane_right).clearAnimation();
+ mHiddenCard2.findViewById(R.id.card_pane_left).clearAnimation();
+ mHiddenCard1.findViewById(R.id.card_pane_right).setVisibility(View.GONE);
+ mHiddenCard1.findViewById(R.id.card_pane_left).setVisibility(View.GONE);
+ mHiddenCard2.findViewById(R.id.card_pane_right).setVisibility(View.GONE);
+ mHiddenCard2.findViewById(R.id.card_pane_left).setVisibility(View.GONE);
+ mHiddenCard1.findViewById(R.id.card_cover).setBackgroundColor(Color.TRANSPARENT);
+ mHiddenCard2.findViewById(R.id.card_cover).setBackgroundColor(Color.TRANSPARENT);
+ mHiddenCard1.findViewById(R.id.card_cover).setVisibility(View.GONE);
+ mHiddenCard2.findViewById(R.id.card_cover).setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {}
+
+ @Override
+ public void onAnimationStart(Animation animation) {
+ // Mark the game as not clickable when an animation is in progress
+ isClickable = false;
+
+ // Mark the correct views as visible before the start of an animation.
+ if (animation == mAnimationScaleLevelDown) {
+ mEndLevelCircle.setVisibility(View.VISIBLE);
+ mLevelNumberText.setVisibility(View.VISIBLE);
+ } else if (animation == mAnimationPlayAgainBackground) {
+ mViewPlayAgainBackground.setVisibility(View.VISIBLE);
+ } else if (animation == mAnimationPlayAgainMain) {
+ mViewPlayAgainMain.setVisibility(View.VISIBLE);
+ setSignInButtonVisibility(true);
+ } else if (animation == mAnimationSetSnowman) {
+ mViewBonusSnowman.setVisibility(View.VISIBLE);
+ mViewBonusSnowman.postDelayed(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (!mSantaPreferences.isMuted()) {
+ SoundPoolUtils.playSoundEffect(mSoundPool, mSoundBeep);
+ }
+ }
+ },
+ 800);
+ }
+
+ // Set a clickability timeout
+ mClickabilityHandler.postDelayed(mMakeClickableRunnable, ANIMATION_TIMEOUT);
+ }
+
+ @Override
+ public void invalidateDrawable(Drawable who) {}
+
+ @Override
+ public void scheduleDrawable(Drawable who, Runnable what, long when) {}
+
+ @Override
+ public void unscheduleDrawable(Drawable who, Runnable what) {}
+
+ /** Pauses the game when the back key is pressed. */
+ public void onBackKeyPressed() {
+ if (mViewPlayAgainMain.getVisibility() == View.VISIBLE) {
+ exit();
+ } else {
+ if (mButtonPause.getVisibility() != View.GONE) { // check if already handled
+ pauseGame();
+ } else {
+ // Exit the game.
+ exit();
+ }
+ }
+ }
+
+ private void pauseGame() {
+ mButtonPause.setVisibility(View.GONE);
+ mButtonPlay.setVisibility(View.VISIBLE);
+ if (mCountDownTimer != null) {
+ mCountDownTimer.cancel();
+ }
+
+ // If the user got the previous turn incorrect and the CloseDoor timer is ticking,
+ // stop the CloseDoor timer but remember how much time is left on it.
+ if (mDoorCloseHandler != null && mDoorCloseRunnable != null && mDoorCloseTimerTicking) {
+ mDoorCloseHandler.removeCallbacks(mDoorCloseRunnable);
+ mDoorCloseTimeRemaining =
+ DOOR_CLOSE_DELAY_MILLIS - (System.currentTimeMillis() - mDoorCloseTimerStart);
+ }
+ mViewPauseOverlay.setVisibility(View.VISIBLE);
+ mButtonCancelBar.setVisibility(View.VISIBLE);
+ ImmersiveModeHelper.setImmersiveStickyWithActionBar(getActivity().getWindow());
+ }
+
+ private void onMuteChanged(boolean muted) {
+ if (muted) {
+ stopBackgroundMusic();
+ mSoundPool.autoPause();
+ } else {
+ loadBackgroundMusic();
+ mSoundPool.autoResume();
+ }
+ }
+
+ /** Submit score to Play Games services and the leader board. */
+ private void submitScore(int resId, int score) {
+ PlayGamesActivity act = Utils.getPlayGamesActivity(this);
+ if (act != null) {
+ act.postSubmitScore(resId, score);
+ }
+ }
+}
diff --git a/memory/src/main/res/anim/left_pane_slide_out.xml b/memory/src/main/res/anim/left_pane_slide_out.xml
new file mode 100644
index 000000000..f4a02a47a
--- /dev/null
+++ b/memory/src/main/res/anim/left_pane_slide_out.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/memory/src/main/res/drawable-hdpi/mmg_background_left.webp b/memory/src/main/res/drawable-hdpi/mmg_background_left.webp
new file mode 100644
index 000000000..88af4669b
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_background_left.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_background_right.webp b/memory/src/main/res/drawable-hdpi/mmg_background_right.webp
new file mode 100644
index 000000000..e48a5edf6
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_background_right.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_background_top.webp b/memory/src/main/res/drawable-hdpi/mmg_background_top.webp
new file mode 100644
index 000000000..f7128c824
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_background_top.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_ball.webp b/memory/src/main/res/drawable-hdpi/mmg_card_ball.webp
new file mode 100644
index 000000000..af28e3cef
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_ball.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_balloon.webp b/memory/src/main/res/drawable-hdpi/mmg_card_balloon.webp
new file mode 100644
index 000000000..f95197adb
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_balloon.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_beachball.webp b/memory/src/main/res/drawable-hdpi/mmg_card_beachball.webp
new file mode 100644
index 000000000..4c7ae8dee
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_beachball.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_candle.webp b/memory/src/main/res/drawable-hdpi/mmg_card_candle.webp
new file mode 100644
index 000000000..48fb9c28c
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_candle.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_cloak_blue_dark.webp b/memory/src/main/res/drawable-hdpi/mmg_card_cloak_blue_dark.webp
new file mode 100644
index 000000000..0e904d6eb
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_cloak_blue_dark.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_cloak_blue_light.webp b/memory/src/main/res/drawable-hdpi/mmg_card_cloak_blue_light.webp
new file mode 100644
index 000000000..2b110cf9b
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_cloak_blue_light.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_cloak_orange.webp b/memory/src/main/res/drawable-hdpi/mmg_card_cloak_orange.webp
new file mode 100644
index 000000000..e42a3a94b
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_cloak_orange.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_cloak_purple.webp b/memory/src/main/res/drawable-hdpi/mmg_card_cloak_purple.webp
new file mode 100644
index 000000000..ca1f42d72
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_cloak_purple.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_cloak_red.webp b/memory/src/main/res/drawable-hdpi/mmg_card_cloak_red.webp
new file mode 100644
index 000000000..05169e4e3
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_cloak_red.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_frame.webp b/memory/src/main/res/drawable-hdpi/mmg_card_frame.webp
new file mode 100644
index 000000000..9678c6a99
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_frame.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_globe.webp b/memory/src/main/res/drawable-hdpi/mmg_card_globe.webp
new file mode 100644
index 000000000..30a131f71
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_globe.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_gumball.webp b/memory/src/main/res/drawable-hdpi/mmg_card_gumball.webp
new file mode 100644
index 000000000..d4fcb77b4
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_gumball.webp differ
diff --git a/santa-tracker/src/main/res/drawable-hdpi/mmg_card_locked.jpg b/memory/src/main/res/drawable-hdpi/mmg_card_locked.jpg
similarity index 100%
rename from santa-tracker/src/main/res/drawable-hdpi/mmg_card_locked.jpg
rename to memory/src/main/res/drawable-hdpi/mmg_card_locked.jpg
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_penguin.webp b/memory/src/main/res/drawable-hdpi/mmg_card_penguin.webp
new file mode 100644
index 000000000..b320f0ee0
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_penguin.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_rabbit.webp b/memory/src/main/res/drawable-hdpi/mmg_card_rabbit.webp
new file mode 100644
index 000000000..099dc2964
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_rabbit.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_reindeer.webp b/memory/src/main/res/drawable-hdpi/mmg_card_reindeer.webp
new file mode 100644
index 000000000..e5689f562
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_reindeer.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_snowman.webp b/memory/src/main/res/drawable-hdpi/mmg_card_snowman.webp
new file mode 100644
index 000000000..9b04934ba
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_snowman.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_tree.webp b/memory/src/main/res/drawable-hdpi/mmg_card_tree.webp
new file mode 100644
index 000000000..572c362c5
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_tree.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_card_trophy.webp b/memory/src/main/res/drawable-hdpi/mmg_card_trophy.webp
new file mode 100644
index 000000000..7f9da445d
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_card_trophy.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_pane_left.webp b/memory/src/main/res/drawable-hdpi/mmg_pane_left.webp
new file mode 100644
index 000000000..ffffab85d
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_pane_left.webp differ
diff --git a/memory/src/main/res/drawable-hdpi/mmg_pane_right.webp b/memory/src/main/res/drawable-hdpi/mmg_pane_right.webp
new file mode 100644
index 000000000..8ce549b39
Binary files /dev/null and b/memory/src/main/res/drawable-hdpi/mmg_pane_right.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_background_left.webp b/memory/src/main/res/drawable-mdpi/mmg_background_left.webp
new file mode 100644
index 000000000..c03158b71
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_background_left.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_background_right.webp b/memory/src/main/res/drawable-mdpi/mmg_background_right.webp
new file mode 100644
index 000000000..2055ee0b7
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_background_right.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_background_top.webp b/memory/src/main/res/drawable-mdpi/mmg_background_top.webp
new file mode 100644
index 000000000..3d77c721f
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_background_top.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_ball.webp b/memory/src/main/res/drawable-mdpi/mmg_card_ball.webp
new file mode 100644
index 000000000..0f89451a4
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_ball.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_balloon.webp b/memory/src/main/res/drawable-mdpi/mmg_card_balloon.webp
new file mode 100644
index 000000000..743ccf7a9
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_balloon.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_beachball.webp b/memory/src/main/res/drawable-mdpi/mmg_card_beachball.webp
new file mode 100644
index 000000000..c67b562f1
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_beachball.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_candle.webp b/memory/src/main/res/drawable-mdpi/mmg_card_candle.webp
new file mode 100644
index 000000000..1b323cc1a
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_candle.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_cloak_blue_dark.webp b/memory/src/main/res/drawable-mdpi/mmg_card_cloak_blue_dark.webp
new file mode 100644
index 000000000..d42d2daac
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_cloak_blue_dark.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_cloak_blue_light.webp b/memory/src/main/res/drawable-mdpi/mmg_card_cloak_blue_light.webp
new file mode 100644
index 000000000..dc137d5f2
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_cloak_blue_light.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_cloak_orange.webp b/memory/src/main/res/drawable-mdpi/mmg_card_cloak_orange.webp
new file mode 100644
index 000000000..abc7de5e3
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_cloak_orange.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_cloak_purple.webp b/memory/src/main/res/drawable-mdpi/mmg_card_cloak_purple.webp
new file mode 100644
index 000000000..de6143a5a
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_cloak_purple.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_cloak_red.webp b/memory/src/main/res/drawable-mdpi/mmg_card_cloak_red.webp
new file mode 100644
index 000000000..48f3f426e
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_cloak_red.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_frame.webp b/memory/src/main/res/drawable-mdpi/mmg_card_frame.webp
new file mode 100644
index 000000000..1e83182ff
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_frame.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_globe.webp b/memory/src/main/res/drawable-mdpi/mmg_card_globe.webp
new file mode 100644
index 000000000..96f150c30
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_globe.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_gumball.webp b/memory/src/main/res/drawable-mdpi/mmg_card_gumball.webp
new file mode 100644
index 000000000..37a84e2e6
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_gumball.webp differ
diff --git a/santa-tracker/src/main/res/drawable-mdpi/mmg_card_locked.jpg b/memory/src/main/res/drawable-mdpi/mmg_card_locked.jpg
similarity index 100%
rename from santa-tracker/src/main/res/drawable-mdpi/mmg_card_locked.jpg
rename to memory/src/main/res/drawable-mdpi/mmg_card_locked.jpg
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_penguin.webp b/memory/src/main/res/drawable-mdpi/mmg_card_penguin.webp
new file mode 100644
index 000000000..525a8d8bd
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_penguin.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_rabbit.webp b/memory/src/main/res/drawable-mdpi/mmg_card_rabbit.webp
new file mode 100644
index 000000000..8e35a77e6
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_rabbit.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_reindeer.webp b/memory/src/main/res/drawable-mdpi/mmg_card_reindeer.webp
new file mode 100644
index 000000000..2cf84971d
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_reindeer.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_snowman.webp b/memory/src/main/res/drawable-mdpi/mmg_card_snowman.webp
new file mode 100644
index 000000000..9c6a5f0c5
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_snowman.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_tree.webp b/memory/src/main/res/drawable-mdpi/mmg_card_tree.webp
new file mode 100644
index 000000000..06b870247
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_tree.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_card_trophy.webp b/memory/src/main/res/drawable-mdpi/mmg_card_trophy.webp
new file mode 100644
index 000000000..4b0273c01
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_card_trophy.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_pane_left.webp b/memory/src/main/res/drawable-mdpi/mmg_pane_left.webp
new file mode 100644
index 000000000..bf6378468
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_pane_left.webp differ
diff --git a/memory/src/main/res/drawable-mdpi/mmg_pane_right.webp b/memory/src/main/res/drawable-mdpi/mmg_pane_right.webp
new file mode 100644
index 000000000..3a9b4a46a
Binary files /dev/null and b/memory/src/main/res/drawable-mdpi/mmg_pane_right.webp differ
diff --git a/memory/src/main/res/drawable-nodpi/snowman_face.webp b/memory/src/main/res/drawable-nodpi/snowman_face.webp
new file mode 100644
index 000000000..ae0628bf2
Binary files /dev/null and b/memory/src/main/res/drawable-nodpi/snowman_face.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_background_left.webp b/memory/src/main/res/drawable-xhdpi/mmg_background_left.webp
new file mode 100644
index 000000000..505d81612
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_background_left.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_background_right.webp b/memory/src/main/res/drawable-xhdpi/mmg_background_right.webp
new file mode 100644
index 000000000..3e0a246df
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_background_right.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_background_top.webp b/memory/src/main/res/drawable-xhdpi/mmg_background_top.webp
new file mode 100644
index 000000000..87c22368a
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_background_top.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_ball.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_ball.webp
new file mode 100644
index 000000000..8598aae92
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_ball.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_balloon.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_balloon.webp
new file mode 100644
index 000000000..1a7cd76ba
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_balloon.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_beachball.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_beachball.webp
new file mode 100644
index 000000000..e36e79a48
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_beachball.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_candle.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_candle.webp
new file mode 100644
index 000000000..1ff533bbb
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_candle.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_blue_dark.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_blue_dark.webp
new file mode 100644
index 000000000..bb8f8673d
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_blue_dark.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_blue_light.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_blue_light.webp
new file mode 100644
index 000000000..a40109a15
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_blue_light.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_orange.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_orange.webp
new file mode 100644
index 000000000..790a97f04
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_orange.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_purple.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_purple.webp
new file mode 100644
index 000000000..cbb9d274e
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_purple.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_red.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_red.webp
new file mode 100644
index 000000000..bafa4a987
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_cloak_red.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_frame.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_frame.webp
new file mode 100644
index 000000000..3a6123912
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_frame.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_globe.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_globe.webp
new file mode 100644
index 000000000..da848a719
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_globe.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_gumball.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_gumball.webp
new file mode 100644
index 000000000..a46ae0513
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_gumball.webp differ
diff --git a/santa-tracker/src/main/res/drawable-xhdpi/mmg_card_locked.jpg b/memory/src/main/res/drawable-xhdpi/mmg_card_locked.jpg
similarity index 100%
rename from santa-tracker/src/main/res/drawable-xhdpi/mmg_card_locked.jpg
rename to memory/src/main/res/drawable-xhdpi/mmg_card_locked.jpg
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_penguin.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_penguin.webp
new file mode 100644
index 000000000..8e2dd1e3b
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_penguin.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_rabbit.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_rabbit.webp
new file mode 100644
index 000000000..e45cb0367
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_rabbit.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_reindeer.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_reindeer.webp
new file mode 100644
index 000000000..a6401237c
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_reindeer.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_snowman.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_snowman.webp
new file mode 100644
index 000000000..ca6625f71
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_snowman.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_tree.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_tree.webp
new file mode 100644
index 000000000..279f2e4e9
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_tree.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_card_trophy.webp b/memory/src/main/res/drawable-xhdpi/mmg_card_trophy.webp
new file mode 100644
index 000000000..88aae8735
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_card_trophy.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_pane_left.webp b/memory/src/main/res/drawable-xhdpi/mmg_pane_left.webp
new file mode 100644
index 000000000..b730421d9
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_pane_left.webp differ
diff --git a/memory/src/main/res/drawable-xhdpi/mmg_pane_right.webp b/memory/src/main/res/drawable-xhdpi/mmg_pane_right.webp
new file mode 100644
index 000000000..7fa2cb29f
Binary files /dev/null and b/memory/src/main/res/drawable-xhdpi/mmg_pane_right.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_background_left.webp b/memory/src/main/res/drawable-xxhdpi/mmg_background_left.webp
new file mode 100644
index 000000000..14bce2369
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_background_left.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_background_right.webp b/memory/src/main/res/drawable-xxhdpi/mmg_background_right.webp
new file mode 100644
index 000000000..39297d08c
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_background_right.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_background_top.webp b/memory/src/main/res/drawable-xxhdpi/mmg_background_top.webp
new file mode 100644
index 000000000..548caccab
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_background_top.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_ball.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_ball.webp
new file mode 100644
index 000000000..0b87c4669
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_ball.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_balloon.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_balloon.webp
new file mode 100644
index 000000000..395fb9997
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_balloon.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_beachball.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_beachball.webp
new file mode 100644
index 000000000..ce319436d
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_beachball.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_candle.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_candle.webp
new file mode 100644
index 000000000..510e6d9b0
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_candle.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_blue_dark.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_blue_dark.webp
new file mode 100644
index 000000000..f58ba778d
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_blue_dark.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_blue_light.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_blue_light.webp
new file mode 100644
index 000000000..04ef21fc4
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_blue_light.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_orange.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_orange.webp
new file mode 100644
index 000000000..7160ef47c
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_orange.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_purple.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_purple.webp
new file mode 100644
index 000000000..cd0150300
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_purple.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_red.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_red.webp
new file mode 100644
index 000000000..00418b025
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_cloak_red.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_frame.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_frame.webp
new file mode 100644
index 000000000..322e0cf0e
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_frame.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_globe.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_globe.webp
new file mode 100644
index 000000000..0114ac733
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_globe.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_gumball.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_gumball.webp
new file mode 100644
index 000000000..fdab7a1ee
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_gumball.webp differ
diff --git a/santa-tracker/src/main/res/drawable-xxhdpi/mmg_card_locked.jpg b/memory/src/main/res/drawable-xxhdpi/mmg_card_locked.jpg
similarity index 100%
rename from santa-tracker/src/main/res/drawable-xxhdpi/mmg_card_locked.jpg
rename to memory/src/main/res/drawable-xxhdpi/mmg_card_locked.jpg
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_penguin.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_penguin.webp
new file mode 100644
index 000000000..ca40d1815
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_penguin.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_rabbit.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_rabbit.webp
new file mode 100644
index 000000000..e426dd07a
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_rabbit.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_reindeer.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_reindeer.webp
new file mode 100644
index 000000000..30da95fba
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_reindeer.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_snowman.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_snowman.webp
new file mode 100644
index 000000000..fcd91e3b8
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_snowman.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_tree.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_tree.webp
new file mode 100644
index 000000000..19af49b90
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_tree.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_card_trophy.webp b/memory/src/main/res/drawable-xxhdpi/mmg_card_trophy.webp
new file mode 100644
index 000000000..1257b90bb
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_card_trophy.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_pane_left.webp b/memory/src/main/res/drawable-xxhdpi/mmg_pane_left.webp
new file mode 100644
index 000000000..6f69930c9
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_pane_left.webp differ
diff --git a/memory/src/main/res/drawable-xxhdpi/mmg_pane_right.webp b/memory/src/main/res/drawable-xxhdpi/mmg_pane_right.webp
new file mode 100644
index 000000000..efbc8f404
Binary files /dev/null and b/memory/src/main/res/drawable-xxhdpi/mmg_pane_right.webp differ
diff --git a/memory/src/main/res/layout/activity_memory.xml b/memory/src/main/res/layout/activity_memory.xml
new file mode 100644
index 000000000..14c24334c
--- /dev/null
+++ b/memory/src/main/res/layout/activity_memory.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/memory/src/main/res/layout/fragment_memory_match.xml b/memory/src/main/res/layout/fragment_memory_match.xml
new file mode 100644
index 000000000..d6e122c03
--- /dev/null
+++ b/memory/src/main/res/layout/fragment_memory_match.xml
@@ -0,0 +1,268 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/santa-tracker/src/main/res/layout/item_memory_card.xml b/memory/src/main/res/layout/item_memory_card.xml
similarity index 78%
rename from santa-tracker/src/main/res/layout/item_memory_card.xml
rename to memory/src/main/res/layout/item_memory_card.xml
index 525a3bd87..262528cf2 100644
--- a/santa-tracker/src/main/res/layout/item_memory_card.xml
+++ b/memory/src/main/res/layout/item_memory_card.xml
@@ -1,4 +1,20 @@
+
+
@@ -72,4 +88,4 @@
android:layout_margin="3dp"
android:src="@drawable/mmg_card_locked" />
-
\ No newline at end of file
+
diff --git a/memory/src/main/res/raw/mmg_close_door.m4a b/memory/src/main/res/raw/mmg_close_door.m4a
new file mode 100644
index 000000000..d32b27dba
Binary files /dev/null and b/memory/src/main/res/raw/mmg_close_door.m4a differ
diff --git a/memory/src/main/res/raw/mmg_open_door_2.m4a b/memory/src/main/res/raw/mmg_open_door_2.m4a
new file mode 100644
index 000000000..d492ef63d
Binary files /dev/null and b/memory/src/main/res/raw/mmg_open_door_2.m4a differ
diff --git a/memory/src/main/res/raw/mmg_open_door_3.m4a b/memory/src/main/res/raw/mmg_open_door_3.m4a
new file mode 100644
index 000000000..1084ff85a
Binary files /dev/null and b/memory/src/main/res/raw/mmg_open_door_3.m4a differ
diff --git a/memory/src/main/res/raw/mmg_right.m4a b/memory/src/main/res/raw/mmg_right.m4a
new file mode 100644
index 000000000..131f5c65a
Binary files /dev/null and b/memory/src/main/res/raw/mmg_right.m4a differ
diff --git a/memory/src/main/res/raw/mmg_wrong.m4a b/memory/src/main/res/raw/mmg_wrong.m4a
new file mode 100644
index 000000000..4809fe288
Binary files /dev/null and b/memory/src/main/res/raw/mmg_wrong.m4a differ
diff --git a/memory/src/main/res/values/colors.xml b/memory/src/main/res/values/colors.xml
new file mode 100644
index 000000000..56165f71c
--- /dev/null
+++ b/memory/src/main/res/values/colors.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/memory/src/main/res/values/styles.xml b/memory/src/main/res/values/styles.xml
new file mode 100644
index 000000000..6c65774ee
--- /dev/null
+++ b/memory/src/main/res/values/styles.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/penguinswim/build.gradle b/penguinswim/build.gradle
new file mode 100644
index 000000000..70acb9f7b
--- /dev/null
+++ b/penguinswim/build.gradle
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
+apply plugin: 'com.android.dynamic-feature'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.tools
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ }
+}
+
+dependencies {
+ implementation project(':santa-tracker')
+ implementation rootProject.ext.supportAnnotations
+}
diff --git a/penguinswim/src/main/AndroidManifest.xml b/penguinswim/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..fc4e91c2c
--- /dev/null
+++ b/penguinswim/src/main/AndroidManifest.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/BoundingBoxSpriteActor.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/BoundingBoxSpriteActor.java
new file mode 100644
index 000000000..5e905bef5
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/BoundingBoxSpriteActor.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import com.google.android.apps.santatracker.doodles.shared.Debug;
+import com.google.android.apps.santatracker.doodles.shared.Touchable;
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import com.google.android.apps.santatracker.doodles.shared.actor.Actor;
+import com.google.android.apps.santatracker.doodles.shared.actor.SpriteActor;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite;
+import com.google.android.apps.santatracker.doodles.shared.physics.Polygon;
+import com.google.android.apps.santatracker.doodles.shared.physics.Util;
+import com.google.android.apps.santatracker.util.SantaLog;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/** A sprite actor which contains a pre-set convex collision body. */
+public class BoundingBoxSpriteActor extends CollisionActor implements Touchable {
+ public static final String DUCK = "duck";
+ public static final String ICE_CUBE = "cube1";
+ public static final String HAND_GRAB = "hand grab";
+ public static final Map TYPE_TO_RESOURCE_MAP;
+ protected static final float SCALE = 2;
+ private static final String TAG = BoundingBoxSpriteActor.class.getSimpleName();
+ private static final Random RANDOM = new Random();
+
+ 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(
+ PenguinSwimSprites.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(
+ PenguinSwimSprites.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 final SpriteActor spriteActor;
+ public String type;
+ 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;
+ }
+
+ public static BoundingBoxSpriteActor create(
+ Vector2D position, String type, Resources resources) {
+ if (!TYPE_TO_RESOURCE_MAP.containsKey(type)) {
+ SantaLog.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);
+ }
+
+ @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);
+
+ if (Debug.DRAW_COLLISION_BOUNDS) {
+ 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));
+ SantaLog.d(TAG, "min: " + collisionBody.min);
+ SantaLog.d(TAG, "max: " + collisionBody.max);
+ } else {
+ spriteOffset.subtract(delta);
+ SantaLog.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;
+ }
+
+ /** 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;
+ }
+ }
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/CollisionActor.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/CollisionActor.java
new file mode 100644
index 000000000..6c90cfd95
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/CollisionActor.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import android.graphics.Canvas;
+import com.google.android.apps.santatracker.doodles.shared.Debug;
+import com.google.android.apps.santatracker.doodles.shared.Touchable;
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import com.google.android.apps.santatracker.doodles.shared.actor.Actor;
+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";
+ // 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;
+ protected static final String POLYGON_KEY = "polygon";
+ 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;
+ }
+
+ public static CollisionActor fromJSON(JSONObject json) throws JSONException {
+ return new CollisionActor(Polygon.fromJSON(json.getJSONArray(POLYGON_KEY)));
+ }
+
+ @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) {
+ if (Debug.DRAW_COLLISION_BOUNDS) {
+ collisionBody.draw(canvas);
+ }
+ }
+
+ public boolean canRemoveCollisionVertex() {
+ return collisionBody.vertices.size() > 3;
+ }
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/DistanceMarkerActor.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/DistanceMarkerActor.java
new file mode 100644
index 000000000..be4e25a7d
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/DistanceMarkerActor.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import com.google.android.apps.santatracker.doodles.shared.ColoredRectangleActor;
+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/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/DiveView.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/DiveView.java
new file mode 100644
index 000000000..dbfddaf89
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/DiveView.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+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 androidx.appcompat.widget.AppCompatImageView;
+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.UIUtil;
+import com.google.android.apps.santatracker.doodles.shared.animation.Interpolator;
+import com.google.android.apps.santatracker.doodles.shared.animation.Tween;
+import com.google.android.apps.santatracker.doodles.shared.views.PauseView;
+import java.util.ArrayList;
+import java.util.List;
+
+/** The dive cooldown UI for the swimming game. */
+public class DiveView extends AppCompatImageView {
+ 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/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/HandGrabActor.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/HandGrabActor.java
new file mode 100644
index 000000000..f18b43f63
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/HandGrabActor.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+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.actor.MultiSpriteActor;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite.AnimatedSpriteListener;
+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;
+ }
+
+ 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, PenguinSwimSprites.penguin_swim_canegrab);
+ lemonGrabSprite.setLoop(false);
+ lemonGrabSprite.setFlippedX(shouldFlip);
+
+ spriteMap.put(LEMON_GRAB_SPRITE, lemonGrabSprite);
+ spriteMap.put(
+ X_SPRITE, AnimatedSprite.fromFrames(res, PenguinSwimSprites.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);
+ }
+
+ @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;
+ }
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/LevelManager.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/LevelManager.java
new file mode 100644
index 000000000..84fa98dd1
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/LevelManager.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import android.content.Context;
+import androidx.annotation.VisibleForTesting;
+import com.google.android.apps.santatracker.doodles.shared.ExternalStoragePermissions;
+import com.google.android.apps.santatracker.doodles.shared.actor.Actor;
+import com.google.android.apps.santatracker.util.SantaLog;
+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;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * 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.
+ SantaLog.w(TAG, "Unable to reach dir: " + levelsDir.getAbsolutePath());
+ return;
+ }
+ try {
+ FileOutputStream outputStream = new FileOutputStream(new File(levelsDir, filename));
+ saveLevel(level, outputStream);
+ } catch (FileNotFoundException e) {
+ SantaLog.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) {
+ SantaLog.w(TAG, "Unable to create level JSON.");
+ } catch (IOException e) {
+ SantaLog.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) {
+ SantaLog.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) {
+ SantaLog.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) {
+ SantaLog.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);
+ SantaLog.d(TAG, "Loaded level from assets.");
+ }
+ if (json == null
+ && externalStorageReader != null
+ && storagePermissions.isExternalStorageReadable()) {
+ json = readLevelJson(externalStorageReader);
+ SantaLog.d(TAG, "Loaded level from external storage.");
+ }
+ if (json == null) {
+ SantaLog.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) {
+ SantaLog.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));
+ SantaLog.d(TAG, json.toString(2));
+
+ if (storagePermissions.isExternalStorageWritable()) {
+ writeLevelJson(json, outputStream);
+ } else {
+ SantaLog.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) {
+ SantaLog.w(TAG, "readLevelJson: Couldn't read JSON.");
+ } catch (JSONException e) {
+ SantaLog.w(TAG, "readLevelJson: Couldn't create JSON.");
+ }
+ return null;
+ }
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/ObstacleManager.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/ObstacleManager.java
new file mode 100644
index 000000000..6302bedd8
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/ObstacleManager.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import android.content.Context;
+import com.google.android.apps.santatracker.doodles.shared.actor.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/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/PenguinSwimActivity.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/PenguinSwimActivity.java
new file mode 100644
index 000000000..21514364b
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/PenguinSwimActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.SWIMMING_GAME_TYPE;
+
+import android.app.Fragment;
+import com.google.android.apps.santatracker.doodles.BaseDoodleActivity;
+import com.google.android.apps.santatracker.doodles.shared.logging.DoodleDebugLogger;
+
+public class PenguinSwimActivity extends BaseDoodleActivity {
+ @Override
+ protected String getGameType() {
+ return SWIMMING_GAME_TYPE;
+ }
+
+ @Override
+ protected int getAnalyticsStringResource() {
+ return R.string.analytics_screen_swimming;
+ }
+
+ @Override
+ protected Fragment makeFragment(DoodleDebugLogger logger) {
+ return SwimmingFragment.newInstance(false);
+ }
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/PenguinSwimSprites.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/PenguinSwimSprites.java
new file mode 100644
index 000000000..96eb1cddb
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/PenguinSwimSprites.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+public interface PenguinSwimSprites {
+
+ 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,
+ };
+
+ 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,
+ };
+
+ 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,
+ };
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmerActor.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmerActor.java
new file mode 100644
index 000000000..567fa4283
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmerActor.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import com.google.android.apps.santatracker.doodles.shared.CallbackProcess;
+import com.google.android.apps.santatracker.doodles.shared.Debug;
+import com.google.android.apps.santatracker.doodles.shared.EventBus;
+import com.google.android.apps.santatracker.doodles.shared.ProcessChain;
+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.actor.MultiSpriteActor;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite.AnimatedSpriteListener;
+import com.google.android.apps.santatracker.doodles.shared.physics.Polygon;
+import com.google.android.apps.santatracker.doodles.shared.physics.Util;
+import com.google.android.apps.santatracker.doodles.shared.views.GameFragment;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.json.JSONObject;
+
+/** The player-controlled swimmer in the swimming game. */
+public class SwimmerActor extends BoundingBoxSpriteActor {
+ 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 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;
+ 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;
+ }
+
+ 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, PenguinSwimSprites.penguin_swim_idle));
+ if (gameFragment.isDestroyed) {
+ return null;
+ }
+ spriteMap.put(
+ KICKOFF_START_SPRITE,
+ AnimatedSprite.fromFrames(res, PenguinSwimSprites.penguin_swim_start));
+ if (gameFragment.isDestroyed) {
+ return null;
+ }
+ spriteMap.put(
+ RINGS_SPRITE, AnimatedSprite.fromFrames(res, PenguinSwimSprites.swimming_rings));
+ if (gameFragment.isDestroyed) {
+ return null;
+ }
+ spriteMap.put(
+ SWIM_LOOP_SPRITE,
+ AnimatedSprite.fromFrames(res, PenguinSwimSprites.penguin_swim_swimming));
+ if (gameFragment.isDestroyed) {
+ return null;
+ }
+ spriteMap.put(
+ CAN_COLLIDE_SPRITE,
+ AnimatedSprite.fromFrames(res, PenguinSwimSprites.penguin_swim_dazed));
+ if (gameFragment.isDestroyed) {
+ return null;
+ }
+ spriteMap.put(
+ FREEZE_SPRITE,
+ AnimatedSprite.fromFrames(res, PenguinSwimSprites.penguin_swim_frozen));
+ if (gameFragment.isDestroyed) {
+ return null;
+ }
+ spriteMap.put(
+ DIVE_DOWN_SPRITE,
+ AnimatedSprite.fromFrames(res, PenguinSwimSprites.penguin_swim_descending));
+ if (gameFragment.isDestroyed) {
+ return null;
+ }
+ spriteMap.put(
+ UNDER_LOOP_SPRITE,
+ AnimatedSprite.fromFrames(res, PenguinSwimSprites.penguin_swim_swimmingunderwater));
+ if (gameFragment.isDestroyed) {
+ return null;
+ }
+ spriteMap.put(
+ RISE_UP_SPRITE,
+ AnimatedSprite.fromFrames(res, PenguinSwimSprites.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);
+ }
+
+ @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);
+
+ if (Debug.DRAW_COLLISION_BOUNDS) {
+ 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);
+ }
+ }
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingFragment.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingFragment.java
new file mode 100644
index 000000000..81cc78c92
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingFragment.java
@@ -0,0 +1,999 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import static com.google.android.apps.santatracker.doodles.shared.logging.DoodleLogEvent.SWIMMING_GAME_TYPE;
+
+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.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Vibrator;
+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 androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import com.google.android.apps.santatracker.doodles.penguinswim.SwimmingModel.SwimmingState;
+import com.google.android.apps.santatracker.doodles.shared.AndroidUtils;
+import com.google.android.apps.santatracker.doodles.shared.ColoredRectangleActor;
+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.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.UIUtil;
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import com.google.android.apps.santatracker.doodles.shared.actor.Camera;
+import com.google.android.apps.santatracker.doodles.shared.actor.CameraShake;
+import com.google.android.apps.santatracker.doodles.shared.actor.RectangularInstructionActor;
+import com.google.android.apps.santatracker.doodles.shared.actor.SpriteActor;
+import com.google.android.apps.santatracker.doodles.shared.animation.AnimatedSprite;
+import com.google.android.apps.santatracker.doodles.shared.sound.SoundManager;
+import com.google.android.apps.santatracker.doodles.shared.views.GameFragment;
+import com.google.android.apps.santatracker.util.MeasurementManager;
+import com.google.android.apps.santatracker.util.SantaLog;
+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 java.util.concurrent.atomic.AtomicReference;
+
+/** The main fragment for the swimming game. */
+public class SwimmingFragment extends GameFragment
+ implements SensorEventListener, EventBusListener {
+ public static final String CURRENT_LEVEL_KEY = "CURRENT_LEVEL";
+ private static final String TAG = SwimmingFragment.class.getSimpleName();
+ 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;
+ private static final String EDITOR_MODE = "editor_mode";
+
+ 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 final AtomicReference modelRef = new AtomicReference<>();
+ 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 static SwimmingFragment newInstance(boolean editorMode) {
+ SwimmingFragment fragment = new SwimmingFragment();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(EDITOR_MODE, editorMode);
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Bundle args = getArguments();
+ if (args != null) {
+ editorMode = args.getBoolean(EDITOR_MODE);
+ }
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ if (context == null) {
+ return null;
+ }
+
+ levelManager = new SwimmingLevelManager(context);
+
+ wrapper = new FrameLayout(context);
+ return wrapper;
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ loadGame();
+ }
+
+ @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;
+
+ 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(
+ com.google.android.apps.santatracker.common.R.string.reset_level,
+ new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ SwimmingModel level = levelManager.loadDefaultLevel();
+ initializeLevel(level, false);
+
+ getActivity()
+ .getSharedPreferences(
+ context.getString(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .string
+ .swimming),
+ Context.MODE_PRIVATE)
+ .edit()
+ .putString(CURRENT_LEVEL_KEY, null)
+ .apply();
+ }
+ });
+ deleteButton =
+ getButton(
+ com.google.android.apps.santatracker.common.R.string.delete_levels,
+ new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ DialogFragment dialogFragment = new DeleteLevelDialogFragment();
+ dialogFragment.show(
+ getActivity().getFragmentManager(), "delete");
+ }
+ });
+ loadButton =
+ getButton(
+ com.google.android.apps.santatracker.common.R.string.load_level,
+ new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ LoadLevelDialogFragment dialogFragment =
+ new LoadLevelDialogFragment();
+ dialogFragment.setSwimmingFragment(that);
+ dialogFragment.show(getActivity().getFragmentManager(), "load");
+ }
+ });
+ saveButton =
+ getButton(
+ com.google.android.apps.santatracker.common.R.string.save_level,
+ new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ SaveLevelDialogFragment dialogFragment =
+ SaveLevelDialogFragment.newInstance(
+ that.modelRef.get().levelName);
+ dialogFragment.setSwimmingFragment(that);
+ dialogFragment.show(getActivity().getFragmentManager(), "save");
+ }
+ });
+ collisionModeButton = new ToggleButton(context);
+ collisionModeButton.setText(
+ com.google.android.apps.santatracker.common.R.string.scenery_mode);
+ collisionModeButton.setTextOff(
+ context.getString(
+ com.google.android.apps.santatracker.common.R.string.scenery_mode));
+ collisionModeButton.setTextOn(
+ context.getString(
+ com.google.android.apps.santatracker.common.R.string.collision_mode));
+ collisionModeButton.setOnCheckedChangeListener(
+ new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ final SwimmingModel model = modelRef.get();
+ 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?
+ SantaLog.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);
+ }
+ modelRef.set(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) {
+ final SwimmingModel model = modelRef.get();
+
+ if (isPaused || model == null) {
+ 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) {
+ SantaLog.d(TAG, "Hiding intro animation right away.");
+
+ model.setState(SwimmingState.WAITING);
+ } else {
+ SantaLog.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) {
+ final SwimmingModel model = modelRef.get();
+ 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) {
+ final SwimmingModel model = modelRef.get();
+ if (isDestroyed || model == null) {
+ 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() {
+ final SwimmingModel model = modelRef.get();
+ if (model == null) {
+ return;
+ }
+ int bestDistance =
+ historyManager
+ .getBestDistance(GameType.SWIMMING)
+ .intValue();
+ String collidedObjectType =
+ model.swimmer.getCollidedObjectType();
+ scoreView.updateBestScore(
+ AndroidUtils.getText(
+ context.getResources(),
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .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);
+ SantaLog.d(TAG, "Waiting " + titleDurationMs + "ms and then hiding title.");
+ break;
+ }
+ }
+
+ @Nullable
+ private Drawable getShareImageDrawable(String collidedObjectType) {
+ return ContextCompat.getDrawable(
+ getActivity(), com.google.android.apps.santatracker.common.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(), PenguinSwimSprites.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(), PenguinSwimSprites.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;
+ }
+ modelRef.set(newLevel);
+ swimmingView.setModel(newLevel);
+
+ 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(),
+ com.google.android.apps.santatracker.common.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() {
+ final SwimmingModel model = modelRef.get();
+ Integer bestStarCount = historyManager.getBestStarCount(GameType.SWIMMING);
+ int modelStarCount = model.getStarCount();
+ if (bestStarCount == null || bestStarCount < modelStarCount) {
+ historyManager.setBestStarCount(GameType.SWIMMING, modelStarCount);
+ }
+ }
+
+ private void calculateBestDistance() {
+ final SwimmingModel model = modelRef.get();
+ 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(),
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .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() {
+ final SwimmingModel model = modelRef.get();
+ if (model != null && model.swimmer != null) {
+ model.swimmer.controlsEnabled = false;
+ }
+ super.onGamePause();
+ }
+
+ @Override
+ protected void onGameResume() {
+ final SwimmingModel model = modelRef.get();
+ if (model != null && model.swimmer != null) {
+ model.swimmer.controlsEnabled = true;
+ }
+ super.onGameResume();
+ }
+
+ @Override
+ protected void onGameReplay() {
+ final SwimmingModel model = modelRef.get();
+ if (model != null && model.swimmer != null) {
+ model.swimmer.controlsEnabled = true;
+ }
+ super.onGameReplay();
+ }
+
+ @Override
+ protected boolean onTitleTapped() {
+ final SwimmingModel model = modelRef.get();
+ 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() {
+ final SwimmingModel model = modelRef.get();
+ return model.distanceMeters;
+ }
+
+ @Override
+ protected int getShareImageId() {
+ final SwimmingModel model = modelRef.get();
+ 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;
+ }
+ }
+
+ public boolean isGameOver() {
+ return mIsGameOver;
+ }
+
+ /** A dialog fragment for loading a swimming level. */
+ public static class LoadLevelDialogFragment extends DialogFragment {
+
+ @Nullable private SwimmingFragment swimmingFragment;
+
+ public void setSwimmingFragment(@NonNull 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(com.google.android.apps.santatracker.common.R.string.load_level)
+ .setItems(
+ fileList,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (swimmingFragment == null) {
+ throw new IllegalStateException();
+ }
+ 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(
+ com.google
+ .android
+ .apps
+ .santatracker
+ .common
+ .R
+ .string
+ .swimming),
+ Context.MODE_PRIVATE)
+ .edit()
+ .putString(CURRENT_LEVEL_KEY, fileList[which])
+ .apply();
+ }
+ });
+ return builder.create();
+ }
+ }
+
+ /** A dialog fragment for saving a swimming level. */
+ public static class SaveLevelDialogFragment extends DialogFragment {
+
+ private static final String LEVEL_NAME = "level_name";
+
+ @Nullable private SwimmingFragment swimmingFragment;
+ private String levelName;
+
+ public void setSwimmingFragment(@NonNull SwimmingFragment swimmingFragment) {
+ this.swimmingFragment = swimmingFragment;
+ }
+
+ public static SaveLevelDialogFragment newInstance(String levelName) {
+ SaveLevelDialogFragment fragment = new SaveLevelDialogFragment();
+ Bundle bundle = new Bundle();
+ bundle.putString(LEVEL_NAME, levelName);
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final EditText editText = new EditText(getActivity());
+ this.levelName = getArguments().getString(LEVEL_NAME);
+ editText.setText(levelName);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(com.google.android.apps.santatracker.common.R.string.save_level)
+ .setView(editText)
+ .setPositiveButton(
+ com.google.android.apps.santatracker.common.R.string.save,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ if (swimmingFragment == null) {
+ throw new IllegalStateException();
+ }
+ swimmingFragment.levelManager.saveLevel(
+ swimmingFragment.modelRef.get(),
+ editText.getText().toString());
+ }
+ })
+ .setNegativeButton(
+ com.google.android.apps.santatracker.common.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(com.google.android.apps.santatracker.common.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(
+ com.google.android.apps.santatracker.common.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(
+ com.google.android.apps.santatracker.common.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ // Do nothing.
+ }
+ });
+ return builder.create();
+ }
+ }
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingLevelChunk.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingLevelChunk.java
new file mode 100644
index 000000000..2cbb3e895
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingLevelChunk.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+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 com.google.android.apps.santatracker.doodles.Config;
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import com.google.android.apps.santatracker.doodles.shared.actor.Actor;
+import com.google.android.apps.santatracker.doodles.shared.physics.Polygon;
+import com.google.android.apps.santatracker.doodles.shared.physics.Util;
+import com.google.android.apps.santatracker.util.SantaLog;
+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 {
+ public static final int LEVEL_LENGTH_IN_METERS = 500;
+ 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 String TAG = SwimmingLevelChunk.class.getSimpleName();
+ private static final int SOLUTION_PATH_NUM_COLS = 50;
+ private static final Random RANDOM = new Random();
+ private static final List TYPES;
+ public static Queue swimmingLevelChunks;
+ public static List pathList;
+
+ static {
+ TYPES = new ArrayList<>();
+ TYPES.add(BoundingBoxSpriteActor.ICE_CUBE);
+ TYPES.add(BoundingBoxSpriteActor.DUCK);
+ TYPES.add(BoundingBoxSpriteActor.HAND_GRAB);
+ }
+
+ public final float startY;
+ public final float endY;
+ private final float DEFAULT_OBSTACLE_DENSITY;
+ public List obstacles;
+ private SolutionPath solutionPath;
+ private boolean mirrored;
+
+ 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();
+ }
+
+ 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);
+ }
+ SantaLog.d(
+ TAG,
+ "generateAllLevelChunks: finished in "
+ + ((System.currentTimeMillis() - startTime) / 1000.0f)
+ + " seconds.");
+ }
+
+ public static SwimmingLevelChunk getNextChunk() {
+ if (!swimmingLevelChunks.isEmpty()) {
+ return swimmingLevelChunks.remove();
+ }
+ return null;
+ }
+
+ 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));
+ }
+
+ @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);
+ }
+ }
+
+ 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;
+
+ SantaLog.d(TAG, "bitmapHeight: " + bitmapHeight);
+ SantaLog.d(TAG, "chunkHeight: " + chunkHeight);
+ SantaLog.d(TAG, "numRows: " + numRows);
+ SantaLog.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/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingLevelManager.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingLevelManager.java
new file mode 100644
index 000000000..461d3ae40
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingLevelManager.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import android.content.Context;
+import android.os.Environment;
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import com.google.android.apps.santatracker.doodles.shared.actor.Actor;
+import com.google.android.apps.santatracker.util.SantaLog;
+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 {
+
+ private static final int DEFAULT_OBSTACLE_Y = -1000;
+ public static File levelsDir = null;
+
+ 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 {
+ SantaLog.w(TAG, "Unable to create object of type: " + type);
+ }
+ return actor;
+ }
+
+ @Override
+ protected SwimmingModel getEmptyModel() {
+ return new SwimmingModel();
+ }
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingModel.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingModel.java
new file mode 100644
index 000000000..7d030b8ad
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingModel.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+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.CallbackProcess;
+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.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.actor.Actor;
+import com.google.android.apps.santatracker.doodles.shared.actor.Camera;
+import com.google.android.apps.santatracker.doodles.shared.actor.CameraShake;
+import com.google.android.apps.santatracker.doodles.shared.actor.RectangularInstructionActor;
+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 {
+ public static final int LEVEL_WIDTH = 1280;
+ public static final int[] SCORE_THRESHOLDS = {30, 50, 100};
+ private static final String TAG = SwimmingModel.class.getSimpleName();
+ 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;
+ public int playCount;
+ private float countdownTimeMs = 3000;
+ private List processChains = new ArrayList<>();
+ 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());
+ }
+
+ 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;
+ }
+
+ @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 SwimmingState getState() {
+ return state;
+ }
+
+ public void setState(SwimmingState state) {
+ if (this.state != state) {
+ this.state = state;
+ timeElapsed = 0;
+ EventBus.getInstance().sendEvent(EventBus.GAME_STATE_CHANGED, 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;
+ }
+
+ 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();
+ }
+ }
+
+ /** States for the swimming game. */
+ public enum SwimmingState {
+ INTRO,
+ WAITING,
+ SWIMMING,
+ FINISHED,
+ }
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingView.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingView.java
new file mode 100644
index 000000000..a15086200
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/SwimmingView.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+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 androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import com.google.android.apps.santatracker.doodles.shared.Touchable;
+import com.google.android.apps.santatracker.doodles.shared.Vector2D;
+import com.google.android.apps.santatracker.doodles.shared.actor.Actor;
+import java.util.ArrayList;
+import java.util.List;
+
+/** The game view for the swimming game. */
+public class SwimmingView extends View {
+ public static final int WATER_BLUE = 0xffa6ffff;
+ public static final int LINES_BLUE = 0xff00d4d4;
+ public static final int NUM_LANES = 5;
+ private static final String TAG = SwimmingView.class.getSimpleName();
+ private static final int LANE_LINE_WIDTH = 10;
+ 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.
+ CreateObjectDialogFragment dialogFragment =
+ CreateObjectDialogFragment.newInstance(model.collisionObjectTypes);
+ dialogFragment.setCenter(model.camera.getWorldCoords(event.getX(), event.getY()));
+ dialogFragment.setSwimmingModel(model);
+ dialogFragment.show(
+ ((Activity) getContext()).getFragmentManager(), "create_object");
+ }
+ }
+ }
+
+ public static class CreateObjectDialogFragment extends DialogFragment {
+
+ private static final String COLLISION_OBJECT_TYPES = "collision_object_types";
+
+ @Nullable private Vector2D center;
+ private List collisionObjectTypes;
+ @Nullable private SwimmingModel model;
+
+ public void setSwimmingModel(@NonNull SwimmingModel model) {
+ this.model = model;
+ }
+
+ public void setCenter(@NonNull Vector2D center) {
+ this.center = center;
+ }
+
+ public static CreateObjectDialogFragment newInstance(List collisionObjectTypes) {
+ CreateObjectDialogFragment fragment = new CreateObjectDialogFragment();
+ Bundle bundle = new Bundle();
+ bundle.putSerializable(
+ COLLISION_OBJECT_TYPES, (ArrayList) collisionObjectTypes);
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final String[] items;
+ this.collisionObjectTypes =
+ (List) getArguments().getSerializable(COLLISION_OBJECT_TYPES);
+ items = new String[collisionObjectTypes.size()];
+ collisionObjectTypes.toArray(items);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(com.google.android.apps.santatracker.common.R.string.create_object)
+ .setItems(
+ items,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ if (model == null) {
+ throw new IllegalStateException();
+ }
+ model.createActor(center, items[which], getResources());
+ }
+ });
+ return builder.create();
+ }
+ }
+}
diff --git a/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/TestTiltModel.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/TestTiltModel.java
new file mode 100644
index 000000000..50cd9114b
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/TestTiltModel.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import com.google.android.apps.santatracker.doodles.shared.actor.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/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/TiltModel.java b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/TiltModel.java
new file mode 100644
index 000000000..5c9f67c82
--- /dev/null
+++ b/penguinswim/src/main/java/com/google/android/apps/santatracker/doodles/penguinswim/TiltModel.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.penguinswim;
+
+import com.google.android.apps.santatracker.doodles.shared.actor.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/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_01.webp
new file mode 100644
index 000000000..863fbca95
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_02.webp
new file mode 100644
index 000000000..2a069207d
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_03.webp
new file mode 100644
index 000000000..5cef0f90a
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_04.webp
new file mode 100644
index 000000000..40e3e5f50
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_05.webp
new file mode 100644
index 000000000..770b991f5
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_06.webp
new file mode 100644
index 000000000..85b1b13d7
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_07.webp
new file mode 100644
index 000000000..bc6b1cb4b
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_08.webp
new file mode 100644
index 000000000..c499bdf94
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_09.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_09.webp
new file mode 100644
index 000000000..23f6ebc33
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ascending_09.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_banner.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_banner.webp
new file mode 100644
index 000000000..7ea3b31e3
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_banner.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_01.webp
new file mode 100644
index 000000000..81cef5125
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_02.webp
new file mode 100644
index 000000000..855909c8c
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_03.webp
new file mode 100644
index 000000000..4a1bfde2a
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_04.webp
new file mode 100644
index 000000000..a1cb365bb
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_05.webp
new file mode 100644
index 000000000..7647b1635
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_candy_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_01.webp
new file mode 100644
index 000000000..707dee08f
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_02.webp
new file mode 100644
index 000000000..3d2a1ef8c
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_03.webp
new file mode 100644
index 000000000..c6533cfc5
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_04.webp
new file mode 100644
index 000000000..5606bb8b9
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_05.webp
new file mode 100644
index 000000000..0900170bc
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_06.webp
new file mode 100644
index 000000000..639d7cac0
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_07.webp
new file mode 100644
index 000000000..d18da63e5
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_08.webp
new file mode 100644
index 000000000..b53d1650d
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_09.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_09.webp
new file mode 100644
index 000000000..56c088106
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_09.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_10.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_10.webp
new file mode 100644
index 000000000..e9dc1e805
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_10.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_11.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_11.webp
new file mode 100644
index 000000000..c2f3aec38
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_11.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_12.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_12.webp
new file mode 100644
index 000000000..506d703cc
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_12.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_13.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_13.webp
new file mode 100644
index 000000000..a1e823e23
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_13.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_14.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_14.webp
new file mode 100644
index 000000000..1cab4deb6
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_14.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_15.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_15.webp
new file mode 100644
index 000000000..a9fcb51eb
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_15.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_16.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_16.webp
new file mode 100644
index 000000000..8fbed31eb
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_16.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_17.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_17.webp
new file mode 100644
index 000000000..59084dc54
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_17.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_18.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_18.webp
new file mode 100644
index 000000000..2f0812ef8
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_18.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_19.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_19.webp
new file mode 100644
index 000000000..b1cd956d0
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_19.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_20.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_20.webp
new file mode 100644
index 000000000..6f116640c
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_20.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_21.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_21.webp
new file mode 100644
index 000000000..a690fe4c8
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_21.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_22.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_22.webp
new file mode 100644
index 000000000..ba095e1a2
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_22.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_23.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_23.webp
new file mode 100644
index 000000000..d9741b4c8
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_23.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_24.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_24.webp
new file mode 100644
index 000000000..3be5c0816
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_24.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_25.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_25.webp
new file mode 100644
index 000000000..021ce57a2
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_25.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_26.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_26.webp
new file mode 100644
index 000000000..1ce32d2d3
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_26.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_27.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_27.webp
new file mode 100644
index 000000000..1f952dbf9
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_27.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_28.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_28.webp
new file mode 100644
index 000000000..3460d9773
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_28.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_29.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_29.webp
new file mode 100644
index 000000000..b493cdddc
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_29.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_30.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_30.webp
new file mode 100644
index 000000000..2df553c47
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_canegrab_30.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_01.webp
new file mode 100644
index 000000000..91680a1e1
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_02.webp
new file mode 100644
index 000000000..9deb30417
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_03.webp
new file mode 100644
index 000000000..c1cd83e51
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_04.webp
new file mode 100644
index 000000000..57379db63
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_05.webp
new file mode 100644
index 000000000..97beb07cb
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_06.webp
new file mode 100644
index 000000000..3df13e70f
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_07.webp
new file mode 100644
index 000000000..74551a2fe
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_08.webp
new file mode 100644
index 000000000..3c47d0ad6
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_09.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_09.webp
new file mode 100644
index 000000000..cdaa8ee30
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_09.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_10.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_10.webp
new file mode 100644
index 000000000..2a0cee7b8
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_10.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_11.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_11.webp
new file mode 100644
index 000000000..90d9bed59
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_11.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_12.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_12.webp
new file mode 100644
index 000000000..5eff54922
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_12.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_13.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_13.webp
new file mode 100644
index 000000000..8c8319380
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_13.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_14.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_14.webp
new file mode 100644
index 000000000..ae3b52cfd
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_14.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_15.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_15.webp
new file mode 100644
index 000000000..daef2e514
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_15.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_16.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_16.webp
new file mode 100644
index 000000000..82569d29f
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_16.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_17.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_17.webp
new file mode 100644
index 000000000..8b6223c1b
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_17.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_18.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_18.webp
new file mode 100644
index 000000000..a7d1465aa
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_18.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_19.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_19.webp
new file mode 100644
index 000000000..8df28bb09
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_19.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_20.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_20.webp
new file mode 100644
index 000000000..70e67aef3
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_20.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_21.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_21.webp
new file mode 100644
index 000000000..cbf66bab8
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_dazed_21.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_01.webp
new file mode 100644
index 000000000..156ff3307
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_02.webp
new file mode 100644
index 000000000..6e0df67d5
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_03.webp
new file mode 100644
index 000000000..7c5094780
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_04.webp
new file mode 100644
index 000000000..813e90dbb
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_05.webp
new file mode 100644
index 000000000..770b991f5
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_06.webp
new file mode 100644
index 000000000..0c0f77a0d
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_07.webp
new file mode 100644
index 000000000..5d7bfdf38
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_08.webp
new file mode 100644
index 000000000..627663c11
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_09.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_09.webp
new file mode 100644
index 000000000..74ad2a308
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_descending_09.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_01.webp
new file mode 100644
index 000000000..7d1964e6b
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_02.webp
new file mode 100644
index 000000000..86f98b207
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_03.webp
new file mode 100644
index 000000000..de66fb76c
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_04.webp
new file mode 100644
index 000000000..0be733696
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_05.webp
new file mode 100644
index 000000000..04922ff92
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_06.webp
new file mode 100644
index 000000000..a053b1ff8
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_07.webp
new file mode 100644
index 000000000..93b23a5f0
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_08.webp
new file mode 100644
index 000000000..44df9ad37
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_09.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_09.webp
new file mode 100644
index 000000000..f81f28734
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_09.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_10.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_10.webp
new file mode 100644
index 000000000..27a7f62c7
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_10.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_11.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_11.webp
new file mode 100644
index 000000000..1facac262
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_11.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_12.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_12.webp
new file mode 100644
index 000000000..af1a76dd4
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_12.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_13.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_13.webp
new file mode 100644
index 000000000..de66fb76c
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_13.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_14.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_14.webp
new file mode 100644
index 000000000..86f98b207
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_14.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_15.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_15.webp
new file mode 100644
index 000000000..7d1964e6b
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_elf_15.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_01.webp
new file mode 100644
index 000000000..4894a3805
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_02.webp
new file mode 100644
index 000000000..659035543
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_03.webp
new file mode 100644
index 000000000..ad502f79d
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_04.webp
new file mode 100644
index 000000000..e77a2dc03
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_05.webp
new file mode 100644
index 000000000..8e6d7d5e7
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_06.webp
new file mode 100644
index 000000000..219c04b62
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_07.webp
new file mode 100644
index 000000000..4485dd9d3
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_08.webp
new file mode 100644
index 000000000..ad4f10549
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_09.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_09.webp
new file mode 100644
index 000000000..b12d7381e
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_09.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_10.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_10.webp
new file mode 100644
index 000000000..5b3c905c1
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_10.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_11.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_11.webp
new file mode 100644
index 000000000..4e8019f1a
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_11.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_12.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_12.webp
new file mode 100644
index 000000000..7778acd7a
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_12.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_13.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_13.webp
new file mode 100644
index 000000000..c240f09fa
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_13.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_14.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_14.webp
new file mode 100644
index 000000000..07317ecd7
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_14.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_15.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_15.webp
new file mode 100644
index 000000000..74024fcd1
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_15.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_16.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_16.webp
new file mode 100644
index 000000000..fe558f43a
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_16.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_17.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_17.webp
new file mode 100644
index 000000000..b80eee330
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_17.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_18.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_18.webp
new file mode 100644
index 000000000..76a7a225d
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_18.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_19.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_19.webp
new file mode 100644
index 000000000..12e34d4d7
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_19.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_20.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_20.webp
new file mode 100644
index 000000000..c31c763ab
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_20.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_21.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_21.webp
new file mode 100644
index 000000000..8f0cc258c
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_21.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_22.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_22.webp
new file mode 100644
index 000000000..3f1404af8
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_22.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_23.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_23.webp
new file mode 100644
index 000000000..53eb07c32
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_23.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_24.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_24.webp
new file mode 100644
index 000000000..4b45d041f
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_24.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_25.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_25.webp
new file mode 100644
index 000000000..d40ce5209
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_25.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_26.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_26.webp
new file mode 100644
index 000000000..8995d0f63
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_26.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_27.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_27.webp
new file mode 100644
index 000000000..4b3da4712
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_27.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_28.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_28.webp
new file mode 100644
index 000000000..c0f054243
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_frozen_28.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_01.webp
new file mode 100644
index 000000000..faa2a006b
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_02.webp
new file mode 100644
index 000000000..5812c8ca3
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_03.webp
new file mode 100644
index 000000000..ef84b4e71
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_04.webp
new file mode 100644
index 000000000..4907912d7
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_05.webp
new file mode 100644
index 000000000..00d4217d1
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_06.webp
new file mode 100644
index 000000000..f484c78ea
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_07.webp
new file mode 100644
index 000000000..fcf925212
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_08.webp
new file mode 100644
index 000000000..1bc3c354c
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_09.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_09.webp
new file mode 100644
index 000000000..fcf925212
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_09.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_10.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_10.webp
new file mode 100644
index 000000000..f484c78ea
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_10.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_11.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_11.webp
new file mode 100644
index 000000000..00d4217d1
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_11.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_12.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_12.webp
new file mode 100644
index 000000000..4907912d7
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_12.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_13.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_13.webp
new file mode 100644
index 000000000..ef84b4e71
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_13.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_14.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_14.webp
new file mode 100644
index 000000000..5812c8ca3
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_14.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_15.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_15.webp
new file mode 100644
index 000000000..faa2a006b
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_ice_15.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_01.webp
new file mode 100644
index 000000000..08f2c6386
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_02.webp
new file mode 100644
index 000000000..08f2c6386
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_03.webp
new file mode 100644
index 000000000..6824fcbfd
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_04.webp
new file mode 100644
index 000000000..6824fcbfd
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_05.webp
new file mode 100644
index 000000000..08f2c6386
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_06.webp
new file mode 100644
index 000000000..08f2c6386
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_07.webp
new file mode 100644
index 000000000..6824fcbfd
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_08.webp
new file mode 100644
index 000000000..6824fcbfd
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_09.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_09.webp
new file mode 100644
index 000000000..1e5ed49c1
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_09.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_10.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_10.webp
new file mode 100644
index 000000000..1e5ed49c1
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_10.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_11.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_11.webp
new file mode 100644
index 000000000..97ad063e0
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_11.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_12.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_12.webp
new file mode 100644
index 000000000..dbf9ffac3
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_12.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_13.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_13.webp
new file mode 100644
index 000000000..4aee0fb6f
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_13.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_14.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_14.webp
new file mode 100644
index 000000000..4aee0fb6f
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_14.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_15.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_15.webp
new file mode 100644
index 000000000..c558eb9c1
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_15.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_16.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_16.webp
new file mode 100644
index 000000000..b3ce21d7e
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_start_16.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_01.webp
new file mode 100644
index 000000000..7e38e60fd
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_02.webp
new file mode 100644
index 000000000..348663f69
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_03.webp
new file mode 100644
index 000000000..0cb1fc7d9
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_04.webp
new file mode 100644
index 000000000..5c499ce64
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_05.webp
new file mode 100644
index 000000000..e311d5561
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_06.webp
new file mode 100644
index 000000000..c672c7478
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_07.webp
new file mode 100644
index 000000000..ec19d37d9
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_08.webp
new file mode 100644
index 000000000..e26b62107
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_09.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_09.webp
new file mode 100644
index 000000000..6c8c8b5dd
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_09.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_10.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_10.webp
new file mode 100644
index 000000000..8622acb00
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_10.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_11.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_11.webp
new file mode 100644
index 000000000..cdc6f9fcd
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_11.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_12.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_12.webp
new file mode 100644
index 000000000..fff3f9f2d
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_12.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_13.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_13.webp
new file mode 100644
index 000000000..a56664371
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_13.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_14.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_14.webp
new file mode 100644
index 000000000..fb050550e
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_14.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_15.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_15.webp
new file mode 100644
index 000000000..5426f53cc
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_15.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_16.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_16.webp
new file mode 100644
index 000000000..35f4b63f5
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimming_16.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_01.webp
new file mode 100644
index 000000000..2a7246dfa
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_02.webp
new file mode 100644
index 000000000..5a34d413d
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_03.webp
new file mode 100644
index 000000000..365901615
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_04.webp
new file mode 100644
index 000000000..0e1e0e329
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_05.webp
new file mode 100644
index 000000000..8b9fa530d
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_06.webp
new file mode 100644
index 000000000..a8ebb71ad
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_07.webp
new file mode 100644
index 000000000..06de2ecca
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_08.webp
new file mode 100644
index 000000000..0401b9394
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_09.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_09.webp
new file mode 100644
index 000000000..bbae4505a
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_09.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_10.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_10.webp
new file mode 100644
index 000000000..ee444c97a
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_10.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_11.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_11.webp
new file mode 100644
index 000000000..0f1e43ea4
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_11.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_12.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_12.webp
new file mode 100644
index 000000000..89bc704b2
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_swimmingunderwater_12.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_01.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_01.webp
new file mode 100644
index 000000000..5da53dbd8
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_02.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_02.webp
new file mode 100644
index 000000000..7d2b8097e
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_03.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_03.webp
new file mode 100644
index 000000000..5da53dbd8
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_04.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_04.webp
new file mode 100644
index 000000000..7d2b8097e
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_05.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_05.webp
new file mode 100644
index 000000000..c7334b8e2
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_06.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_06.webp
new file mode 100644
index 000000000..f89a6ea10
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_07.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_07.webp
new file mode 100644
index 000000000..b7897f1f9
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_08.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_08.webp
new file mode 100644
index 000000000..479bd1117
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swim_tutorials_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swimming_candycane_endscreen.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swimming_candycane_endscreen.webp
new file mode 100644
index 000000000..3d43f8c29
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swimming_candycane_endscreen.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swimming_dazed_endscreen.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swimming_dazed_endscreen.webp
new file mode 100644
index 000000000..66bdd1c77
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swimming_dazed_endscreen.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/penguin_swimming_frozen_endscreen.webp b/penguinswim/src/main/res/drawable-nodpi/penguin_swimming_frozen_endscreen.webp
new file mode 100644
index 000000000..129c90328
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/penguin_swimming_frozen_endscreen.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/swimming_rings_00.webp b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_00.webp
new file mode 100644
index 000000000..fd5aff706
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_00.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/swimming_rings_01.webp b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_01.webp
new file mode 100644
index 000000000..3ec5a9394
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_01.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/swimming_rings_02.webp b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_02.webp
new file mode 100644
index 000000000..089dd4328
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_02.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/swimming_rings_03.webp b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_03.webp
new file mode 100644
index 000000000..4cd91013c
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_03.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/swimming_rings_04.webp b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_04.webp
new file mode 100644
index 000000000..cd91f0e07
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_04.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/swimming_rings_05.webp b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_05.webp
new file mode 100644
index 000000000..4068bf1e3
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_05.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/swimming_rings_06.webp b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_06.webp
new file mode 100644
index 000000000..8a7d4327e
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_06.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/swimming_rings_07.webp b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_07.webp
new file mode 100644
index 000000000..a53a073d5
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_07.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/swimming_rings_08.webp b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_08.webp
new file mode 100644
index 000000000..36b4de0fe
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_08.webp differ
diff --git a/penguinswim/src/main/res/drawable-nodpi/swimming_rings_09.webp b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_09.webp
new file mode 100644
index 000000000..d8e2560f0
Binary files /dev/null and b/penguinswim/src/main/res/drawable-nodpi/swimming_rings_09.webp differ
diff --git a/penguinswim/src/main/res/drawable/swimming_dive_arrow.webp b/penguinswim/src/main/res/drawable/swimming_dive_arrow.webp
new file mode 100644
index 000000000..845e88cff
Binary files /dev/null and b/penguinswim/src/main/res/drawable/swimming_dive_arrow.webp differ
diff --git a/penguinswim/src/main/res/raw/diamond.webp b/penguinswim/src/main/res/raw/diamond.webp
new file mode 100644
index 000000000..c9f5c9cba
Binary files /dev/null and b/penguinswim/src/main/res/raw/diamond.webp differ
diff --git a/penguinswim/src/main/res/raw/fork_in.webp b/penguinswim/src/main/res/raw/fork_in.webp
new file mode 100644
index 000000000..61fd13b45
Binary files /dev/null and b/penguinswim/src/main/res/raw/fork_in.webp differ
diff --git a/penguinswim/src/main/res/raw/fork_out.webp b/penguinswim/src/main/res/raw/fork_out.webp
new file mode 100644
index 000000000..c1919b3ab
Binary files /dev/null and b/penguinswim/src/main/res/raw/fork_out.webp differ
diff --git a/penguinswim/src/main/res/raw/middle_open.webp b/penguinswim/src/main/res/raw/middle_open.webp
new file mode 100644
index 000000000..84da31644
Binary files /dev/null and b/penguinswim/src/main/res/raw/middle_open.webp differ
diff --git a/penguinswim/src/main/res/raw/swimming_dive_down.ogg b/penguinswim/src/main/res/raw/swimming_dive_down.ogg
new file mode 100644
index 000000000..5dce94edb
Binary files /dev/null and b/penguinswim/src/main/res/raw/swimming_dive_down.ogg differ
diff --git a/penguinswim/src/main/res/raw/swimming_dive_up.ogg b/penguinswim/src/main/res/raw/swimming_dive_up.ogg
new file mode 100644
index 000000000..987bb63d6
Binary files /dev/null and b/penguinswim/src/main/res/raw/swimming_dive_up.ogg differ
diff --git a/penguinswim/src/main/res/raw/swimming_duck_collide.ogg b/penguinswim/src/main/res/raw/swimming_duck_collide.ogg
new file mode 100644
index 000000000..4b356af71
Binary files /dev/null and b/penguinswim/src/main/res/raw/swimming_duck_collide.ogg differ
diff --git a/penguinswim/src/main/res/raw/swimming_grab.ogg b/penguinswim/src/main/res/raw/swimming_grab.ogg
new file mode 100644
index 000000000..e50b8f514
Binary files /dev/null and b/penguinswim/src/main/res/raw/swimming_grab.ogg differ
diff --git a/penguinswim/src/main/res/raw/swimming_ice_collide.ogg b/penguinswim/src/main/res/raw/swimming_ice_collide.ogg
new file mode 100644
index 000000000..b088b7ab5
Binary files /dev/null and b/penguinswim/src/main/res/raw/swimming_ice_collide.ogg differ
diff --git a/penguinswim/src/main/res/raw/swimming_ice_splash_a.ogg b/penguinswim/src/main/res/raw/swimming_ice_splash_a.ogg
new file mode 100644
index 000000000..2cfb7f2d5
Binary files /dev/null and b/penguinswim/src/main/res/raw/swimming_ice_splash_a.ogg differ
diff --git a/penguinswim/src/main/res/raw/zig.webp b/penguinswim/src/main/res/raw/zig.webp
new file mode 100644
index 000000000..042d81c03
Binary files /dev/null and b/penguinswim/src/main/res/raw/zig.webp differ
diff --git a/penguinswim/src/main/res/raw/ziggeroo.webp b/penguinswim/src/main/res/raw/ziggeroo.webp
new file mode 100644
index 000000000..ad7344d64
Binary files /dev/null and b/penguinswim/src/main/res/raw/ziggeroo.webp differ
diff --git a/penguinswim/src/main/res/values-sw360dp/dimens.xml b/penguinswim/src/main/res/values-sw360dp/dimens.xml
new file mode 100644
index 000000000..a26ad4c6f
--- /dev/null
+++ b/penguinswim/src/main/res/values-sw360dp/dimens.xml
@@ -0,0 +1,27 @@
+
+
+
+
+ 20dp
+ 30dp
+ 60dp
+ 240dp
+ 70dp
+ 8dp
+ 16sp
+ 90dp
+
diff --git a/penguinswim/src/main/res/values-sw600dp/dimens.xml b/penguinswim/src/main/res/values-sw600dp/dimens.xml
new file mode 100644
index 000000000..4438dce37
--- /dev/null
+++ b/penguinswim/src/main/res/values-sw600dp/dimens.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ 20dp
+ 16sp
+ 120dp
+ 80dp
+ 140dp
+ 100dp
+ 280dp
+ 20dp
+ 70dp
+ 8dp
+ 16sp
+ 100dp
+ 80dp
+ 70dp
+ 240dp
+
diff --git a/penguinswim/src/main/res/values/colors.xml b/penguinswim/src/main/res/values/colors.xml
new file mode 100644
index 000000000..96cc71577
--- /dev/null
+++ b/penguinswim/src/main/res/values/colors.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ #fed32b
+
diff --git a/penguinswim/src/main/res/values/dimens.xml b/penguinswim/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..e54734a4a
--- /dev/null
+++ b/penguinswim/src/main/res/values/dimens.xml
@@ -0,0 +1,58 @@
+
+
+
+
+ 48dp
+ 25dp
+ 25dp
+ 76dp
+ 76dp
+ 24dp
+ 40dp
+ 3dp
+ 130dp
+ 25dp
+ 100sp
+ 100dp
+ 80dp
+ 40dp
+ 348dp
+ 148dp
+ 5dp
+ 70dp
+ 50dp
+ 100dp
+ 80dp
+ 15dp
+ 12sp
+ 200dp
+ 40dp
+ 10dp
+ 10dp
+ 20dp
+ 60dp
+ 6dp
+ 12sp
+ 10dp
+ 80dp
+ 46dp
+ 40dp
+ 138dp
+ 20sp
+ 20dp
+ 40dp
+
diff --git a/penguinswim/src/main/res/values/values_analytics.xml b/penguinswim/src/main/res/values/values_analytics.xml
new file mode 100644
index 000000000..d81ffb249
--- /dev/null
+++ b/penguinswim/src/main/res/values/values_analytics.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ Swimming
+ Running
+ PresentToss
+
diff --git a/playgames/build.gradle b/playgames/build.gradle
new file mode 100644
index 000000000..008953e38
--- /dev/null
+++ b/playgames/build.gradle
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.tools
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ }
+}
+
+dependencies {
+ implementation project(':common')
+
+ implementation rootProject.ext.appCompat
+ implementation rootProject.ext.playCore
+ implementation (rootProject.ext.firebaseAppindexing) {
+ exclude group: 'com.android.support', module: 'support-v4'
+ }
+ implementation (rootProject.ext.playServicesGames) {
+ exclude group: 'com.android.support', module: 'support-v4'
+ }
+}
diff --git a/playgames/lint.xml b/playgames/lint.xml
new file mode 100644
index 000000000..ba0b137e5
--- /dev/null
+++ b/playgames/lint.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/playgames/src/main/AndroidManifest.xml b/playgames/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..26aed4047
--- /dev/null
+++ b/playgames/src/main/AndroidManifest.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/TopCropImageView.java b/playgames/src/main/java/com/google/android/apps/playgames/TopCropImageView.java
similarity index 86%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/TopCropImageView.java
rename to playgames/src/main/java/com/google/android/apps/playgames/TopCropImageView.java
index 96a530713..ac1a5ef56 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/TopCropImageView.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/TopCropImageView.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games;
+package com.google.android.apps.playgames;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.widget.ImageView;
+import androidx.appcompat.widget.AppCompatImageView;
-public class TopCropImageView extends ImageView {
+public class TopCropImageView extends AppCompatImageView {
public TopCropImageView(Context context) {
super(context);
@@ -50,6 +50,5 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
}
}
diff --git a/playgames/src/main/java/com/google/android/apps/playgames/Utils.java b/playgames/src/main/java/com/google/android/apps/playgames/Utils.java
new file mode 100644
index 000000000..ff2926f1f
--- /dev/null
+++ b/playgames/src/main/java/com/google/android/apps/playgames/Utils.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.playgames;
+
+import android.app.Activity;
+import androidx.fragment.app.Fragment;
+import com.google.android.apps.playgames.common.PlayGamesActivity;
+import com.google.android.apps.santatracker.util.SantaLog;
+
+public class Utils {
+
+ private static final String TAG = "SantaTracker";
+
+ public static PlayGamesActivity getPlayGamesActivity(Fragment fragment) {
+ Activity act = fragment.getActivity();
+ if (act == null || !(act instanceof PlayGamesActivity)) {
+ SantaLog.w(TAG, "Fragment is not in a PlayGamesActivity!");
+ return null;
+ }
+ return (PlayGamesActivity) act;
+ }
+
+ public static boolean isSignedIn(Fragment fragment) {
+ PlayGamesActivity gamesActivity = getPlayGamesActivity(fragment);
+ return gamesActivity != null && gamesActivity.isSignedIn();
+ }
+}
diff --git a/playgames/src/main/java/com/google/android/apps/playgames/common/GameActivity.java b/playgames/src/main/java/com/google/android/apps/playgames/common/GameActivity.java
new file mode 100644
index 000000000..5b0102fdf
--- /dev/null
+++ b/playgames/src/main/java/com/google/android/apps/playgames/common/GameActivity.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.playgames.common;
+
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.graphics.drawable.ColorDrawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.Window;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.content.ContextCompat;
+import com.google.android.apps.playgames.R;
+import com.google.android.apps.santatracker.games.PlayGamesFragment;
+import com.google.android.apps.santatracker.games.SignInListener;
+import com.google.android.apps.santatracker.util.ImmersiveModeHelper;
+import com.google.android.apps.santatracker.util.SantaLog;
+import com.google.android.gms.appindexing.AppIndex;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.PendingResult;
+import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.common.api.Status;
+
+@SuppressLint("Registered")
+public abstract class GameActivity extends AppCompatActivity implements SignInListener {
+
+ private static final String TAG = "GameActivity";
+
+ /** Non-visible fragment encapsulating Play Games logic. */
+ private PlayGamesFragment mGamesFragment;
+
+ // we need a separate API client for App Indexing
+ // so that view and ViewEnd events can be recorded even
+ // when the user is not signed in
+ GoogleApiClient mApiClient = null;
+ boolean mSignedIn = false;
+
+ // base URL for deep links required by App Indexing
+ // Deep link intent filter entries in AndroidManifest.xml must match
+ // the data part of this prefix
+ private static Uri BASE_APP_URI;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ supportRequestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
+
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayShowTitleEnabled(false);
+ actionBar.setHomeButtonEnabled(false);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setBackgroundDrawable(
+ new ColorDrawable(ContextCompat.getColor(this, android.R.color.transparent)));
+ }
+
+ mGamesFragment = PlayGamesFragment.getInstance(this, this);
+
+ mApiClient = new GoogleApiClient.Builder(this).addApi(AppIndex.APP_INDEX_API).build();
+ // add App Indexing API
+ BASE_APP_URI =
+ Uri.parse(
+ "android-app://"
+ + getApplicationContext().getPackageName()
+ + "/"
+ + getResources()
+ .getString(R.string.santa_tracker_deep_link_prefix));
+
+ ImmersiveModeHelper.setImmersiveSticky(getWindow());
+ ImmersiveModeHelper.installSystemUiVisibilityChangeListener(getWindow());
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (hasFocus) {
+ ImmersiveModeHelper.setImmersiveSticky(getWindow());
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ appIndexingRecordView();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ appIndexingRecordViewEnd();
+ }
+
+ @Override
+ public void onActivityResult(int req, int resp, Intent data) {
+ super.onActivityResult(req, resp, data);
+ mGamesFragment.onActivityResult(req, resp, data);
+ }
+
+ @Override
+ public void onSignInFailed() {
+ mSignedIn = false;
+ }
+
+ @Override
+ public void onSignInSucceeded() {
+ mSignedIn = true;
+ }
+
+ public boolean isSignedIn() {
+ return mSignedIn;
+ }
+
+ public void beginUserInitiatedSignIn() {
+ mGamesFragment.beginUserInitiatedSignIn();
+ }
+
+ public GoogleApiClient getGamesApiClient() {
+ return mGamesFragment.getGamesApiClient();
+ }
+
+ /**
+ * Connect the client, record the view using App Indexing API. We're not connecting the client
+ * in the activity lifecycle method to maintain symmetry with appIndexingRecordViewEnd which
+ * disconnects the client once the view is recorded
+ */
+ private void appIndexingRecordView() {
+ // connect the client
+ mApiClient.connect();
+ // Define a title for your current page, shown in autocompletion UI
+ final String title = getGameTitle();
+ final Uri appUri = getGameDeepLinkUri();
+
+ // Call the App Indexing API view method
+ PendingResult result =
+ AppIndex.AppIndexApi.view(mApiClient, this, appUri, title, null, null);
+
+ result.setResultCallback(
+ new ResultCallback() {
+ @Override
+ public void onResult(Status status) {
+ if (status.isSuccess()) {
+ SantaLog.v(
+ TAG,
+ String.format(
+ "App Indexing API: Recorded ["
+ + title
+ + "] view successfully."));
+ } else {
+ SantaLog.e(
+ TAG,
+ "App Indexing API: There was an error recording the view."
+ + status.toString());
+ }
+ }
+ });
+ }
+
+ /**
+ * Record the view end using the App Indexing API, disconnect the client once the view is
+ * recorded.
+ */
+ private void appIndexingRecordViewEnd() {
+ final Uri appUri = getGameDeepLinkUri();
+ final String title = getGameTitle();
+ PendingResult result = AppIndex.AppIndexApi.viewEnd(mApiClient, this, appUri);
+ result.setResultCallback(
+ new ResultCallback() {
+ @Override
+ public void onResult(Status status) {
+ mApiClient.disconnect(); // disconnecting here because of a potential race
+ if (status.isSuccess()) {
+ SantaLog.v(
+ TAG,
+ "App Indexing API: Recorded ["
+ + title
+ + "] view end successfully.");
+ } else {
+ SantaLog.e(
+ TAG,
+ "App Indexing API: There was an error recording the view end."
+ + status.toString());
+ }
+ }
+ });
+ }
+
+ /**
+ * See https://developers.google.com/app-indexing/webmasters/appindexingapi
+ *
+ * @return deep link representing this game
+ */
+ public Uri getGameDeepLinkUri() {
+ return BASE_APP_URI.buildUpon().appendPath(String.valueOf(getGameId())).build();
+ }
+
+ /**
+ * This is the ID which becomes a part of the deep link. For example:
+ * android-app://com.google.android.apps.santatracker/http/google.com/santatracker/gumball This
+ * value need not be human-readable, it sent in the Intent back to the Santa Tracker by the
+ * Google App. When extending this class and providing new deep links, make sure to update the
+ * corresponding intent-filter in AndroidManifest.xml.
+ *
+ * @return deep link component to identify the game to app indexing API
+ */
+ public abstract String getGameId();
+
+ /**
+ * This name will be shown to users in the Google app for autocompletion
+ *
+ * @return user-visible game title
+ */
+ public abstract String getGameTitle();
+}
diff --git a/playgames/src/main/java/com/google/android/apps/playgames/common/GameConstants.java b/playgames/src/main/java/com/google/android/apps/playgames/common/GameConstants.java
new file mode 100644
index 000000000..d87eb254d
--- /dev/null
+++ b/playgames/src/main/java/com/google/android/apps/playgames/common/GameConstants.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.playgames.common;
+
+import com.google.android.apps.playgames.R;
+
+/** Constants for the memory match and gumball games. */
+public class GameConstants {
+
+ /** Name of the preferences file for the gumball and memory match games. */
+ public static final String PREFERENCES_FILENAME = "match_gumball_games";
+ /** Key of the preference indicating that the memory match instructions have been viewed. */
+ public static final String MATCH_INSTRUCTIONS_VIEWED = "MATCH_INSTRUCTIONS_VIEWED";
+ /** Key of the preference indicating that the gumball instructions have been viewed. */
+ public static final String GUMBALL_INSTRUCTIONS_VIEWED = "GUMBALL_INSTRUCTIONS_VIEWED";
+
+ /**
+ * ID of the string resource pointing to the Play Games leaderboard game ID for the memory match
+ * game.
+ */
+ public static final int LEADERBOARDS_MATCH = R.string.leaderboard_memory;
+ /**
+ * ID of the string resource pointing to the Play Games leaderboard game ID for the gumball
+ * game.
+ */
+ public static final int LEADERBOARDS_GUMBALL = R.string.leaderboard_gumball;
+
+ /** Initial time for the gumball game. */
+ public static final long GUMBALL_INIT_TIME = 60000;
+ /** Time to add to the countdown when a gumball is dropped. */
+ public static final long GUMBALL_ADDED_TIME = 5000;
+ /** Initial time for the memory match game. */
+ public static final long MATCH_INIT_TIME = 60000;
+ /** Time to add to the countdown for each successful match in the memory match game. */
+ public static final long MATCH_ADD_TIME_NEXT_LEVEL = 5000;
+}
diff --git a/playgames/src/main/java/com/google/android/apps/playgames/common/PlayGamesActivity.java b/playgames/src/main/java/com/google/android/apps/playgames/common/PlayGamesActivity.java
new file mode 100644
index 000000000..a3dea5008
--- /dev/null
+++ b/playgames/src/main/java/com/google/android/apps/playgames/common/PlayGamesActivity.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.playgames.common;
+
+import android.content.Context;
+import android.os.Bundle;
+import androidx.appcompat.app.ActionBar;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.games.Games;
+import com.google.android.play.core.splitcompat.SplitCompat;
+import java.util.HashMap;
+
+public abstract class PlayGamesActivity extends GameActivity {
+
+ // list of achievements we are pending to unlock or increment (waiting for sign in)
+ // Key is the achievement ID, value is the number of steps to increment. 0 means
+ // unlock rather than increment.
+ private HashMap mAchievementsToSend = new HashMap();
+
+ // score we are pending to send (waiting for sign in). Hash of leaderboard ID to score.
+ private HashMap mScoresToSend = new HashMap();
+
+ protected abstract int getLayoutId();
+
+ @Override
+ protected void attachBaseContext(Context newBase) {
+ super.attachBaseContext(newBase);
+ SplitCompat.install(this);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(getLayoutId());
+
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayShowTitleEnabled(false);
+ actionBar.setDisplayHomeAsUpEnabled(false);
+ }
+ }
+
+ @Override
+ public boolean onSupportNavigateUp() {
+ launchStartupActivity();
+ return true;
+ }
+
+ @Override
+ public void onBackPressed() {
+ launchStartupActivity();
+ }
+
+ protected void launchStartupActivity() {
+ finish();
+ }
+
+ @Override
+ public void onSignInSucceeded() {
+ super.onSignInSucceeded();
+ tryToSendGameData();
+ }
+
+ // Call from any thread
+ public void postUnlockAchievement(final int achResId) {
+ final String achievementId = getString(achResId);
+ runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (!mAchievementsToSend.containsKey(achievementId)) {
+ mAchievementsToSend.put(achievementId, 0);
+ }
+ tryToSendGameData();
+ }
+ });
+ }
+
+ // Call from any thread
+ public void postIncrementAchievement(final int achResId, final int steps) {
+ final String achievementId = getString(achResId);
+ if (steps <= 0) {
+ return;
+ }
+ runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (!mAchievementsToSend.containsKey(achievementId)) {
+ mAchievementsToSend.put(achievementId, steps);
+ } else {
+ mAchievementsToSend.put(
+ achievementId, mAchievementsToSend.get(achievementId) + steps);
+ }
+ tryToSendGameData();
+ }
+ });
+ }
+
+ // Call from any thread
+ public void postSubmitScore(final int lbResId, final long score) {
+ final String leaderboardId = getString(lbResId);
+ runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (mScoresToSend.containsKey(leaderboardId)) {
+ long existingScore = mScoresToSend.get(leaderboardId);
+ if (existingScore >= score) {
+ return;
+ }
+ }
+ mScoresToSend.put(leaderboardId, score);
+ tryToSendGameData();
+ }
+ });
+ }
+
+ // Call from UI thread only.
+ private void tryToSendGameData() {
+ if (isSignedIn() && getGamesApiClient().isConnected()) {
+ GoogleApiClient apiClient = getGamesApiClient();
+ for (String achId : mAchievementsToSend.keySet()) {
+ int arg = mAchievementsToSend.get(achId);
+ if (arg <= 0) {
+ Games.Achievements.unlock(apiClient, achId);
+ } else {
+ Games.Achievements.increment(apiClient, achId, arg);
+ }
+ }
+ mAchievementsToSend.clear();
+
+ for (String lbId : mScoresToSend.keySet()) {
+ Games.Leaderboards.submitScore(apiClient, lbId, mScoresToSend.get(lbId));
+ }
+ mScoresToSend.clear();
+ }
+ }
+
+ public void startSignIn() {
+ if (!isSignedIn()) {
+ beginUserInitiatedSignIn();
+ }
+ }
+}
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/matching/CircleView.java b/playgames/src/main/java/com/google/android/apps/playgames/customviews/CircleView.java
similarity index 85%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/matching/CircleView.java
rename to playgames/src/main/java/com/google/android/apps/playgames/customviews/CircleView.java
index caf58bfec..ffb022874 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/matching/CircleView.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/customviews/CircleView.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.matching;
+package com.google.android.apps.playgames.customviews;
import android.content.Context;
import android.graphics.Canvas;
@@ -27,8 +27,8 @@
import android.view.View;
/**
- * View that contains a round red circle, with a cut out in its center.
- * Used for the end level screen.
+ * View that contains a round red circle, with a cut out in its center. Used for the end level
+ * screen.
*/
public class CircleView extends View {
@@ -52,12 +52,10 @@ protected void onDraw(Canvas canvas) {
try {
canvas.clipPath(mInsideCircle, Region.Op.XOR);
} catch (UnsupportedOperationException e) {
- //ignore clipping path for devices that don't support it (i.e. ICS)
+ // ignore clipping path for devices that don't support it (i.e. ICS)
}
mPaint.setColor(Color.RED);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, getHeight() / 8, mPaint);
-
}
-
}
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/matching/LevelTextView.java b/playgames/src/main/java/com/google/android/apps/playgames/customviews/LevelTextView.java
similarity index 77%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/matching/LevelTextView.java
rename to playgames/src/main/java/com/google/android/apps/playgames/customviews/LevelTextView.java
index 1edb33ee8..d7c187d7c 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/matching/LevelTextView.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/customviews/LevelTextView.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.matching;
+package com.google.android.apps.playgames.customviews;
import android.content.Context;
import android.graphics.Canvas;
@@ -25,9 +25,7 @@
import android.util.AttributeSet;
import android.view.View;
-/**
- * View that displays the level at 60% of the available height of the canvas.
- */
+/** View that displays the level at 60% of the available height of the canvas. */
public class LevelTextView extends View {
private Paint mPaint = new Paint();
@@ -40,8 +38,8 @@ public class LevelTextView extends View {
*/
public LevelTextView(Context context, AttributeSet attrs) {
super(context, attrs);
- mRobotoTypeface = Typeface.createFromAsset(getContext().getAssets(),
- "RobotoCondensed-Regular.ttf");
+
+ mRobotoTypeface = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
}
@Override
@@ -52,8 +50,11 @@ protected void onDraw(Canvas canvas) {
// Text size is set as 60% of the available height of the canvas
mPaint.setTextSize(getHeight() / 6);
mPaint.setTypeface(mRobotoTypeface);
- canvas.drawText(String.valueOf(mLevelNumber), getWidth() / 2,
- (getHeight() - (mPaint.ascent() + mPaint.descent())) / 2, mPaint);
+ canvas.drawText(
+ String.valueOf(mLevelNumber),
+ getWidth() / 2,
+ (getHeight() - (mPaint.ascent() + mPaint.descent())) / 2,
+ mPaint);
}
public void setLevelNumber(int levelNumber) {
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/BitmapTextureMaker.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/BitmapTextureMaker.java
similarity index 85%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/BitmapTextureMaker.java
rename to playgames/src/main/java/com/google/android/apps/playgames/simpleengine/BitmapTextureMaker.java
index d28867032..411eb8a6b 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/BitmapTextureMaker.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/BitmapTextureMaker.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.simpleengine;
+package com.google.android.apps.playgames.simpleengine;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.WindowManager;
-
import java.util.ArrayList;
class BitmapTextureMaker implements Runnable {
@@ -35,8 +34,7 @@ class BitmapTextureMaker implements Runnable {
private ArrayList mEntries = new ArrayList();
- BitmapTextureMaker() {
- }
+ BitmapTextureMaker() {}
public void request(int tag, int resId, String name, int dimType, float maxDim) {
if (mStartedLoading) {
@@ -60,8 +58,11 @@ public void startLoading(Context ctx) {
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mScreenWidth = wm.getDefaultDisplay().getWidth();
mScreenHeight = wm.getDefaultDisplay().getHeight();
- Logger.d("Starting async load of bitmaps. Screen dimensions " + mScreenWidth + "screenX" +
- mScreenHeight);
+ Logger.d(
+ "Starting async load of bitmaps. Screen dimensions "
+ + mScreenWidth
+ + "screenX"
+ + mScreenHeight);
Thread t = new Thread(this);
t.start();
}
@@ -77,10 +78,15 @@ class BitmapEntry {
@Override
public String toString() {
- return "[BitmapEntry name=" + name + ", " +
- ((dimType == DIM_HEIGHT) ? "maxH=" : "maxW=") + maxDim +
- ", resId=" + resId + ", bitmap=" + (bitmap == null ? "(null)" : "loaded!" +
- "]");
+ return "[BitmapEntry name="
+ + name
+ + ", "
+ + ((dimType == DIM_HEIGHT) ? "maxH=" : "maxW=")
+ + maxDim
+ + ", resId="
+ + resId
+ + ", bitmap="
+ + (bitmap == null ? "(null)" : "loaded!" + "]");
}
}
@@ -125,8 +131,13 @@ void loadBitmapEntry(BitmapEntry e) {
options.inSampleSize = inSampleSize;
options.inJustDecodeBounds = false;
e.bitmap = BitmapFactory.decodeResource(mContext.getResources(), e.resId, options);
- Logger.d("Loaded bitmap for " + e.name + ", " + e.bitmap.getWidth() + "x" +
- e.bitmap.getHeight());
+ Logger.d(
+ "Loaded bitmap for "
+ + e.name
+ + ", "
+ + e.bitmap.getWidth()
+ + "x"
+ + e.bitmap.getHeight());
}
// From http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/GameView.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/GameView.java
similarity index 91%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/GameView.java
rename to playgames/src/main/java/com/google/android/apps/playgames/simpleengine/GameView.java
index d8af99a19..c0c3213da 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/GameView.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/GameView.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.simpleengine;
+package com.google.android.apps.playgames.simpleengine;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.KeyEvent;
import android.view.MotionEvent;
-
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
diff --git a/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/Logger.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/Logger.java
new file mode 100644
index 000000000..37e9f6af7
--- /dev/null
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/Logger.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.playgames.simpleengine;
+
+import com.google.android.apps.santatracker.util.SantaLog;
+
+public class Logger {
+ private static final String TAG = "seng";
+
+ public static void d(String msg) {
+ SantaLog.d(TAG, msg);
+ }
+
+ public static void w(String msg) {
+ SantaLog.w(TAG, "!!! WARNING: " + msg);
+ }
+
+ public static void e(String msg) {
+ SantaLog.e(TAG, "*** ERROR: " + msg);
+ }
+}
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/Renderer.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/Renderer.java
similarity index 78%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/Renderer.java
rename to playgames/src/main/java/com/google/android/apps/playgames/simpleengine/Renderer.java
index 434bb13d1..2dbeb16ca 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/Renderer.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/Renderer.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.simpleengine;
+package com.google.android.apps.playgames.simpleengine;
import android.content.Context;
import android.graphics.Bitmap;
@@ -22,7 +22,6 @@
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.opengl.Matrix;
-
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
@@ -64,8 +63,8 @@ public final class Renderer {
private class TexInfo {
- int glTex = 0; // OpenGL texture handle, if loaded; 0 if not yet loaded
- float aspect; // aspect ratio (width/height), computed when texture is loaded
+ int glTex = 0; // OpenGL texture handle, if loaded; 0 if not yet loaded
+ float aspect; // aspect ratio (width/height), computed when texture is loaded
int width, height; // computed when texture is loaded
// texture request parameters
@@ -105,12 +104,9 @@ private class TexInfo {
private int mLocTexCoord = -1;
// quad data
- private static float[] QUAD_GEOM = { // screenX, screenY, z, u, v
- -0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
- 0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
- -0.5f, 0.5f, 0.0f, 0.0f, 0.0f,
- 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-
+ private static float[] QUAD_GEOM = { // screenX, screenY, z, u, v
+ -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, -0.5f, 0.5f, 0.0f, 0.0f,
+ 0.0f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
};
private final int SIZEOF_FLOAT = 4;
private final int QUAD_GEOM_VERTEX_COUNT = 4;
@@ -128,14 +124,8 @@ private class TexInfo {
// color used to clear the screen
private static final int DEFAULT_CLEAR_COLOR = 0xffff0000;
- int mClearColor = DEFAULT_CLEAR_COLOR;
- public void setClearColor(int color) {
- mClearColor = color;
- }
-
- Renderer() {
- }
+ Renderer() {}
public void onGLSurfaceCreated(Context ctx) {
initGL();
@@ -183,13 +173,25 @@ private void initGL() {
mLocSampler = GLES20.glGetUniformLocation(program, "u_Sampler");
mLocPosition = GLES20.glGetAttribLocation(program, "a_Position");
mLocTexCoord = GLES20.glGetAttribLocation(program, "a_TexCoord");
- Logger.d("Locations: " +
- "mLocMatrix=" + mLocMatrix + "; " +
- "mLocColor=" + mLocColor + "; " +
- "mLocTintFactor=" + mLocTintFactor + "; " +
- "mLocSampler=" + mLocSampler + "; " +
- "mLocPosition=" + mLocPosition + "; " +
- "mLocTexCoord=" + mLocTexCoord);
+ Logger.d(
+ "Locations: "
+ + "mLocMatrix="
+ + mLocMatrix
+ + "; "
+ + "mLocColor="
+ + mLocColor
+ + "; "
+ + "mLocTintFactor="
+ + mLocTintFactor
+ + "; "
+ + "mLocSampler="
+ + mLocSampler
+ + "; "
+ + "mLocPosition="
+ + mLocPosition
+ + "; "
+ + "mLocTexCoord="
+ + mLocTexCoord);
ByteBuffer bb = ByteBuffer.allocateDirect(SIZEOF_FLOAT * QUAD_GEOM.length);
bb.order(ByteOrder.nativeOrder());
@@ -217,8 +219,7 @@ private void pushColor(float r, float g, float b, float a, float factor) {
GLES20.glUniform1f(mLocTintFactor, factor);
}
- private void drawQuad(float centerX, float centerY, float width, float height,
- float rotation) {
+ private void drawQuad(float centerX, float centerY, float width, float height, float rotation) {
// compute final matrix
float[] modelViewM = mTmpMatA;
float[] finalM = mTmpMatB;
@@ -234,14 +235,14 @@ private void drawQuad(float centerX, float centerY, float width, float height,
// push positions
GLES20.glEnableVertexAttribArray(mLocPosition);
mQuadGeomBuf.position(QUAD_GEOM_POS_OFFSET);
- GLES20.glVertexAttribPointer(mLocPosition, 3, GLES20.GL_FLOAT, false,
- QUAD_GEOM_STRIDE, mQuadGeomBuf);
+ GLES20.glVertexAttribPointer(
+ mLocPosition, 3, GLES20.GL_FLOAT, false, QUAD_GEOM_STRIDE, mQuadGeomBuf);
// push texture coordinates
GLES20.glEnableVertexAttribArray(mLocTexCoord);
mQuadGeomBuf.position(QUAD_GEOM_TEXCOORD_OFFSET);
- GLES20.glVertexAttribPointer(mLocTexCoord, 2, GLES20.GL_FLOAT, false,
- QUAD_GEOM_STRIDE, mQuadGeomBuf);
+ GLES20.glVertexAttribPointer(
+ mLocTexCoord, 2, GLES20.GL_FLOAT, false, QUAD_GEOM_STRIDE, mQuadGeomBuf);
// draw
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, QUAD_GEOM_VERTEX_COUNT);
@@ -291,8 +292,8 @@ void onGLSurfaceChanged(int width, int height) {
// set up projection matrix
mProjMat = new float[16];
- Matrix.orthoM(mProjMat, 0, mBounds.left, mBounds.right, mBounds.bottom,
- mBounds.top, -1.0f, 1.0f);
+ Matrix.orthoM(
+ mProjMat, 0, mBounds.left, mBounds.right, mBounds.bottom, mBounds.top, -1.0f, 1.0f);
}
void generateImageTextures() {
@@ -322,6 +323,7 @@ private void generateTexture(int texIndex, Bitmap bmp) {
GLES20.glGenTextures(1, texH, 0);
TexInfo ti = mTexInfo.get(texIndex);
bitmapToGLTexture(texH[0], bmp);
+
ti.glTex = texH[0];
ti.width = bmp.getWidth();
ti.height = bmp.getHeight();
@@ -330,14 +332,14 @@ private void generateTexture(int texIndex, Bitmap bmp) {
void bitmapToGLTexture(int texH, Bitmap bmp) {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texH);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameterf(
+ GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
+ GLES20.glTexParameterf(
+ GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+ GLES20.glTexParameterf(
+ GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameterf(
+ GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
}
@@ -370,74 +372,75 @@ private void parseColor(int color, float[] out) {
out[2] *= out[3];
}
-
private float[] mTmpColor = new float[4];
public void doFrame() {
- parseColor(mClearColor, mTmpColor);
- GLES20.glClearColor(mTmpColor[0], mTmpColor[1], mTmpColor[2], mTmpColor[3]);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
if (mBitmapTextureMaker != null || mTextTextureMaker != null) {
// we are still loading textures, so don't render any sprites yet
return;
}
-
int i, size = mSprites.size();
for (i = 0; i < size; i++) {
Sprite s = mSprites.get(i);
- if (!s.enabled) {
- continue;
- }
+ drawSprite(s);
+ }
+ }
+
+ private boolean drawSprite(Sprite s) {
+ if (!s.enabled) {
+ return false;
+ }
+
+ float tintFactor = s.tintFactor;
+ TexInfo ti = null;
+ if (s.texIndex >= 0 && s.texIndex < mTexInfo.size()) {
+ ti = mTexInfo.get(s.texIndex);
+ pushTex(ti.glTex);
- float tintFactor = s.tintFactor;
- TexInfo ti = null;
- if (s.texIndex >= 0 && s.texIndex < mTexInfo.size()) {
- ti = mTexInfo.get(s.texIndex);
- pushTex(ti.glTex);
- } else {
- pushTex(0);
- tintFactor = 1.0f;
+ } else {
+ pushTex(0);
+ tintFactor = 1.0f;
+ }
+ parseColor(s.color, mTmpColor);
+ pushColor(mTmpColor[0], mTmpColor[1], mTmpColor[2], mTmpColor[3], tintFactor);
+
+ float width = s.width, height = s.height, x = s.x, y = s.y;
+
+ if (ti != null && ti.type == TexInfo.TYPE_IMAGE) {
+ width = s.width;
+ height = s.height;
+ if (Float.isNaN(width) && ti != null) {
+ // auto calculate width based on texture aspect ratio
+ width = s.width = s.height * ti.aspect;
}
- parseColor(s.color, mTmpColor);
- pushColor(mTmpColor[0], mTmpColor[1], mTmpColor[2], mTmpColor[3], tintFactor);
-
- float width = s.width, height = s.height, x = s.x, y = s.y;
-
- if (ti != null && ti.type == TexInfo.TYPE_IMAGE) {
- width = s.width;
- height = s.height;
- if (Float.isNaN(width) && ti != null) {
- // auto calculate width based on texture aspect ratio
- width = s.width = s.height * ti.aspect;
- }
- if (Float.isNaN(height) && ti != null) {
- // auto calculate height based on texture aspect ratio
- height = s.height = s.width / ti.aspect;
- }
- } else if (ti != null && ti.type == TexInfo.TYPE_TEXT) {
- // text images don't respect width/height -- they render at whatever
- // size they were created, in order to respect the originally requested font size
- width = pixelsToLogical(ti.width);
- height = pixelsToLogical(ti.height);
-
- // adjust x,y according to text anchor parameter
- int horizAnchor = ti.textAnchor & TEXT_ANCHOR_HORIZ_MASK;
- int vertAnchor = ti.textAnchor & TEXT_ANCHOR_VERT_MASK;
- if (horizAnchor == TEXT_ANCHOR_LEFT) {
- x += width * 0.5f;
- } else if (horizAnchor == TEXT_ANCHOR_RIGHT) {
- x -= width * 0.5f;
- }
- if (vertAnchor == TEXT_ANCHOR_TOP) {
- y += height * 0.5f;
- } else if (vertAnchor == TEXT_ANCHOR_BOTTOM) {
- y -= height * 0.5f;
- }
+ if (Float.isNaN(height) && ti != null) {
+ // auto calculate height based on texture aspect ratio
+ height = s.height = s.width / ti.aspect;
+ }
+ } else if (ti != null && ti.type == TexInfo.TYPE_TEXT) {
+ // text images don't respect width/height -- they render at whatever
+ // size they were created, in order to respect the originally requested font size
+ width = pixelsToLogical(ti.width);
+ height = pixelsToLogical(ti.height);
+
+ // adjust x,y according to text anchor parameter
+ int horizAnchor = ti.textAnchor & TEXT_ANCHOR_HORIZ_MASK;
+ int vertAnchor = ti.textAnchor & TEXT_ANCHOR_VERT_MASK;
+ if (horizAnchor == TEXT_ANCHOR_LEFT) {
+ x += width * 0.5f;
+ } else if (horizAnchor == TEXT_ANCHOR_RIGHT) {
+ x -= width * 0.5f;
+ }
+ if (vertAnchor == TEXT_ANCHOR_TOP) {
+ y += height * 0.5f;
+ } else if (vertAnchor == TEXT_ANCHOR_BOTTOM) {
+ y -= height * 0.5f;
}
-
- drawQuad(x, y, width, height, s.rotation);
}
+ drawQuad(x, y, width, height, s.rotation);
+ return true;
}
private float pixelsToLogical(int pixels) {
@@ -473,8 +476,8 @@ public int requestTextTex(int resId, String name, float fontSize, int textAnchor
}
public int requestTextTex(int resId, String name, float fontSize) {
- return requestTextTex(resId, name, fontSize,
- TEXT_ANCHOR_CENTER | TEXT_ANCHOR_MIDDLE, 0xffffffff);
+ return requestTextTex(
+ resId, name, fontSize, TEXT_ANCHOR_CENTER | TEXT_ANCHOR_MIDDLE, 0xffffffff);
}
public float getLeft() {
@@ -516,7 +519,6 @@ public void deleteTextures() {
}
public void reset() {
- mClearColor = DEFAULT_CLEAR_COLOR;
deleteTextures();
deleteSprites();
}
@@ -613,10 +615,14 @@ public void deleteSprites() {
}
public float getRelativePos(int relativeTo, float delta) {
- return delta + (relativeTo == REL_RIGHT ? mBounds.right :
- relativeTo == REL_LEFT ? mBounds.left :
- relativeTo == REL_TOP ? mBounds.top :
- relativeTo == REL_BOTTOM ? mBounds.bottom : 0.0f);
+ return delta
+ + (relativeTo == REL_RIGHT
+ ? mBounds.right
+ : relativeTo == REL_LEFT
+ ? mBounds.left
+ : relativeTo == REL_TOP
+ ? mBounds.top
+ : relativeTo == REL_BOTTOM ? mBounds.bottom : 0.0f);
}
public void bringToFront(Sprite sp) {
@@ -626,4 +632,12 @@ public void bringToFront(Sprite sp) {
mSprites.add(sp);
}
}
+
+ public void sendToBack(Sprite sp) {
+ int idx = mSprites.indexOf(sp);
+ if (idx > 0 && idx < mSprites.size()) {
+ mSprites.remove(idx);
+ mSprites.add(0, sp);
+ }
+ }
}
diff --git a/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/Scene.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/Scene.java
new file mode 100644
index 000000000..6b98cc682
--- /dev/null
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/Scene.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.playgames.simpleengine;
+
+public class Scene {
+
+ public void onScreenResized(int width, int height) {}
+
+ public void doStandbyFrame(float deltaT) {}
+
+ public void doFrame(float deltaT) {}
+
+ public void onInstall() {}
+
+ public void onUninstall() {}
+
+ public void onPointerDown(int pointerId, float x, float y) {}
+
+ public void onPointerMove(int pointerId, float x, float y, float deltaX, float deltaY) {}
+
+ public void onPointerUp(int pointerId, float x, float y) {}
+
+ public void onKeyDown(int keyCode, int repeatCount) {}
+
+ public void onKeyUp(int keyCode) {}
+
+ public void onSensorChanged(float x, float y, int accuracy) {}
+
+ public boolean isGameEnded() {
+ return false;
+ }
+}
diff --git a/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/SceneManager.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/SceneManager.java
new file mode 100644
index 000000000..48866dc39
--- /dev/null
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/SceneManager.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.playgames.simpleengine;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.PointF;
+import android.hardware.SensorEvent;
+import android.os.Vibrator;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.Surface;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+public class SceneManager {
+ private static final String TAG = "SceneManager";
+ private static SceneManager instance = new SceneManager();
+ private Renderer mRenderer = new Renderer();
+ private SoundManager mSoundManager = null;
+ private Scene mCurScene = null;
+ private Scene mNewScene = null;
+ private long mLastFrameTime = -1;
+ private boolean mHasGL = false;
+ private Vibrator mVibrator;
+ private Context mAppContext = null;
+
+ // reference to Activity, if it's in the resumed state -- otherwise null
+ private WeakReference mActivity = new WeakReference(null);
+ private boolean mActivityResumed = false;
+ private boolean mActivityHasFocus = false;
+
+ // queue of MotionEvents to process from the game thread
+ private ArrayList mMotionEventQueue = new ArrayList(32);
+ private ArrayList mMotionEventRecycle = new ArrayList(32);
+
+ private ArrayList mSensorEventQueue = new ArrayList<>(32);
+ private ArrayList mSensorEventRecycle = new ArrayList<>(32);
+
+ private ArrayList mTmpMotionEvent = new ArrayList(32);
+ private ArrayList mTmpSensorEvent = new ArrayList<>(32);
+ // this flag is raised by the UI thread when it adds something to mMotionEventQueue
+ // and lowered by the game thread when it processes the motion event queue. This flag
+ // should only be modified when mMotionEventQueue is locked; it can be read without
+ // locking.
+ private volatile boolean mCheckMotionEvents = false;
+
+ private boolean mLargePresentMode = false;
+
+ private volatile boolean mCheckSensorEvents = false;
+
+ // last x, y of pointer, keyed by pointer ID
+ private SparseArray mLastTouchCoords = new SparseArray();
+
+ // recycle bin of PointF objects
+ private ArrayList mPointRecycleBin = new ArrayList();
+
+ private SceneManager() {}
+
+ public static SceneManager getInstance() {
+ return instance;
+ }
+
+ void onGLSurfaceCreated(Context ctx) {
+ mHasGL = true;
+ mAppContext = ctx.getApplicationContext();
+ mRenderer.onGLSurfaceCreated(mAppContext);
+ if (mSoundManager == null) {
+ mSoundManager = new SoundManager(ctx);
+ }
+ }
+
+ void onGLSurfaceChanged(int width, int height) {
+ mRenderer.onGLSurfaceChanged(width, height);
+ if (mCurScene != null) {
+ mCurScene.onScreenResized(width, height);
+ }
+ }
+
+ private void installNewScene() {
+ if (mCurScene != null) {
+ mCurScene.onUninstall();
+ mRenderer.reset();
+ mSoundManager.reset();
+ }
+ mCurScene = mNewScene;
+ mNewScene = null;
+ if (mCurScene != null) {
+ mCurScene.onInstall();
+ mRenderer.startLoadingTexs(mAppContext);
+ }
+ }
+
+ public void onPause() {
+ mActivityResumed = false;
+ if (mSoundManager != null) {
+ mSoundManager.stopSound();
+ }
+ mActivity.clear();
+ }
+
+ public void onResume(Activity activity) {
+ mActivityResumed = true;
+ mActivity = new WeakReference(activity);
+ if (mSoundManager != null && mActivityHasFocus) {
+ mSoundManager.resumeSound();
+ }
+ }
+
+ public void setLargePresentMode(boolean largePresentMode) {
+ mLargePresentMode = largePresentMode;
+ }
+
+ public boolean getLargePresentMode() {
+ return mLargePresentMode;
+ }
+
+ public Activity getActivity() {
+ return mActivity.get();
+ }
+
+ public void onFocusChanged(boolean focus) {
+ mActivityHasFocus = focus;
+ if (!focus) {
+ mSoundManager.stopSound();
+ } else if (mActivityResumed && mSoundManager != null) {
+ mSoundManager.resumeSound();
+ }
+ }
+
+ public Vibrator getVibrator() {
+ if (mVibrator == null) {
+ mVibrator = ((Vibrator) mAppContext.getSystemService(Context.VIBRATOR_SERVICE));
+ }
+ return mVibrator;
+ }
+
+ public boolean shouldBePlaying() {
+ return mActivityResumed && mActivityHasFocus;
+ }
+
+ public Scene getCurrentScene() {
+ return mCurScene;
+ }
+
+ void onDrawFrame() {
+ if (!mHasGL) {
+ Logger.w("Ignoring request to do frame without a GL surface.");
+ return;
+ }
+ if (mNewScene != null) {
+ installNewScene();
+ }
+ if (mCurScene != null) {
+ if (mLastFrameTime < 0) {
+ mLastFrameTime = System.currentTimeMillis();
+ }
+ float deltaT = (System.currentTimeMillis() - mLastFrameTime) * 0.001f;
+ mLastFrameTime = System.currentTimeMillis();
+ if (mRenderer.prepareFrame() && mSoundManager.isReady()) {
+ mCurScene.doFrame(deltaT);
+ } else {
+ mCurScene.doStandbyFrame(deltaT);
+ }
+ }
+ mRenderer.doFrame();
+
+ // process touch events
+ if (mCheckMotionEvents) {
+ processMotionEvents();
+ }
+ if (mCheckSensorEvents) {
+ processSensorEvents();
+ }
+ }
+
+ public void requestNewScene(Scene c) {
+ mNewScene = c;
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ return false;
+ } else {
+ processKeyEvent(keyCode, event);
+ return true;
+ }
+ }
+
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ return false;
+ } else {
+ processKeyEvent(keyCode, event);
+ return true;
+ }
+ }
+
+ public void onSensorChanged(SensorEvent event) {
+ float x = 0, y = 0;
+ int rotation = Surface.ROTATION_90;
+ if (getActivity() != null) {
+ // Store the current screen rotation (used to offset the readings of the sensor).
+ rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
+ }
+
+ // Handle screen rotations by interpreting the sensor readings here
+ // Game is locked in 90 degree rotation so that config is assumed.
+ x = event.values[1];
+ y = -event.values[0];
+ queueSensorEvent(x, y, event.accuracy);
+ }
+
+ public boolean onTouchEvent(MotionEvent event) {
+ // we are running on the UI thread, so deliver the event to the queue,
+ // where the game thread will pick it up to process
+ synchronized (mMotionEventQueue) {
+ int action = event.getActionMasked();
+
+ // get updates about each pointer in the gesture
+ int i;
+ for (i = 0; i < event.getPointerCount(); i++) {
+ int pointerId = event.getPointerId(i);
+ float x = event.getX(i);
+ float y = event.getY(i);
+
+ // figure out delta from last touch event
+ float deltaX = x - getLastTouchX(pointerId, x);
+ float deltaY = y - getLastTouchY(pointerId, y);
+
+ // queue the motion event
+ queueMotionEvent(MotionEvent.ACTION_MOVE, pointerId, x, y, deltaX, deltaY);
+
+ // update last touch coordinates
+ setLastTouchCoords(pointerId, x, y);
+ }
+
+ // figure out if a pointer went up or down
+ int id;
+ PointF point;
+ switch (action) {
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ id = event.getPointerId(event.getActionIndex());
+ forgetLastTouchCoords(id);
+ queueMotionEvent(
+ MotionEvent.ACTION_UP, id, event.getX(), event.getY(), 0.0f, 0.0f);
+ break;
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ id = event.getPointerId(event.getActionIndex());
+ setLastTouchCoords(id, event.getX(), event.getY());
+ queueMotionEvent(
+ MotionEvent.ACTION_DOWN, id, event.getX(), event.getY(), 0.0f, 0.0f);
+ break;
+ }
+ }
+ return true;
+ }
+
+ private float getLastTouchX(int pointerId, float defaultX) {
+ PointF pt = mLastTouchCoords.get(pointerId, null);
+ return pt != null ? pt.x : defaultX;
+ }
+
+ private float getLastTouchY(int pointerId, float defaultY) {
+ PointF pt = mLastTouchCoords.get(pointerId, null);
+ return pt != null ? pt.y : defaultY;
+ }
+
+ private void setLastTouchCoords(int pointerId, float x, float y) {
+ PointF pt = mLastTouchCoords.get(pointerId, null);
+ if (pt == null) {
+ pt = allocPointF();
+ }
+ pt.x = x;
+ pt.y = y;
+ mLastTouchCoords.put(pointerId, pt);
+ }
+
+ private void forgetLastTouchCoords(int pointerId) {
+ PointF pt = mLastTouchCoords.get(pointerId, null);
+ if (pt != null) {
+ mLastTouchCoords.remove(pointerId);
+ recyclePointF(pt);
+ }
+ }
+
+ private PointF allocPointF() {
+ if (mPointRecycleBin.size() > 0) {
+ PointF p = mPointRecycleBin.remove(mPointRecycleBin.size() - 1);
+ p.x = p.y = 0.0f;
+ return p;
+ }
+ return new PointF();
+ }
+
+ private void recyclePointF(PointF p) {
+ mPointRecycleBin.add(p);
+ }
+
+ private void queueMotionEvent(
+ int action, int pointerId, float screenX, float screenY, float deltaX, float deltaY) {
+ OurMotionEvent e =
+ mMotionEventRecycle.size() > 0
+ ? mMotionEventRecycle.remove(mMotionEventRecycle.size() - 1)
+ : new OurMotionEvent();
+ e.action = action;
+ e.pointerId = pointerId;
+ e.screenX = screenX;
+ e.screenY = screenY;
+ e.deltaX = deltaX;
+ e.deltaY = deltaY;
+ mMotionEventQueue.add(e);
+ mCheckMotionEvents = true;
+ }
+
+ private void queueSensorEvent(float x, float y, int accuracy) {
+ OurSensorEvent e =
+ mSensorEventRecycle.size() > 0
+ ? mSensorEventRecycle.remove(mSensorEventRecycle.size() - 1)
+ : new OurSensorEvent();
+ e.x = x;
+ e.y = y;
+ e.accuracy = accuracy;
+ mSensorEventQueue.add(e);
+ mCheckSensorEvents = true;
+ }
+
+ public Renderer getRenderer() {
+ return mRenderer;
+ }
+
+ public SoundManager getSoundManager() {
+ return mSoundManager;
+ }
+
+ private void processSensorEvents() {
+ int i;
+ synchronized (mSensorEventQueue) {
+ for (i = 0; i < mSensorEventQueue.size(); i++) {
+ OurSensorEvent e = mSensorEventQueue.get(i);
+ if (e != null) {
+ mTmpSensorEvent.add(mSensorEventQueue.get(i));
+ }
+ }
+ mSensorEventQueue.clear();
+ mCheckSensorEvents = false;
+ }
+ // process the sensor events
+ for (i = 0; i < mTmpSensorEvent.size(); i++) {
+ processSensorEvent(mTmpSensorEvent.get(i));
+ }
+
+ // recycle the objects
+ synchronized (mSensorEventQueue) {
+ for (i = 0; i < mTmpMotionEvent.size(); i++) {
+ mSensorEventRecycle.add(mTmpSensorEvent.get(i));
+ }
+ mTmpSensorEvent.clear();
+ }
+ }
+
+ private void processSensorEvent(OurSensorEvent e) {
+ if (mCurScene == null) {
+ return;
+ }
+ if (e != null) {
+ mCurScene.onSensorChanged(e.x, e.y, e.accuracy);
+ }
+ }
+
+ private void processMotionEvents() {
+ int i;
+
+ // move array items to our temporary array so we can unlock the original
+ synchronized (mMotionEventQueue) {
+ for (i = 0; i < mMotionEventQueue.size(); i++) {
+ mTmpMotionEvent.add(mMotionEventQueue.get(i));
+ }
+ mMotionEventQueue.clear();
+ mCheckMotionEvents = false;
+ }
+
+ // process the motion events
+ for (i = 0; i < mTmpMotionEvent.size(); i++) {
+ processMotionEvent(mTmpMotionEvent.get(i));
+ }
+
+ // recycle the objects
+ synchronized (mMotionEventQueue) {
+ for (i = 0; i < mTmpMotionEvent.size(); i++) {
+ mMotionEventRecycle.add(mTmpMotionEvent.get(i));
+ }
+ mTmpMotionEvent.clear();
+ }
+ }
+
+ private void processMotionEvent(OurMotionEvent event) {
+ if (mCurScene == null) {
+ return;
+ }
+
+ // convert the screen coordinates to our standard coordinate system
+ float x = mRenderer.convertScreenX(event.screenX);
+ float y = mRenderer.convertScreenY(event.screenY);
+ float deltaX = mRenderer.convertScreenDeltaX(event.deltaX);
+ float deltaY = mRenderer.convertScreenDeltaY(event.deltaY);
+
+ switch (event.action) {
+ case MotionEvent.ACTION_DOWN:
+ mCurScene.onPointerDown(event.pointerId, x, y);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ mCurScene.onPointerMove(event.pointerId, x, y, deltaX, deltaY);
+ break;
+ case MotionEvent.ACTION_UP:
+ mCurScene.onPointerUp(event.pointerId, x, y);
+ break;
+ }
+ }
+
+ private void processKeyEvent(int keyCode, KeyEvent event) {
+ if (mCurScene == null) {
+ return;
+ }
+
+ // convert the screen coordinates to our standard coordinate system
+
+ switch (event.getAction()) {
+ case KeyEvent.ACTION_DOWN:
+ mCurScene.onKeyDown(keyCode, event.getRepeatCount());
+ break;
+ case KeyEvent.ACTION_UP:
+ mCurScene.onKeyUp(keyCode);
+ break;
+ }
+ }
+
+ private class OurMotionEvent {
+
+ int action;
+ int pointerId;
+ float screenX, screenY;
+ float deltaX, deltaY;
+ }
+
+ private class OurSensorEvent {
+ float x;
+ float y;
+ int accuracy;
+ }
+}
diff --git a/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ShaderSource.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ShaderSource.java
new file mode 100644
index 000000000..959c0981a
--- /dev/null
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ShaderSource.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.playgames.simpleengine;
+
+public class ShaderSource {
+
+ private static final String COMMON_DECLS =
+ "precision mediump float; \n"
+ + "uniform mat4 u_Matrix; \n"
+ + "uniform vec4 u_Color; \n"
+ + "uniform float u_TintFactor; \n"
+ + "uniform sampler2D u_Sampler; \n "
+ + "varying vec4 v_Color; \n"
+ + "varying vec2 v_TexCoord; \n";
+
+ public static final String VERTEX_SHADER =
+ COMMON_DECLS
+ + "attribute vec4 a_Position; \n"
+ + "attribute vec2 a_TexCoord; \n"
+ + "void main() \n"
+ + "{ \n"
+ + " v_Color = u_Color; \n"
+ + " v_TexCoord = a_TexCoord; \n"
+ + " gl_Position = u_Matrix * a_Position; \n"
+ + "} \n";
+
+ public static final String FRAG_SHADER =
+ COMMON_DECLS
+ + "void main() \n"
+ + "{ \n"
+ + " vec4 c = mix(texture2D(u_Sampler, v_TexCoord), u_Color, u_TintFactor);\n"
+ + " gl_FragColor = c;\n"
+ + "}\n";
+}
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/SmoothValue.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/SmoothValue.java
similarity index 92%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/SmoothValue.java
rename to playgames/src/main/java/com/google/android/apps/playgames/simpleengine/SmoothValue.java
index a95b391a8..0f3e77846 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/SmoothValue.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/SmoothValue.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.simpleengine;
+package com.google.android.apps.playgames.simpleengine;
public class SmoothValue {
@@ -26,8 +26,7 @@ public class SmoothValue {
private float mMax = Float.POSITIVE_INFINITY;
private int mSamples = 1;
- public SmoothValue() {
- }
+ public SmoothValue() {}
public SmoothValue(float initialValue, float changeSpeed) {
init(initialValue, changeSpeed, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, 1);
diff --git a/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/SoundManager.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/SoundManager.java
new file mode 100644
index 000000000..4f7021bf2
--- /dev/null
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/SoundManager.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.playgames.simpleengine;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.SoundPool;
+import com.google.android.apps.santatracker.AudioConstants;
+import com.google.android.apps.santatracker.data.SantaPreferences;
+
+public class SoundManager
+ implements MediaPlayer.OnPreparedListener, SoundPool.OnLoadCompleteListener {
+
+ MediaPlayer mBgmMediaPlayer = null;
+ boolean mBgmLoading = false;
+ Context mAppContext;
+ boolean mStoppedSound = false;
+ boolean mWantBgm = true;
+
+ SoundPool mSoundPool = null;
+ int mSoundsLoading = 0; // how many sounds are loading in the SoundPool
+
+ static final int MAX_STREAMS = 4;
+ static final int STREAM_TYPE = AudioManager.STREAM_MUSIC;
+ static final int SRC_QUALITY = 0;
+ static final int DEFAULT_PRIORITY = 1;
+
+ private final SantaPreferences mSantaPreferences;
+
+ public SoundManager(Context ctx) {
+ mAppContext = ctx.getApplicationContext();
+ mSantaPreferences = new SantaPreferences(mAppContext);
+
+ mSoundPool = new SoundPool(MAX_STREAMS, STREAM_TYPE, SRC_QUALITY);
+ mSoundPool.setOnLoadCompleteListener(this);
+ }
+
+ public void requestBackgroundMusic(int resId) {
+ mBgmMediaPlayer = MediaPlayer.create(mAppContext, resId);
+ mBgmMediaPlayer.setOnPreparedListener(this);
+ mBgmLoading = true;
+ }
+
+ public int requestSfx(int resId) {
+ mSoundsLoading++;
+ return mSoundPool.load(mAppContext, resId, DEFAULT_PRIORITY);
+ }
+
+ public void playSfx(int soundId) {
+ if (!isMuted() && !mStoppedSound) {
+ mSoundPool.play(
+ soundId,
+ AudioConstants.DEFAULT_SOUND_EFFECT_VOLUME,
+ AudioConstants.DEFAULT_SOUND_EFFECT_VOLUME,
+ DEFAULT_PRIORITY,
+ 0,
+ 1.0f);
+ }
+ }
+
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ mBgmLoading = false;
+ mBgmMediaPlayer.setVolume(
+ AudioConstants.DEFAULT_BACKGROUND_VOLUME, AudioConstants.DEFAULT_BACKGROUND_VOLUME);
+ mBgmMediaPlayer.setLooping(true);
+ updateBgm();
+ }
+
+ public boolean isReady() {
+ return !mBgmLoading && mSoundsLoading <= 0;
+ }
+
+ private void updateBgm() {
+ boolean shouldPlay = !isMuted() && mWantBgm && !mStoppedSound;
+ final MediaPlayer bgmMediaPlayer = mBgmMediaPlayer;
+ if (bgmMediaPlayer != null) {
+ if (shouldPlay && !bgmMediaPlayer.isPlaying()) {
+ bgmMediaPlayer.start();
+ } else if (!shouldPlay && bgmMediaPlayer.isPlaying()) {
+ bgmMediaPlayer.pause();
+ }
+ }
+ }
+
+ public void mute() {
+ setMute(true);
+ }
+
+ public void unmute() {
+ setMute(false);
+ }
+
+ public boolean isMuted() {
+ return mSantaPreferences.isMuted();
+ }
+
+ public void setMute(boolean mute) {
+ mSantaPreferences.setMuted(mute);
+ updateBgm();
+ }
+
+ public void stopSound() {
+ mStoppedSound = true;
+ updateBgm();
+ }
+
+ public void resumeSound() {
+ mStoppedSound = false;
+ updateBgm();
+ }
+
+ public void enableBgm(boolean enable) {
+ mWantBgm = enable;
+ updateBgm();
+ }
+
+ public void reset() {
+ if (mBgmMediaPlayer != null) {
+ if (mBgmMediaPlayer.isPlaying()) {
+ mBgmMediaPlayer.stop();
+ }
+ mBgmMediaPlayer = null;
+ }
+ mBgmLoading = false;
+ mWantBgm = true;
+ }
+
+ public void dispose() {
+ if (mBgmMediaPlayer != null && mBgmMediaPlayer.isPlaying()) {
+ mBgmMediaPlayer.stop();
+ }
+ }
+
+ @Override
+ public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
+ mSoundsLoading--;
+ if (status != 0) {
+ Logger.e("Error loading SFX into SoundPool, sample " + sampleId + ", status " + status);
+ }
+ }
+}
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/TextTextureMaker.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/TextTextureMaker.java
similarity index 79%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/TextTextureMaker.java
rename to playgames/src/main/java/com/google/android/apps/playgames/simpleengine/TextTextureMaker.java
index aa9cadc98..aad0af414 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/TextTextureMaker.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/TextTextureMaker.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.simpleengine;
+package com.google.android.apps.playgames.simpleengine;
import android.content.Context;
import android.graphics.Bitmap;
@@ -22,17 +22,16 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.WindowManager;
-
import java.util.ArrayList;
public class TextTextureMaker implements Runnable {
- private final static int PADDING_LEFT = 2;
- private final static int PADDING_RIGHT = 5;
- private final static int PADDING_BOTTOM = 2;
- private final static int PADDING_TOP = 2;
+ private static final int PADDING_LEFT = 2;
+ private static final int PADDING_RIGHT = 5;
+ private static final int PADDING_BOTTOM = 2;
+ private static final int PADDING_TOP = 2;
- private final static int SUPERSAMPLING = 2;
+ private static final int SUPERSAMPLING = 2;
private class Entry {
@@ -48,8 +47,7 @@ private class Entry {
boolean mFinishedLoading = false;
Context mCtx = null;
- public TextTextureMaker() {
- }
+ public TextTextureMaker() {}
void requestTex(int tag, String text, float fontSize, int color) {
Entry e = new Entry();
@@ -117,8 +115,15 @@ private void makeBitmapForEntry(Entry e) {
int textX = -bounds.left + PADDING_LEFT;
int textY = -bounds.top + PADDING_TOP;
- Logger.d("Bitmap will be " + width + "x" + height + ", offset will be " + textX + "," +
- textY);
+ Logger.d(
+ "Bitmap will be "
+ + width
+ + "x"
+ + height
+ + ", offset will be "
+ + textX
+ + ","
+ + textY);
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmp);
@@ -127,8 +132,12 @@ private void makeBitmapForEntry(Entry e) {
c.drawText(e.text, textX, textY, p);
if (SUPERSAMPLING > 1) {
- e.bitmap = Bitmap.createScaledBitmap(bmp, bmp.getWidth() / SUPERSAMPLING,
- bmp.getHeight() / SUPERSAMPLING, true);
+ e.bitmap =
+ Bitmap.createScaledBitmap(
+ bmp,
+ bmp.getWidth() / SUPERSAMPLING,
+ bmp.getHeight() / SUPERSAMPLING,
+ true);
bmp.recycle();
} else {
e.bitmap = bmp;
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/game/GameObject.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/game/GameObject.java
similarity index 93%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/game/GameObject.java
rename to playgames/src/main/java/com/google/android/apps/playgames/simpleengine/game/GameObject.java
index 410bf1bd8..b284a0ab8 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/game/GameObject.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/game/GameObject.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.simpleengine.game;
-
-import com.google.android.apps.santatracker.games.simpleengine.Renderer;
+package com.google.android.apps.playgames.simpleengine.game;
+import com.google.android.apps.playgames.simpleengine.Renderer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -194,4 +193,11 @@ public void bringToFront() {
mWorld.getRenderer().bringToFront(mSprites.get(i));
}
}
+
+ public void sendToBack() {
+ int i;
+ for (i = 0; i < mSprites.size(); i++) {
+ mWorld.getRenderer().sendToBack(mSprites.get(i));
+ }
+ }
}
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/game/World.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/game/World.java
similarity index 81%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/game/World.java
rename to playgames/src/main/java/com/google/android/apps/playgames/simpleengine/game/World.java
index 9ea2bfaf9..30fcd570b 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/game/World.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/game/World.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,12 +14,10 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.simpleengine.game;
-
-import com.google.android.apps.santatracker.games.simpleengine.Renderer;
+package com.google.android.apps.playgames.simpleengine.game;
import android.graphics.RectF;
-
+import com.google.android.apps.playgames.simpleengine.Renderer;
import java.util.ArrayList;
public final class World {
@@ -36,8 +34,16 @@ public World(Renderer r) {
mRenderer = r;
}
- private GameObject newGameObject(int type, float x, float y, boolean createSprite,
- int texIndex, int color, float tintFactor, float spriteWidth, float spriteHeight) {
+ private GameObject newGameObject(
+ int type,
+ float x,
+ float y,
+ boolean createSprite,
+ int texIndex,
+ int color,
+ float tintFactor,
+ float spriteWidth,
+ float spriteHeight) {
GameObject o;
if (mRecycleBin.isEmpty()) {
o = new GameObject(this);
@@ -65,13 +71,13 @@ public GameObject newGameObject(int type, float x, float y) {
return newGameObject(type, x, y, false, -1, 0, 0.0f, 0.0f, 0.0f);
}
- public GameObject newGameObjectWithImage(int type, float x, float y,
- int texIndex, float spriteWidth, float spriteHeight) {
+ public GameObject newGameObjectWithImage(
+ int type, float x, float y, int texIndex, float spriteWidth, float spriteHeight) {
return newGameObject(type, x, y, true, texIndex, 0, 0.0f, spriteWidth, spriteHeight);
}
- public GameObject newGameObjectWithColor(int type, float x, float y, int color,
- float spriteWidth, float spriteHeight) {
+ public GameObject newGameObjectWithColor(
+ int type, float x, float y, int color, float spriteWidth, float spriteHeight) {
return newGameObject(type, x, y, true, -1, color, 1.0f, spriteWidth, spriteHeight);
}
@@ -102,8 +108,8 @@ public void doFrame(float deltaT) {
}
}
- public boolean detectCollisions(GameObject object,
- ArrayList result, boolean clear) {
+ public boolean detectCollisions(
+ GameObject object, ArrayList result, boolean clear) {
int i;
boolean found = false;
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/ui/Button.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ui/Button.java
similarity index 82%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/ui/Button.java
rename to playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ui/Button.java
index fefd79099..5b431bf83 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/ui/Button.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ui/Button.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.simpleengine.ui;
-
-import com.google.android.apps.santatracker.games.simpleengine.Renderer;
+package com.google.android.apps.playgames.simpleengine.ui;
+import com.google.android.apps.playgames.simpleengine.Renderer;
import java.util.ArrayList;
public class Button extends Widget {
private boolean mVisible = true;
private boolean mArmed = false;
+ private boolean mEnabled = true;
private Renderer mRenderer;
private float mX, mY, mWidth, mHeight;
@@ -61,8 +61,14 @@ public void addFlatBackground(int normalColor, int highlightColor) {
updateSprites();
}
- public void addTex(boolean showWhenNormal, boolean showWhenHighlighted,
- int texIndex, float deltaX, float deltaY, float width, float height) {
+ public void addTex(
+ boolean showWhenNormal,
+ boolean showWhenHighlighted,
+ int texIndex,
+ float deltaX,
+ float deltaY,
+ float width,
+ float height) {
if (!showWhenHighlighted && !showWhenNormal) {
return;
@@ -95,8 +101,8 @@ public void addNormalTex(int texIndex) {
addNormalTex(texIndex, 0.0f, 0.0f, mWidth, mHeight);
}
- public void addHighlightTex(int texIndex, float deltaX, float deltaY, float width,
- float height) {
+ public void addHighlightTex(
+ int texIndex, float deltaX, float deltaY, float width, float height) {
addTex(false, true, texIndex, deltaX, deltaY, width, height);
}
@@ -187,34 +193,44 @@ private boolean isInButton(float x, float y) {
@Override
public void onPointerDown(int pointerId, float x, float y) {
- super.onPointerDown(pointerId, x, y);
- if (isInButton(x, y)) {
- mArmed = true;
- updateSprites();
+ if (mEnabled) {
+ super.onPointerDown(pointerId, x, y);
+ if (isInButton(x, y)) {
+ mArmed = true;
+ updateSprites();
+ }
}
}
@Override
public void onPointerMove(int pointerId, float x, float y, float deltaX, float deltaY) {
- super.onPointerMove(pointerId, x, y, deltaX, deltaY);
- if (!isInButton(x, y)) {
- mArmed = false;
- updateSprites();
+ if (mEnabled) {
+ super.onPointerMove(pointerId, x, y, deltaX, deltaY);
+ if (!isInButton(x, y)) {
+ mArmed = false;
+ updateSprites();
+ }
}
}
@Override
public void onPointerUp(int pointerId, float x, float y) {
- super.onPointerUp(pointerId, x, y);
- if (mArmed && isInButton(x, y)) {
- mArmed = false;
- updateSprites();
- if (mListener != null) {
- mListener.onWidgetTriggered(mTriggerMessage);
+ if (mEnabled) {
+ super.onPointerUp(pointerId, x, y);
+ if (mArmed && isInButton(x, y)) {
+ mArmed = false;
+ updateSprites();
+ if (mListener != null) {
+ mListener.onWidgetTriggered(mTriggerMessage);
+ }
}
}
}
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ }
+
@Override
public void dispose() {
for (Renderer.Sprite sp : mNormalSprites) {
diff --git a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/ui/SimpleUI.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ui/SimpleUI.java
similarity index 87%
rename from santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/ui/SimpleUI.java
rename to playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ui/SimpleUI.java
index accacbb6c..f7de3579a 100644
--- a/santa-tracker/src/main/java/com/google/android/apps/santatracker/games/simpleengine/ui/SimpleUI.java
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ui/SimpleUI.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * Copyright 2019. Google LLC
*
* 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
+ * https://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,
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package com.google.android.apps.santatracker.games.simpleengine.ui;
-
-import com.google.android.apps.santatracker.games.simpleengine.Renderer;
+package com.google.android.apps.playgames.simpleengine.ui;
+import com.google.android.apps.playgames.simpleengine.Renderer;
import java.util.ArrayList;
public class SimpleUI {
diff --git a/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ui/Widget.java b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ui/Widget.java
new file mode 100644
index 000000000..b12a048aa
--- /dev/null
+++ b/playgames/src/main/java/com/google/android/apps/playgames/simpleengine/ui/Widget.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.playgames.simpleengine.ui;
+
+public class Widget {
+
+ public interface WidgetTriggerListener {
+
+ public void onWidgetTriggered(int message);
+ }
+
+ public void doFrame(float deltaT) {}
+
+ public void onPointerDown(int pointerId, float x, float y) {}
+
+ public void onPointerMove(int pointerId, float x, float y, float deltaX, float deltaY) {}
+
+ public void onPointerUp(int pointerId, float x, float y) {}
+
+ public void dispose() {}
+}
diff --git a/playgames/src/main/res/anim/card_answer_flash.xml b/playgames/src/main/res/anim/card_answer_flash.xml
new file mode 100644
index 000000000..4989a6a6c
--- /dev/null
+++ b/playgames/src/main/res/anim/card_answer_flash.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/anim/level_fade_out_anim.xml b/playgames/src/main/res/anim/level_fade_out_anim.xml
new file mode 100644
index 000000000..8ce92e8e6
--- /dev/null
+++ b/playgames/src/main/res/anim/level_fade_out_anim.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/anim/play_again_bkgrd_anim.xml b/playgames/src/main/res/anim/play_again_bkgrd_anim.xml
new file mode 100644
index 000000000..b077d7164
--- /dev/null
+++ b/playgames/src/main/res/anim/play_again_bkgrd_anim.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/anim/play_again_main_anim.xml b/playgames/src/main/res/anim/play_again_main_anim.xml
new file mode 100644
index 000000000..de2bb9e36
--- /dev/null
+++ b/playgames/src/main/res/anim/play_again_main_anim.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/playgames/src/main/res/anim/right_pane_slide_in.xml b/playgames/src/main/res/anim/right_pane_slide_in.xml
new file mode 100644
index 000000000..f534dbfbd
--- /dev/null
+++ b/playgames/src/main/res/anim/right_pane_slide_in.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/anim/scale_level_anim_down.xml b/playgames/src/main/res/anim/scale_level_anim_down.xml
new file mode 100644
index 000000000..1845f42c9
--- /dev/null
+++ b/playgames/src/main/res/anim/scale_level_anim_down.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/anim/scale_up_level_anim.xml b/playgames/src/main/res/anim/scale_up_level_anim.xml
new file mode 100644
index 000000000..5bf8eb053
--- /dev/null
+++ b/playgames/src/main/res/anim/scale_up_level_anim.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/drawable-hdpi/gbg_score_summary_dialog.9.png b/playgames/src/main/res/drawable-hdpi/gbg_score_summary_dialog.9.png
new file mode 100644
index 000000000..f7d7a5998
Binary files /dev/null and b/playgames/src/main/res/drawable-hdpi/gbg_score_summary_dialog.9.png differ
diff --git a/playgames/src/main/res/drawable-hdpi/gbg_score_summary_elf.webp b/playgames/src/main/res/drawable-hdpi/gbg_score_summary_elf.webp
new file mode 100644
index 000000000..98fad0bec
Binary files /dev/null and b/playgames/src/main/res/drawable-hdpi/gbg_score_summary_elf.webp differ
diff --git a/playgames/src/main/res/drawable-mdpi/gbg_score_summary_dialog.9.png b/playgames/src/main/res/drawable-mdpi/gbg_score_summary_dialog.9.png
new file mode 100644
index 000000000..ee459ffdc
Binary files /dev/null and b/playgames/src/main/res/drawable-mdpi/gbg_score_summary_dialog.9.png differ
diff --git a/playgames/src/main/res/drawable-mdpi/gbg_score_summary_elf.webp b/playgames/src/main/res/drawable-mdpi/gbg_score_summary_elf.webp
new file mode 100644
index 000000000..6941cd874
Binary files /dev/null and b/playgames/src/main/res/drawable-mdpi/gbg_score_summary_elf.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_0.webp b/playgames/src/main/res/drawable-nodpi/games_digit_0.webp
new file mode 100644
index 000000000..592e30067
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_0.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_1.webp b/playgames/src/main/res/drawable-nodpi/games_digit_1.webp
new file mode 100644
index 000000000..b612818a2
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_1.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_2.webp b/playgames/src/main/res/drawable-nodpi/games_digit_2.webp
new file mode 100644
index 000000000..4aedf8bcc
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_2.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_3.webp b/playgames/src/main/res/drawable-nodpi/games_digit_3.webp
new file mode 100644
index 000000000..d58f293d6
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_3.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_4.webp b/playgames/src/main/res/drawable-nodpi/games_digit_4.webp
new file mode 100644
index 000000000..d3447eb45
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_4.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_5.webp b/playgames/src/main/res/drawable-nodpi/games_digit_5.webp
new file mode 100644
index 000000000..861f7a3d1
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_5.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_6.webp b/playgames/src/main/res/drawable-nodpi/games_digit_6.webp
new file mode 100644
index 000000000..575ae7bc9
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_6.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_7.webp b/playgames/src/main/res/drawable-nodpi/games_digit_7.webp
new file mode 100644
index 000000000..65c7bcc0b
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_7.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_8.webp b/playgames/src/main/res/drawable-nodpi/games_digit_8.webp
new file mode 100644
index 000000000..0623eb02b
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_8.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_9.webp b/playgames/src/main/res/drawable-nodpi/games_digit_9.webp
new file mode 100644
index 000000000..15d9141c6
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_9.webp differ
diff --git a/playgames/src/main/res/drawable-nodpi/games_digit_negative.webp b/playgames/src/main/res/drawable-nodpi/games_digit_negative.webp
new file mode 100644
index 000000000..5a5f5293b
Binary files /dev/null and b/playgames/src/main/res/drawable-nodpi/games_digit_negative.webp differ
diff --git a/playgames/src/main/res/drawable-v21/category_button_ripple.xml b/playgames/src/main/res/drawable-v21/category_button_ripple.xml
new file mode 100644
index 000000000..e648c1f6c
--- /dev/null
+++ b/playgames/src/main/res/drawable-v21/category_button_ripple.xml
@@ -0,0 +1,19 @@
+
+
+
+
diff --git a/playgames/src/main/res/drawable-xhdpi/gbg_score_summary_dialog.9.png b/playgames/src/main/res/drawable-xhdpi/gbg_score_summary_dialog.9.png
new file mode 100644
index 000000000..1acfc58e0
Binary files /dev/null and b/playgames/src/main/res/drawable-xhdpi/gbg_score_summary_dialog.9.png differ
diff --git a/playgames/src/main/res/drawable-xhdpi/gbg_score_summary_elf.webp b/playgames/src/main/res/drawable-xhdpi/gbg_score_summary_elf.webp
new file mode 100644
index 000000000..fa2bdbbb7
Binary files /dev/null and b/playgames/src/main/res/drawable-xhdpi/gbg_score_summary_elf.webp differ
diff --git a/playgames/src/main/res/drawable-xxhdpi/gbg_score_summary_dialog.9.png b/playgames/src/main/res/drawable-xxhdpi/gbg_score_summary_dialog.9.png
new file mode 100644
index 000000000..8cc5e82f0
Binary files /dev/null and b/playgames/src/main/res/drawable-xxhdpi/gbg_score_summary_dialog.9.png differ
diff --git a/playgames/src/main/res/drawable-xxhdpi/gbg_score_summary_elf.webp b/playgames/src/main/res/drawable-xxhdpi/gbg_score_summary_elf.webp
new file mode 100644
index 000000000..fc60d44cb
Binary files /dev/null and b/playgames/src/main/res/drawable-xxhdpi/gbg_score_summary_elf.webp differ
diff --git a/playgames/src/main/res/drawable/category_button_background.xml b/playgames/src/main/res/drawable/category_button_background.xml
new file mode 100644
index 000000000..2773aeb9b
--- /dev/null
+++ b/playgames/src/main/res/drawable/category_button_background.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ -
+
+
+
+
+
diff --git a/playgames/src/main/res/drawable/category_button_ripple.xml b/playgames/src/main/res/drawable/category_button_ripple.xml
new file mode 100644
index 000000000..33f1f47dd
--- /dev/null
+++ b/playgames/src/main/res/drawable/category_button_ripple.xml
@@ -0,0 +1,25 @@
+
+
+
+
+ -
+
+
+ -
+
+
+
diff --git a/playgames/src/main/res/drawable/instructions_shake_1.xml b/playgames/src/main/res/drawable/instructions_shake_1.xml
new file mode 100644
index 000000000..dbd338f7d
--- /dev/null
+++ b/playgames/src/main/res/drawable/instructions_shake_1.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/drawable/instructions_shake_2.xml b/playgames/src/main/res/drawable/instructions_shake_2.xml
new file mode 100644
index 000000000..f63a1c58e
--- /dev/null
+++ b/playgames/src/main/res/drawable/instructions_shake_2.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/drawable/instructions_shake_3.xml b/playgames/src/main/res/drawable/instructions_shake_3.xml
new file mode 100644
index 000000000..5833f6a2e
--- /dev/null
+++ b/playgames/src/main/res/drawable/instructions_shake_3.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/drawable/instructions_touch_1.xml b/playgames/src/main/res/drawable/instructions_touch_1.xml
new file mode 100644
index 000000000..c364be753
--- /dev/null
+++ b/playgames/src/main/res/drawable/instructions_touch_1.xml
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/drawable/instructions_touch_2.xml b/playgames/src/main/res/drawable/instructions_touch_2.xml
new file mode 100644
index 000000000..704b13e27
--- /dev/null
+++ b/playgames/src/main/res/drawable/instructions_touch_2.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/drawable/marker_pin.xml b/playgames/src/main/res/drawable/marker_pin.xml
new file mode 100644
index 000000000..798171cfb
--- /dev/null
+++ b/playgames/src/main/res/drawable/marker_pin.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/drawable/play_again_button.xml b/playgames/src/main/res/drawable/play_again_button.xml
new file mode 100644
index 000000000..e099edf30
--- /dev/null
+++ b/playgames/src/main/res/drawable/play_again_button.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/layout/fragment_license_dialog.xml b/playgames/src/main/res/layout/fragment_license_dialog.xml
new file mode 100644
index 000000000..e22196951
--- /dev/null
+++ b/playgames/src/main/res/layout/fragment_license_dialog.xml
@@ -0,0 +1,21 @@
+
+
+
diff --git a/playgames/src/main/res/layout/include_instruction_image.xml b/playgames/src/main/res/layout/include_instruction_image.xml
new file mode 100644
index 000000000..9d1115024
--- /dev/null
+++ b/playgames/src/main/res/layout/include_instruction_image.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/layout/layout_game_fragment.xml b/playgames/src/main/res/layout/layout_game_fragment.xml
new file mode 100644
index 000000000..496231072
--- /dev/null
+++ b/playgames/src/main/res/layout/layout_game_fragment.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/santa-tracker/src/main/res/raw/gameover.mp3 b/playgames/src/main/res/raw/gameover.mp3
similarity index 100%
rename from santa-tracker/src/main/res/raw/gameover.mp3
rename to playgames/src/main/res/raw/gameover.mp3
diff --git a/playgames/src/main/res/values-af/strings_gumball.xml b/playgames/src/main/res/values-af/strings_gumball.xml
new file mode 100644
index 000000000..459b3fe4c
--- /dev/null
+++ b/playgames/src/main/res/values-af/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Laat speletjie wag
+ Hervat speletjie
+
diff --git a/playgames/src/main/res/values-af/strings_memory.xml b/playgames/src/main/res/values-af/strings_memory.xml
new file mode 100644
index 000000000..11d2c1167
--- /dev/null
+++ b/playgames/src/main/res/values-af/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ TELLING
+ VLAK
+ SPEEL WEER
+ Laat speletjie wag
+ Hervat speletjie
+
diff --git a/playgames/src/main/res/values-af/strings_village.xml b/playgames/src/main/res/values-af/strings_village.xml
new file mode 100644
index 000000000..856676af6
--- /dev/null
+++ b/playgames/src/main/res/values-af/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Volg Kersvader op 24 Desember.
+ Geskenksoektog sal op 1 Desember beskikbaar wees.
+ Kersvader-kiekie sal binnekort beskikbaar wees.
+ Gumball sal op 1 Desember beskikbaar wees.
+ Memory sal op 1 Desember beskikbaar wees.
+ Vuurpylslee sal op 1 Desember beskikbaar wees.
+ Dasher-danser sal op 1 Desember beskikbaar wees.
+ Stadvasvra sal op 1 Desember beskikbaar wees.
+ %1$s is nie tans beskikbaar nie.
+ %1$s is nog nie beskikbaar nie. Kom kyk later weer!
+ Video
+ Video sal op %1$d Desember ontsluit word.
+ Video is tans onbeskikbaar.
+ Speel
+ Kyk
+
diff --git a/playgames/src/main/res/values-ar-rXB/strings_gumball.xml b/playgames/src/main/res/values-ar-rXB/strings_gumball.xml
new file mode 100644
index 000000000..ecffa985b
--- /dev/null
+++ b/playgames/src/main/res/values-ar-rXB/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-ar-rXB/strings_memory.xml b/playgames/src/main/res/values-ar-rXB/strings_memory.xml
new file mode 100644
index 000000000..5672e29ef
--- /dev/null
+++ b/playgames/src/main/res/values-ar-rXB/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ LEVEL
+ PLAY AGAIN
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-ar-rXB/strings_village.xml b/playgames/src/main/res/values-ar-rXB/strings_village.xml
new file mode 100644
index 000000000..298c4990a
--- /dev/null
+++ b/playgames/src/main/res/values-ar-rXB/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Follow Santa on December 24th.
+ Present Quest will be available on December 1st.
+ Santa Snap will be available soon.
+ Gumball will be available on December 1st.
+ Memory will be available on December 1st.
+ Rocket Sleigh will be available on December 1st.
+ Dasher Dancer will be available on December 1st.
+ City Quiz game will be available on December 1st.
+ %1$s is currently unavailable.
+ %1$s is not yet available. Check back later!
+ Video
+ Video will be unlocked on December %1$d.
+ Video is currently unavailable.
+ Play
+ Watch
+
diff --git a/playgames/src/main/res/values-bg/strings_gumball.xml b/playgames/src/main/res/values-bg/strings_gumball.xml
new file mode 100644
index 000000000..625a94552
--- /dev/null
+++ b/playgames/src/main/res/values-bg/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Поставяне на играта на пауза
+ Възобновяване на играта
+
diff --git a/playgames/src/main/res/values-bg/strings_memory.xml b/playgames/src/main/res/values-bg/strings_memory.xml
new file mode 100644
index 000000000..41d7d00c2
--- /dev/null
+++ b/playgames/src/main/res/values-bg/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ РЕЗУЛТАТ
+ НИВО
+ НОВА ИГРА
+ Поставяне на играта на пауза
+ Възобновяване на играта
+
diff --git a/playgames/src/main/res/values-bg/strings_village.xml b/playgames/src/main/res/values-bg/strings_village.xml
new file mode 100644
index 000000000..e50e9277d
--- /dev/null
+++ b/playgames/src/main/res/values-bg/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Следвайте Дядо Коледа на 24 декември.
+ „Търсене на подаръци“ ще е налице на 1 декември.
+ Играта „Коледни селфита“ скоро ще е налице.
+ Gumball ще е налице на 1 декември.
+ Memory ще е налице на 1 декември.
+ Rocket Sleigh ще е налице на 1 декември.
+ Dasher Dancer ще е налице на 1 декември.
+ Играта „Географска викторина“ ще е налице на 1 декември.
+ Понастоящем „%1$s“ не е налице.
+ „%1$s“ още не е налице. Проверете отново по-късно!
+ Видеоклип
+ Видеоклипът ще бъде отключен на %1$d декември.
+ Понастоящем видеоклипът не е налице.
+ Игра
+ Гледане
+
diff --git a/playgames/src/main/res/values-ca/strings_gumball.xml b/playgames/src/main/res/values-ca/strings_gumball.xml
new file mode 100644
index 000000000..770639b48
--- /dev/null
+++ b/playgames/src/main/res/values-ca/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Posa en pausa el joc
+ Reprèn el joc
+
diff --git a/playgames/src/main/res/values-ca/strings_memory.xml b/playgames/src/main/res/values-ca/strings_memory.xml
new file mode 100644
index 000000000..c23942d18
--- /dev/null
+++ b/playgames/src/main/res/values-ca/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓ
+ NIVELL
+ TORNA A JUGAR
+ Pausa el joc
+ Reprèn el joc
+
diff --git a/playgames/src/main/res/values-ca/strings_village.xml b/playgames/src/main/res/values-ca/strings_village.xml
new file mode 100644
index 000000000..fe9864f8f
--- /dev/null
+++ b/playgames/src/main/res/values-ca/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Segueix el Pare Noel el 24 de desembre.
+ El joc Recerca de regals estarà disponible a partir de l\'1 de desembre.
+ Les fotos del Pare Noel estarà disponible aviat.
+ Gumball estarà disponible a partir de l\'1 de desembre.
+ Memory estarà disponible a partir de l\'1 de desembre.
+ Rocket Sleigh estarà disponible a partir de l\'1 de desembre.
+ Dasher Dancer estarà disponible a partir de l\'1 de desembre.
+ El Joc de les ciutats estarà disponible a partir de l\'1 de desembre.
+ %1$s no està disponible en aquest moment.
+ %1$s encara no està disponible. Torna més tard.
+ Vídeo
+ El vídeo es desbloquejarà el dia %1$d de desembre.
+ El vídeo no està disponible en aquest moment.
+ Juga
+ Mira
+
diff --git a/playgames/src/main/res/values-da/strings_gumball.xml b/playgames/src/main/res/values-da/strings_gumball.xml
new file mode 100644
index 000000000..53ea58b05
--- /dev/null
+++ b/playgames/src/main/res/values-da/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Sæt spillet på pause
+ Genoptag spillet
+
diff --git a/playgames/src/main/res/values-da/strings_memory.xml b/playgames/src/main/res/values-da/strings_memory.xml
new file mode 100644
index 000000000..caf803a26
--- /dev/null
+++ b/playgames/src/main/res/values-da/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ POINT
+ BANE
+ SPIL IGEN
+ Sæt spillet på pause
+ Genoptag spillet
+
diff --git a/playgames/src/main/res/values-da/strings_village.xml b/playgames/src/main/res/values-da/strings_village.xml
new file mode 100644
index 000000000..0ac126e18
--- /dev/null
+++ b/playgames/src/main/res/values-da/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Følg julemanden den 24. december.
+ Gavejagten er tilgængeligt den 1. december.
+ Julemands-snap kommer snart.
+ Gumball er tilgængeligt den 1. december.
+ Huskespillet er tilgængeligt den 1. december.
+ Spillet med raketdrevne slæder er tilgængeligt den 1. december.
+ Spillet med julemandens rensdyr er tilgængeligt den 1. december.
+ Spillet Kortquiz er tilgængeligt 1. december.
+ %1$s er ikke tilgængeligt i øjeblikket.
+ %1$s kan ikke spilles endnu. Kig forbi senere!
+ Video
+ Der er adgang til videoen den %1$d. december.
+ Videoen er ikke tilgængelig i øjeblikket.
+ Spil
+ Se
+
diff --git a/playgames/src/main/res/values-de-rAT/strings_gumball.xml b/playgames/src/main/res/values-de-rAT/strings_gumball.xml
new file mode 100644
index 000000000..57fab51b1
--- /dev/null
+++ b/playgames/src/main/res/values-de-rAT/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Spiel pausieren
+ Spiel fortsetzen
+
diff --git a/playgames/src/main/res/values-de-rAT/strings_memory.xml b/playgames/src/main/res/values-de-rAT/strings_memory.xml
new file mode 100644
index 000000000..c827785fd
--- /dev/null
+++ b/playgames/src/main/res/values-de-rAT/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNKTE
+ LEVEL
+ NEUES SPIEL
+ Spiel pausieren
+ Spiel fortsetzen
+
diff --git a/playgames/src/main/res/values-de-rAT/strings_village.xml b/playgames/src/main/res/values-de-rAT/strings_village.xml
new file mode 100644
index 000000000..3dae2a8c9
--- /dev/null
+++ b/playgames/src/main/res/values-de-rAT/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Dem Weihnachtsmann ab 24. Dezember folgen
+ Present Quest steht ab dem 1. Dezember zur Verfügung.
+ Weihnachtsmann-Selfie ist bald verfügbar.
+ Gumball ist ab dem 1. Dezember verfügbar.
+ Memory ist ab dem 1. Dezember verfügbar.
+ Das Spiel \"Raketenflug\" ist ab dem 1. Dezember verfügbar.
+ Dasher Dancer ist ab dem 1. Dezember verfügbar.
+ City Quiz steht ab dem 1. Dezember zur Verfügung.
+ %1$s ist zurzeit nicht verfügbar.
+ %1$s ist noch nicht verfügbar. Schau später noch einmal vorbei.
+ Video
+ Dieses Video wird am %1$d freigegeben.
+ Dieses Video ist derzeit nicht verfügbar.
+ Spielen
+ Ansehen
+
diff --git a/playgames/src/main/res/values-de-rCH/strings_gumball.xml b/playgames/src/main/res/values-de-rCH/strings_gumball.xml
new file mode 100644
index 000000000..57fab51b1
--- /dev/null
+++ b/playgames/src/main/res/values-de-rCH/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Spiel pausieren
+ Spiel fortsetzen
+
diff --git a/playgames/src/main/res/values-de-rCH/strings_memory.xml b/playgames/src/main/res/values-de-rCH/strings_memory.xml
new file mode 100644
index 000000000..c827785fd
--- /dev/null
+++ b/playgames/src/main/res/values-de-rCH/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNKTE
+ LEVEL
+ NEUES SPIEL
+ Spiel pausieren
+ Spiel fortsetzen
+
diff --git a/playgames/src/main/res/values-de-rCH/strings_village.xml b/playgames/src/main/res/values-de-rCH/strings_village.xml
new file mode 100644
index 000000000..3dae2a8c9
--- /dev/null
+++ b/playgames/src/main/res/values-de-rCH/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Dem Weihnachtsmann ab 24. Dezember folgen
+ Present Quest steht ab dem 1. Dezember zur Verfügung.
+ Weihnachtsmann-Selfie ist bald verfügbar.
+ Gumball ist ab dem 1. Dezember verfügbar.
+ Memory ist ab dem 1. Dezember verfügbar.
+ Das Spiel \"Raketenflug\" ist ab dem 1. Dezember verfügbar.
+ Dasher Dancer ist ab dem 1. Dezember verfügbar.
+ City Quiz steht ab dem 1. Dezember zur Verfügung.
+ %1$s ist zurzeit nicht verfügbar.
+ %1$s ist noch nicht verfügbar. Schau später noch einmal vorbei.
+ Video
+ Dieses Video wird am %1$d freigegeben.
+ Dieses Video ist derzeit nicht verfügbar.
+ Spielen
+ Ansehen
+
diff --git a/playgames/src/main/res/values-de/strings_gumball.xml b/playgames/src/main/res/values-de/strings_gumball.xml
new file mode 100644
index 000000000..57fab51b1
--- /dev/null
+++ b/playgames/src/main/res/values-de/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Spiel pausieren
+ Spiel fortsetzen
+
diff --git a/playgames/src/main/res/values-de/strings_memory.xml b/playgames/src/main/res/values-de/strings_memory.xml
new file mode 100644
index 000000000..c827785fd
--- /dev/null
+++ b/playgames/src/main/res/values-de/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNKTE
+ LEVEL
+ NEUES SPIEL
+ Spiel pausieren
+ Spiel fortsetzen
+
diff --git a/playgames/src/main/res/values-de/strings_village.xml b/playgames/src/main/res/values-de/strings_village.xml
new file mode 100644
index 000000000..3dae2a8c9
--- /dev/null
+++ b/playgames/src/main/res/values-de/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Dem Weihnachtsmann ab 24. Dezember folgen
+ Present Quest steht ab dem 1. Dezember zur Verfügung.
+ Weihnachtsmann-Selfie ist bald verfügbar.
+ Gumball ist ab dem 1. Dezember verfügbar.
+ Memory ist ab dem 1. Dezember verfügbar.
+ Das Spiel \"Raketenflug\" ist ab dem 1. Dezember verfügbar.
+ Dasher Dancer ist ab dem 1. Dezember verfügbar.
+ City Quiz steht ab dem 1. Dezember zur Verfügung.
+ %1$s ist zurzeit nicht verfügbar.
+ %1$s ist noch nicht verfügbar. Schau später noch einmal vorbei.
+ Video
+ Dieses Video wird am %1$d freigegeben.
+ Dieses Video ist derzeit nicht verfügbar.
+ Spielen
+ Ansehen
+
diff --git a/playgames/src/main/res/values-en-rGB/strings_gumball.xml b/playgames/src/main/res/values-en-rGB/strings_gumball.xml
new file mode 100644
index 000000000..dd690484d
--- /dev/null
+++ b/playgames/src/main/res/values-en-rGB/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rGB/strings_memory.xml b/playgames/src/main/res/values-en-rGB/strings_memory.xml
new file mode 100644
index 000000000..d7c895025
--- /dev/null
+++ b/playgames/src/main/res/values-en-rGB/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ LEVEL
+ PLAY AGAIN
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rGB/strings_village.xml b/playgames/src/main/res/values-en-rGB/strings_village.xml
new file mode 100644
index 000000000..5a5388630
--- /dev/null
+++ b/playgames/src/main/res/values-en-rGB/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Follow Santa on 24 December.
+ Present Quest will be available on 1 December.
+ Santa Snap will be available soon.
+ Gumball will be available on 1 December.
+ Memory will be available on 1 December.
+ Rocket Sleigh will be available on 1 December.
+ Dasher Dancer will be available on 1 December.
+ City Quiz game will be available on 1 December.
+ %1$s is currently unavailable.
+ %1$s is not yet available. Check back later!
+ In-stream video
+ Video will be unlocked on %1$d December.
+ Video is currently unavailable.
+ Play
+ Watch
+
diff --git a/playgames/src/main/res/values-en-rIE/strings_gumball.xml b/playgames/src/main/res/values-en-rIE/strings_gumball.xml
new file mode 100644
index 000000000..dd690484d
--- /dev/null
+++ b/playgames/src/main/res/values-en-rIE/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rIE/strings_memory.xml b/playgames/src/main/res/values-en-rIE/strings_memory.xml
new file mode 100644
index 000000000..d7c895025
--- /dev/null
+++ b/playgames/src/main/res/values-en-rIE/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ LEVEL
+ PLAY AGAIN
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rIE/strings_village.xml b/playgames/src/main/res/values-en-rIE/strings_village.xml
new file mode 100644
index 000000000..5a5388630
--- /dev/null
+++ b/playgames/src/main/res/values-en-rIE/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Follow Santa on 24 December.
+ Present Quest will be available on 1 December.
+ Santa Snap will be available soon.
+ Gumball will be available on 1 December.
+ Memory will be available on 1 December.
+ Rocket Sleigh will be available on 1 December.
+ Dasher Dancer will be available on 1 December.
+ City Quiz game will be available on 1 December.
+ %1$s is currently unavailable.
+ %1$s is not yet available. Check back later!
+ In-stream video
+ Video will be unlocked on %1$d December.
+ Video is currently unavailable.
+ Play
+ Watch
+
diff --git a/playgames/src/main/res/values-en-rIN/strings_gumball.xml b/playgames/src/main/res/values-en-rIN/strings_gumball.xml
new file mode 100644
index 000000000..dd690484d
--- /dev/null
+++ b/playgames/src/main/res/values-en-rIN/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rIN/strings_memory.xml b/playgames/src/main/res/values-en-rIN/strings_memory.xml
new file mode 100644
index 000000000..d7c895025
--- /dev/null
+++ b/playgames/src/main/res/values-en-rIN/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ LEVEL
+ PLAY AGAIN
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rIN/strings_village.xml b/playgames/src/main/res/values-en-rIN/strings_village.xml
new file mode 100644
index 000000000..5a5388630
--- /dev/null
+++ b/playgames/src/main/res/values-en-rIN/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Follow Santa on 24 December.
+ Present Quest will be available on 1 December.
+ Santa Snap will be available soon.
+ Gumball will be available on 1 December.
+ Memory will be available on 1 December.
+ Rocket Sleigh will be available on 1 December.
+ Dasher Dancer will be available on 1 December.
+ City Quiz game will be available on 1 December.
+ %1$s is currently unavailable.
+ %1$s is not yet available. Check back later!
+ In-stream video
+ Video will be unlocked on %1$d December.
+ Video is currently unavailable.
+ Play
+ Watch
+
diff --git a/playgames/src/main/res/values-en-rSG/strings_gumball.xml b/playgames/src/main/res/values-en-rSG/strings_gumball.xml
new file mode 100644
index 000000000..dd690484d
--- /dev/null
+++ b/playgames/src/main/res/values-en-rSG/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rSG/strings_memory.xml b/playgames/src/main/res/values-en-rSG/strings_memory.xml
new file mode 100644
index 000000000..d7c895025
--- /dev/null
+++ b/playgames/src/main/res/values-en-rSG/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ LEVEL
+ PLAY AGAIN
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rSG/strings_village.xml b/playgames/src/main/res/values-en-rSG/strings_village.xml
new file mode 100644
index 000000000..5a5388630
--- /dev/null
+++ b/playgames/src/main/res/values-en-rSG/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Follow Santa on 24 December.
+ Present Quest will be available on 1 December.
+ Santa Snap will be available soon.
+ Gumball will be available on 1 December.
+ Memory will be available on 1 December.
+ Rocket Sleigh will be available on 1 December.
+ Dasher Dancer will be available on 1 December.
+ City Quiz game will be available on 1 December.
+ %1$s is currently unavailable.
+ %1$s is not yet available. Check back later!
+ In-stream video
+ Video will be unlocked on %1$d December.
+ Video is currently unavailable.
+ Play
+ Watch
+
diff --git a/playgames/src/main/res/values-en-rXA/strings_gumball.xml b/playgames/src/main/res/values-en-rXA/strings_gumball.xml
new file mode 100644
index 000000000..744e1b48f
--- /dev/null
+++ b/playgames/src/main/res/values-en-rXA/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ [Þåûšé ĝåmé one two]
+ [Ŕéšûmé ĝåmé one two]
+
diff --git a/playgames/src/main/res/values-en-rXA/strings_memory.xml b/playgames/src/main/res/values-en-rXA/strings_memory.xml
new file mode 100644
index 000000000..b1e1025b8
--- /dev/null
+++ b/playgames/src/main/res/values-en-rXA/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ [ŠÇÖŔÉ one]
+ [ĻÉVÉĻ one]
+ [ÞĻÅÝ ÅĜÅÎÑ one two]
+ [Þåûšé ĝåmé one two]
+ [Ŕéšûmé ĝåmé one two]
+
diff --git a/playgames/src/main/res/values-en-rXA/strings_village.xml b/playgames/src/main/res/values-en-rXA/strings_village.xml
new file mode 100644
index 000000000..e8e0e2d06
--- /dev/null
+++ b/playgames/src/main/res/values-en-rXA/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ [Föļļöŵ Šåñţå öñ Ðéçémбéŕ 24ţĥ. one two three four five six seven]
+ [Þŕéšéñţ Qûéšţ ŵîļļ бé åvåîļåбļé öñ Ðéçémбéŕ 1šţ. one two three four five six seven eight nine ten]
+ [Šåñţå Šñåþ ŵîļļ бé åvåîļåбļé šööñ. one two three four five six seven]
+ [Ĝûmбåļļ ŵîļļ бé åvåîļåбļé öñ Ðéçémбéŕ 1šţ. one two three four five six seven eight nine]
+ [Mémöŕý ŵîļļ бé åvåîļåбļé öñ Ðéçémбéŕ 1šţ. one two three four five six seven eight nine]
+ [Ŕöçķéţ Šļéîĝĥ ŵîļļ бé åvåîļåбļé öñ Ðéçémбéŕ 1šţ. one two three four five six seven eight nine ten]
+ [Ðåšĥéŕ Ðåñçéŕ ŵîļļ бé åvåîļåбļé öñ Ðéçémбéŕ 1šţ. one two three four five six seven eight nine ten]
+ [Çîţý Qûîž ĝåmé ŵîļļ бé åvåîļåбļé öñ Ðéçémбéŕ 1šţ. one two three four five six seven eight nine ten]
+ [ᐅ%1$sᐊ îš çûŕŕéñţļý ûñåvåîļåбļé. one two three four five six seven]
+ [ᐅ%1$sᐊ îš ñöţ ýéţ åvåîļåбļé. Çĥéçķ бåçķ ļåţéŕ¡ one two three four five six seven eight nine]
+ [Vîðéö one]
+ [Vîðéö ŵîļļ бé ûñļöçķéð öñ Ðéçémбéŕ ᐅ%1$dᐊ. one two three four five six seven eight]
+ [Vîðéö îš çûŕŕéñţļý ûñåvåîļåбļé. one two three four five six seven]
+ [Þļåý one]
+ [Ŵåţçĥ one]
+
diff --git a/playgames/src/main/res/values-en-rXC/strings_gumball.xml b/playgames/src/main/res/values-en-rXC/strings_gumball.xml
new file mode 100644
index 000000000..8d3ae1e35
--- /dev/null
+++ b/playgames/src/main/res/values-en-rXC/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rXC/strings_memory.xml b/playgames/src/main/res/values-en-rXC/strings_memory.xml
new file mode 100644
index 000000000..d4a2feb93
--- /dev/null
+++ b/playgames/src/main/res/values-en-rXC/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ LEVEL
+ PLAY AGAIN
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rXC/strings_village.xml b/playgames/src/main/res/values-en-rXC/strings_village.xml
new file mode 100644
index 000000000..7a7502e67
--- /dev/null
+++ b/playgames/src/main/res/values-en-rXC/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Follow Santa on December 24th.
+ Present Quest will be available on December 1st.
+ Santa Snap will be available soon.
+ Gumball will be available on December 1st.
+ Memory will be available on December 1st.
+ Rocket Sleigh will be available on December 1st.
+ Dasher Dancer will be available on December 1st.
+ City Quiz game will be available on December 1st.
+ %1$s is currently unavailable.
+ %1$s is not yet available. Check back later!
+ Video
+ Video will be unlocked on December %1$d.
+ Video is currently unavailable.
+ Play
+ Watch
+
diff --git a/playgames/src/main/res/values-en-rZA/strings_gumball.xml b/playgames/src/main/res/values-en-rZA/strings_gumball.xml
new file mode 100644
index 000000000..dd690484d
--- /dev/null
+++ b/playgames/src/main/res/values-en-rZA/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rZA/strings_memory.xml b/playgames/src/main/res/values-en-rZA/strings_memory.xml
new file mode 100644
index 000000000..d7c895025
--- /dev/null
+++ b/playgames/src/main/res/values-en-rZA/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ LEVEL
+ PLAY AGAIN
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values-en-rZA/strings_village.xml b/playgames/src/main/res/values-en-rZA/strings_village.xml
new file mode 100644
index 000000000..5a5388630
--- /dev/null
+++ b/playgames/src/main/res/values-en-rZA/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Follow Santa on 24 December.
+ Present Quest will be available on 1 December.
+ Santa Snap will be available soon.
+ Gumball will be available on 1 December.
+ Memory will be available on 1 December.
+ Rocket Sleigh will be available on 1 December.
+ Dasher Dancer will be available on 1 December.
+ City Quiz game will be available on 1 December.
+ %1$s is currently unavailable.
+ %1$s is not yet available. Check back later!
+ In-stream video
+ Video will be unlocked on %1$d December.
+ Video is currently unavailable.
+ Play
+ Watch
+
diff --git a/playgames/src/main/res/values-es-rAR/strings_gumball.xml b/playgames/src/main/res/values-es-rAR/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rAR/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rAR/strings_memory.xml b/playgames/src/main/res/values-es-rAR/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rAR/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rAR/strings_village.xml b/playgames/src/main/res/values-es-rAR/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rAR/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rBO/strings_gumball.xml b/playgames/src/main/res/values-es-rBO/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rBO/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rBO/strings_memory.xml b/playgames/src/main/res/values-es-rBO/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rBO/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rBO/strings_village.xml b/playgames/src/main/res/values-es-rBO/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rBO/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rCL/strings_gumball.xml b/playgames/src/main/res/values-es-rCL/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rCL/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rCL/strings_memory.xml b/playgames/src/main/res/values-es-rCL/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rCL/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rCL/strings_village.xml b/playgames/src/main/res/values-es-rCL/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rCL/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rCO/strings_gumball.xml b/playgames/src/main/res/values-es-rCO/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rCO/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rCO/strings_memory.xml b/playgames/src/main/res/values-es-rCO/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rCO/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rCO/strings_village.xml b/playgames/src/main/res/values-es-rCO/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rCO/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rCR/strings_gumball.xml b/playgames/src/main/res/values-es-rCR/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rCR/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rCR/strings_memory.xml b/playgames/src/main/res/values-es-rCR/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rCR/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rCR/strings_village.xml b/playgames/src/main/res/values-es-rCR/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rCR/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rDO/strings_gumball.xml b/playgames/src/main/res/values-es-rDO/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rDO/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rDO/strings_memory.xml b/playgames/src/main/res/values-es-rDO/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rDO/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rDO/strings_village.xml b/playgames/src/main/res/values-es-rDO/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rDO/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rEC/strings_gumball.xml b/playgames/src/main/res/values-es-rEC/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rEC/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rEC/strings_memory.xml b/playgames/src/main/res/values-es-rEC/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rEC/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rEC/strings_village.xml b/playgames/src/main/res/values-es-rEC/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rEC/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rES/strings_gumball.xml b/playgames/src/main/res/values-es-rES/strings_gumball.xml
new file mode 100644
index 000000000..0367ac7df
--- /dev/null
+++ b/playgames/src/main/res/values-es-rES/strings_gumball.xml
@@ -0,0 +1,18 @@
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rES/strings_memory.xml b/playgames/src/main/res/values-es-rES/strings_memory.xml
new file mode 100644
index 000000000..a32e95966
--- /dev/null
+++ b/playgames/src/main/res/values-es-rES/strings_memory.xml
@@ -0,0 +1,21 @@
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rES/strings_village.xml b/playgames/src/main/res/values-es-rES/strings_village.xml
new file mode 100644
index 000000000..d05e71688
--- /dev/null
+++ b/playgames/src/main/res/values-es-rES/strings_village.xml
@@ -0,0 +1,24 @@
+
+
+ Sigue a Santa el 24 de diciembre.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+
diff --git a/playgames/src/main/res/values-es-rGT/strings_gumball.xml b/playgames/src/main/res/values-es-rGT/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rGT/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rGT/strings_memory.xml b/playgames/src/main/res/values-es-rGT/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rGT/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rGT/strings_village.xml b/playgames/src/main/res/values-es-rGT/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rGT/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rHN/strings_gumball.xml b/playgames/src/main/res/values-es-rHN/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rHN/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rHN/strings_memory.xml b/playgames/src/main/res/values-es-rHN/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rHN/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rHN/strings_village.xml b/playgames/src/main/res/values-es-rHN/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rHN/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rMX/strings_gumball.xml b/playgames/src/main/res/values-es-rMX/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rMX/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rMX/strings_memory.xml b/playgames/src/main/res/values-es-rMX/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rMX/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rMX/strings_village.xml b/playgames/src/main/res/values-es-rMX/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rMX/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rNI/strings_gumball.xml b/playgames/src/main/res/values-es-rNI/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rNI/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rNI/strings_memory.xml b/playgames/src/main/res/values-es-rNI/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rNI/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rNI/strings_village.xml b/playgames/src/main/res/values-es-rNI/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rNI/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rPA/strings_gumball.xml b/playgames/src/main/res/values-es-rPA/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPA/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rPA/strings_memory.xml b/playgames/src/main/res/values-es-rPA/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPA/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rPA/strings_village.xml b/playgames/src/main/res/values-es-rPA/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPA/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rPE/strings_gumball.xml b/playgames/src/main/res/values-es-rPE/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPE/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rPE/strings_memory.xml b/playgames/src/main/res/values-es-rPE/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPE/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rPE/strings_village.xml b/playgames/src/main/res/values-es-rPE/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPE/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rPR/strings_gumball.xml b/playgames/src/main/res/values-es-rPR/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPR/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rPR/strings_memory.xml b/playgames/src/main/res/values-es-rPR/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPR/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rPR/strings_village.xml b/playgames/src/main/res/values-es-rPR/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPR/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rPY/strings_gumball.xml b/playgames/src/main/res/values-es-rPY/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPY/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rPY/strings_memory.xml b/playgames/src/main/res/values-es-rPY/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPY/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rPY/strings_village.xml b/playgames/src/main/res/values-es-rPY/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rPY/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rSV/strings_gumball.xml b/playgames/src/main/res/values-es-rSV/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rSV/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rSV/strings_memory.xml b/playgames/src/main/res/values-es-rSV/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rSV/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rSV/strings_village.xml b/playgames/src/main/res/values-es-rSV/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rSV/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rUS/strings_gumball.xml b/playgames/src/main/res/values-es-rUS/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rUS/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rUS/strings_memory.xml b/playgames/src/main/res/values-es-rUS/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rUS/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rUS/strings_village.xml b/playgames/src/main/res/values-es-rUS/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rUS/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rUY/strings_gumball.xml b/playgames/src/main/res/values-es-rUY/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rUY/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rUY/strings_memory.xml b/playgames/src/main/res/values-es-rUY/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rUY/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rUY/strings_village.xml b/playgames/src/main/res/values-es-rUY/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rUY/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es-rVE/strings_gumball.xml b/playgames/src/main/res/values-es-rVE/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es-rVE/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rVE/strings_memory.xml b/playgames/src/main/res/values-es-rVE/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es-rVE/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es-rVE/strings_village.xml b/playgames/src/main/res/values-es-rVE/strings_village.xml
new file mode 100644
index 000000000..4706bc69c
--- /dev/null
+++ b/playgames/src/main/res/values-es-rVE/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Santa el 24 de diciembre.
+ Búsqueda de regalos estará disponible el 1 de diciembre.
+ Instantáneas navideñas estará disponible pronto.
+ Gumball estará disponible el 1.º de diciembre.
+ Memory estará disponible el 1.º de diciembre.
+ Rocket Sleigh estará disponible el 1.º de diciembre.
+ Dasher Dancer estará disponible el 1.º de diciembre.
+ El cuestionario sobre ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible en este momento.
+ %1$s aún no está disponible. Vuelve a revisar más tarde.
+ Video
+ El video se desbloqueará el %1$d de diciembre.
+ El video no está disponible en este momento.
+ Jugar
+ Mirar
+
diff --git a/playgames/src/main/res/values-es/strings_gumball.xml b/playgames/src/main/res/values-es/strings_gumball.xml
new file mode 100644
index 000000000..651c73148
--- /dev/null
+++ b/playgames/src/main/res/values-es/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es/strings_memory.xml b/playgames/src/main/res/values-es/strings_memory.xml
new file mode 100644
index 000000000..6e3eb7698
--- /dev/null
+++ b/playgames/src/main/res/values-es/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTUACIÓN
+ NIVEL
+ VOLVER A JUGAR
+ Pausar el juego
+ Reanudar el juego
+
diff --git a/playgames/src/main/res/values-es/strings_village.xml b/playgames/src/main/res/values-es/strings_village.xml
new file mode 100644
index 000000000..ade31ae25
--- /dev/null
+++ b/playgames/src/main/res/values-es/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sigue a Papá Noel el 24 de diciembre.
+ Atrapa el regalo estará disponible el 1 de diciembre.
+ El juego Selfie de Papá Noel pronto estará disponible.
+ Gumball estará disponible el 1 de diciembre.
+ Memory estará disponible el 1 de diciembre.
+ Rocket Sleigh estará disponible el 1 de diciembre.
+ Dasher Dancer estará disponible el 1 de diciembre.
+ Juego de las ciudades estará disponible el 1 de diciembre.
+ %1$s no está disponible por el momento.
+ El juego \"%1$s\" todavía no está disponible. Vuelve a comprobarlo más tarde.
+ Vídeo
+ Vídeo se desbloqueará el %1$d de diciembre.
+ Vídeo no está disponible en estos momentos.
+ Jugar
+ Ver
+
diff --git a/playgames/src/main/res/values-et/strings_gumball.xml b/playgames/src/main/res/values-et/strings_gumball.xml
new file mode 100644
index 000000000..cda4288dd
--- /dev/null
+++ b/playgames/src/main/res/values-et/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Peatage mäng
+ Jätkake mängu
+
diff --git a/playgames/src/main/res/values-et/strings_memory.xml b/playgames/src/main/res/values-et/strings_memory.xml
new file mode 100644
index 000000000..a0301793b
--- /dev/null
+++ b/playgames/src/main/res/values-et/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ TULEMUS
+ TASE
+ MÄNGI UUESTI
+ Peatage mäng
+ Jätkake mängu
+
diff --git a/playgames/src/main/res/values-et/strings_village.xml b/playgames/src/main/res/values-et/strings_village.xml
new file mode 100644
index 000000000..6bafe0dbe
--- /dev/null
+++ b/playgames/src/main/res/values-et/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Jõuluvana saate jälgida 24. detsembril.
+ Kingiseiklus on saadaval alates 1. detsembrist.
+ Jõuluvanatuur on peagi saadaval.
+ Gumball on saadaval alates 1. detsembrist.
+ Memory on saadaval alates 1. detsembrist.
+ Rocket Sleigh on saadaval alates 1. detsembrist.
+ Dasher Dancer on saadaval alates 1. detsembrist.
+ Linnaviktoriin on saadaval alates 1. detsembrist.
+ %1$s ei ole praegu saadaval.
+ %1$s ei ole veel saadaval. Proovige hiljem uuesti!
+ Video
+ Video avatakse %1$d. detsembril.
+ Video pole praegu saadaval.
+ Mängige
+ Esita
+
diff --git a/playgames/src/main/res/values-fi/strings_gumball.xml b/playgames/src/main/res/values-fi/strings_gumball.xml
new file mode 100644
index 000000000..c2ae86c23
--- /dev/null
+++ b/playgames/src/main/res/values-fi/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Keskeytä peli
+ Jatka peliä
+
diff --git a/playgames/src/main/res/values-fi/strings_memory.xml b/playgames/src/main/res/values-fi/strings_memory.xml
new file mode 100644
index 000000000..e5938cb7a
--- /dev/null
+++ b/playgames/src/main/res/values-fi/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ TULOS
+ TASO
+ PELAA UUDELLEEN
+ Keskeytä peli
+ Jatka peliä
+
diff --git a/playgames/src/main/res/values-fi/strings_village.xml b/playgames/src/main/res/values-fi/strings_village.xml
new file mode 100644
index 000000000..b94f78fc2
--- /dev/null
+++ b/playgames/src/main/res/values-fi/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Seuraa joulupukkia jouluaattona.
+ Lahjaseikkailu on saatavana 1. joulukuuta.
+ Pukin pikakuvat on pelattavissa pian.
+ Gumball-peli on saatavana 1. joulukuuta.
+ Memory-peli on saatavana 1. joulukuuta.
+ Rocket Sleigh -peli on saatavana 1. joulukuuta.
+ Dasher Dancer -peli on saatavana 1. joulukuuta.
+ Kaupunkivisa on saatavana 1. joulukuuta.
+ %1$s ei ole tällä hetkellä saatavana.
+ %1$s ei ole vielä pelattavissa. Tule kokeilemaan myöhemmin uudelleen!
+ Video
+ Video avataan %1$d. joulukuuta.
+ Video ei tällä hetkellä ole saatavana.
+ Pelaa
+ Katso
+
diff --git a/playgames/src/main/res/values-fil/strings_gumball.xml b/playgames/src/main/res/values-fil/strings_gumball.xml
new file mode 100644
index 000000000..3ad5866b5
--- /dev/null
+++ b/playgames/src/main/res/values-fil/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ I-pause ang laro
+ Ipagpatuloy ang laro
+
diff --git a/playgames/src/main/res/values-fil/strings_memory.xml b/playgames/src/main/res/values-fil/strings_memory.xml
new file mode 100644
index 000000000..1f0922786
--- /dev/null
+++ b/playgames/src/main/res/values-fil/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ MARKA
+ LEVEL
+ MAGLARONG MULI
+ I-pause ang laro
+ Ipagpatuloy ang laro
+
diff --git a/playgames/src/main/res/values-fil/strings_village.xml b/playgames/src/main/res/values-fil/strings_village.xml
new file mode 100644
index 000000000..bd86105ca
--- /dev/null
+++ b/playgames/src/main/res/values-fil/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sundan si Santa sa ika-24 ng Disyembre.
+ Magiging available sa ika-1 ng Disyembre ang Present Quest.
+ Malapit nang maging available ang Santa Snap.
+ Magiging available ang Gumball sa ika-1 ng Disyembre.
+ Magiging available ang Memory sa ika-1 ng Disyembre.
+ Magiging available ang Rocket Sleigh sa ika-1 ng Disyembre.
+ Magiging available ang Dasher Dancer sa ika-1 ng Disyembre.
+ Magiging available sa ika-1 ng Disyembre ang larong City Quiz.
+ Kasalukuyang hindi available ang %1$s.
+ Hindi pa available ang %1$s. Tingnang muli sa ibang pagkakataon!
+ Video
+ Maa-unlock ang video sa Disyembre %1$d.
+ Kasalukuyang hind available ang video.
+ I-play
+ Panoorin
+
diff --git a/playgames/src/main/res/values-fr-rCA/strings_gumball.xml b/playgames/src/main/res/values-fr-rCA/strings_gumball.xml
new file mode 100644
index 000000000..b275e6ed2
--- /dev/null
+++ b/playgames/src/main/res/values-fr-rCA/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Mettre le jeu sur pause
+ Reprendre le jeu
+
diff --git a/playgames/src/main/res/values-fr-rCA/strings_memory.xml b/playgames/src/main/res/values-fr-rCA/strings_memory.xml
new file mode 100644
index 000000000..45bf1c279
--- /dev/null
+++ b/playgames/src/main/res/values-fr-rCA/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ NIVEAU
+ REJOUER
+ Mettre le jeu sur pause
+ Reprendre le jeu
+
diff --git a/playgames/src/main/res/values-fr-rCA/strings_village.xml b/playgames/src/main/res/values-fr-rCA/strings_village.xml
new file mode 100644
index 000000000..0bbc2bc11
--- /dev/null
+++ b/playgames/src/main/res/values-fr-rCA/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Suivez le père Noël le 24 décembre.
+ Le jeu Quête de cadeaux sera offert le 1er décembre.
+ Le jeu Des photos avec le père Noël sera disponible bientôt.
+ Gumball sera offert à compter du 1er décembre.
+ Memory sera offert à compter du 1er décembre.
+ Rocket Sleigh sera offert à compter du 1er décembre.
+ Dasher Dancer sera offert à compter du 1er décembre.
+ Le jeu Quiz urbain sera offert le 1er décembre.
+ Le jeu %1$s n\'est actuellement pas disponible.
+ %1$s n\'est pas encore disponible. Revenez plus tard!
+ Vidéo
+ La vidéo sera déverrouillée à compter du %1$d décembre.
+ La vidéo n\'est pas disponible actuellement.
+ Lire
+ Visionner
+
diff --git a/playgames/src/main/res/values-fr-rCH/strings_gumball.xml b/playgames/src/main/res/values-fr-rCH/strings_gumball.xml
new file mode 100644
index 000000000..7d016596c
--- /dev/null
+++ b/playgames/src/main/res/values-fr-rCH/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Mettre la partie sur pause
+ Reprendre la partie
+
diff --git a/playgames/src/main/res/values-fr-rCH/strings_memory.xml b/playgames/src/main/res/values-fr-rCH/strings_memory.xml
new file mode 100644
index 000000000..bb582981c
--- /dev/null
+++ b/playgames/src/main/res/values-fr-rCH/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ NIVEAU
+ REJOUER
+ Mettre la partie sur pause
+ Reprendre la partie
+
diff --git a/playgames/src/main/res/values-fr-rCH/strings_village.xml b/playgames/src/main/res/values-fr-rCH/strings_village.xml
new file mode 100644
index 000000000..21a36e878
--- /dev/null
+++ b/playgames/src/main/res/values-fr-rCH/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Suivre le père Noël le 24 décembre
+ La quête des cadeaux sera disponible le 1er décembre.
+ Le jeu Selfie de lutin sera bientôt disponible.
+ Gumball sera disponible le 1er décembre.
+ Memory sera disponible le 1er décembre.
+ Rocket Sleigh sera disponible le 1er décembre.
+ Dasher Dancer sera disponible le 1er décembre.
+ Le questionnaire des villes sera disponible le 1er décembre.
+ %1$s n\'est pas disponible actuellement.
+ %1$s n\'est pas encore disponible. Réessayez plus tard.
+ Vidéo
+ La vidéo sera accessible le %1$d décembre.
+ La vidéo est actuellement indisponible.
+ Lire
+ Regarder
+
diff --git a/playgames/src/main/res/values-fr/strings_gumball.xml b/playgames/src/main/res/values-fr/strings_gumball.xml
new file mode 100644
index 000000000..7d016596c
--- /dev/null
+++ b/playgames/src/main/res/values-fr/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Mettre la partie sur pause
+ Reprendre la partie
+
diff --git a/playgames/src/main/res/values-fr/strings_memory.xml b/playgames/src/main/res/values-fr/strings_memory.xml
new file mode 100644
index 000000000..bb582981c
--- /dev/null
+++ b/playgames/src/main/res/values-fr/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ NIVEAU
+ REJOUER
+ Mettre la partie sur pause
+ Reprendre la partie
+
diff --git a/playgames/src/main/res/values-fr/strings_village.xml b/playgames/src/main/res/values-fr/strings_village.xml
new file mode 100644
index 000000000..21a36e878
--- /dev/null
+++ b/playgames/src/main/res/values-fr/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Suivre le père Noël le 24 décembre
+ La quête des cadeaux sera disponible le 1er décembre.
+ Le jeu Selfie de lutin sera bientôt disponible.
+ Gumball sera disponible le 1er décembre.
+ Memory sera disponible le 1er décembre.
+ Rocket Sleigh sera disponible le 1er décembre.
+ Dasher Dancer sera disponible le 1er décembre.
+ Le questionnaire des villes sera disponible le 1er décembre.
+ %1$s n\'est pas disponible actuellement.
+ %1$s n\'est pas encore disponible. Réessayez plus tard.
+ Vidéo
+ La vidéo sera accessible le %1$d décembre.
+ La vidéo est actuellement indisponible.
+ Lire
+ Regarder
+
diff --git a/playgames/src/main/res/values-gsw/strings_gumball.xml b/playgames/src/main/res/values-gsw/strings_gumball.xml
new file mode 100644
index 000000000..57fab51b1
--- /dev/null
+++ b/playgames/src/main/res/values-gsw/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Spiel pausieren
+ Spiel fortsetzen
+
diff --git a/playgames/src/main/res/values-gsw/strings_memory.xml b/playgames/src/main/res/values-gsw/strings_memory.xml
new file mode 100644
index 000000000..c827785fd
--- /dev/null
+++ b/playgames/src/main/res/values-gsw/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNKTE
+ LEVEL
+ NEUES SPIEL
+ Spiel pausieren
+ Spiel fortsetzen
+
diff --git a/playgames/src/main/res/values-gsw/strings_village.xml b/playgames/src/main/res/values-gsw/strings_village.xml
new file mode 100644
index 000000000..3dae2a8c9
--- /dev/null
+++ b/playgames/src/main/res/values-gsw/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Dem Weihnachtsmann ab 24. Dezember folgen
+ Present Quest steht ab dem 1. Dezember zur Verfügung.
+ Weihnachtsmann-Selfie ist bald verfügbar.
+ Gumball ist ab dem 1. Dezember verfügbar.
+ Memory ist ab dem 1. Dezember verfügbar.
+ Das Spiel \"Raketenflug\" ist ab dem 1. Dezember verfügbar.
+ Dasher Dancer ist ab dem 1. Dezember verfügbar.
+ City Quiz steht ab dem 1. Dezember zur Verfügung.
+ %1$s ist zurzeit nicht verfügbar.
+ %1$s ist noch nicht verfügbar. Schau später noch einmal vorbei.
+ Video
+ Dieses Video wird am %1$d freigegeben.
+ Dieses Video ist derzeit nicht verfügbar.
+ Spielen
+ Ansehen
+
diff --git a/playgames/src/main/res/values-hdpi/dimens.xml b/playgames/src/main/res/values-hdpi/dimens.xml
new file mode 100644
index 000000000..853b8d4c7
--- /dev/null
+++ b/playgames/src/main/res/values-hdpi/dimens.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+ 80dp
+ 108dp
+ 25dp
+ 18dp
+ 16dp
+ 18dp
+ 20dp
+ 12sp
+ 180dp
+ 180dp
+ 300dp
+ 36dp
+ 50
+
+
diff --git a/playgames/src/main/res/values-hr/strings_gumball.xml b/playgames/src/main/res/values-hr/strings_gumball.xml
new file mode 100644
index 000000000..1b2047533
--- /dev/null
+++ b/playgames/src/main/res/values-hr/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pauziraj igru
+ Nastavi igru
+
diff --git a/playgames/src/main/res/values-hr/strings_memory.xml b/playgames/src/main/res/values-hr/strings_memory.xml
new file mode 100644
index 000000000..40099130e
--- /dev/null
+++ b/playgames/src/main/res/values-hr/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ REZULTAT
+ RAZINA
+ IGRAJ PONOVO
+ Pauziraj igru
+ Nastavi igru
+
diff --git a/playgames/src/main/res/values-hr/strings_village.xml b/playgames/src/main/res/values-hr/strings_village.xml
new file mode 100644
index 000000000..1a4471e2e
--- /dev/null
+++ b/playgames/src/main/res/values-hr/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Prati Djeda Božićnjaka 24. prosinca.
+ Lov na darove bit će dostupan od 1. prosinca.
+ Djedov fotograf bit će dostupan uskoro.
+ Igra Gumball bit će dostupna od 1. prosinca.
+ Igra Memory bit će dostupna od 1. prosinca.
+ Igra Rocket Sleigh bit će dostupna od 1. prosinca.
+ Igra Dasher Dancer bit će dostupna od 1. prosinca.
+ Igra Kviz o gradovima bit će dostupna od 1. prosinca.
+ Igra %1$s trenutačno nije dostupna.
+ Igra %1$s još nije dostupna. Vratite se kasnije!
+ Videozapis
+ Videozapis se otključava %1$d. prosinca.
+ Videozapis trenutačno nije dostupan.
+ Reprodukcija
+ Gledanje
+
diff --git a/playgames/src/main/res/values-id/strings_gumball.xml b/playgames/src/main/res/values-id/strings_gumball.xml
new file mode 100644
index 000000000..068acf826
--- /dev/null
+++ b/playgames/src/main/res/values-id/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Jeda game
+ Lanjutkan game
+
diff --git a/playgames/src/main/res/values-id/strings_memory.xml b/playgames/src/main/res/values-id/strings_memory.xml
new file mode 100644
index 000000000..e2bf12d36
--- /dev/null
+++ b/playgames/src/main/res/values-id/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SKOR
+ LEVEL
+ MAIN LAGI
+ Jeda game
+ Lanjutkan game
+
diff --git a/playgames/src/main/res/values-id/strings_village.xml b/playgames/src/main/res/values-id/strings_village.xml
new file mode 100644
index 000000000..c7806cb86
--- /dev/null
+++ b/playgames/src/main/res/values-id/strings_village.xml
@@ -0,0 +1,35 @@
+
+
+
+
+ Ikuti Sinterklas pada tanggal 24 Desember.
+ Cari Hadiah akan hadir tanggal 1 Desember.
+ Santa Snap akan segera tersedia.
+ Bola Permen akan tersedia pada tanggal 1 Desember.
+ Cocokkan Gambar akan tersedia pada tanggal 1 Desember.
+
+ Seluncur Roket akan tersedia pada tanggal 1 Desember.
+ Joget Santa akan tersedia pada tanggal 1 Desember.
+ Game Kuis Tebak Kota akan tersedia pada tanggal 1 Desember.
+ %1$s saat ini tidak tersedia.
+ %1$s belum tersedia. Periksa lagi nanti!
+ Video
+ Video akan dibuka pada bulan Desember %1$d.
+ Video saat ini tidak tersedia.
+ Mainkan
+ Tonton
+
diff --git a/playgames/src/main/res/values-in/strings_gumball.xml b/playgames/src/main/res/values-in/strings_gumball.xml
new file mode 100644
index 000000000..068acf826
--- /dev/null
+++ b/playgames/src/main/res/values-in/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Jeda game
+ Lanjutkan game
+
diff --git a/playgames/src/main/res/values-in/strings_memory.xml b/playgames/src/main/res/values-in/strings_memory.xml
new file mode 100644
index 000000000..e2bf12d36
--- /dev/null
+++ b/playgames/src/main/res/values-in/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SKOR
+ LEVEL
+ MAIN LAGI
+ Jeda game
+ Lanjutkan game
+
diff --git a/playgames/src/main/res/values-in/strings_village.xml b/playgames/src/main/res/values-in/strings_village.xml
new file mode 100644
index 000000000..c7806cb86
--- /dev/null
+++ b/playgames/src/main/res/values-in/strings_village.xml
@@ -0,0 +1,35 @@
+
+
+
+
+ Ikuti Sinterklas pada tanggal 24 Desember.
+ Cari Hadiah akan hadir tanggal 1 Desember.
+ Santa Snap akan segera tersedia.
+ Bola Permen akan tersedia pada tanggal 1 Desember.
+ Cocokkan Gambar akan tersedia pada tanggal 1 Desember.
+
+ Seluncur Roket akan tersedia pada tanggal 1 Desember.
+ Joget Santa akan tersedia pada tanggal 1 Desember.
+ Game Kuis Tebak Kota akan tersedia pada tanggal 1 Desember.
+ %1$s saat ini tidak tersedia.
+ %1$s belum tersedia. Periksa lagi nanti!
+ Video
+ Video akan dibuka pada bulan Desember %1$d.
+ Video saat ini tidak tersedia.
+ Mainkan
+ Tonton
+
diff --git a/playgames/src/main/res/values-it/strings_gumball.xml b/playgames/src/main/res/values-it/strings_gumball.xml
new file mode 100644
index 000000000..ab153acea
--- /dev/null
+++ b/playgames/src/main/res/values-it/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Metti in pausa la partita
+ Riprendi partita
+
diff --git a/playgames/src/main/res/values-it/strings_memory.xml b/playgames/src/main/res/values-it/strings_memory.xml
new file mode 100644
index 000000000..52d8ccca8
--- /dev/null
+++ b/playgames/src/main/res/values-it/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PUNTEGGIO
+ LIVELLO
+ GIOCA ANCORA
+ Metti in pausa la partita
+ Riprendi partita
+
diff --git a/playgames/src/main/res/values-it/strings_village.xml b/playgames/src/main/res/values-it/strings_village.xml
new file mode 100644
index 000000000..e07a47b0f
--- /dev/null
+++ b/playgames/src/main/res/values-it/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Segui Babbo Natale il 24 dicembre.
+ \"Caccia ai regali\" sarà disponibile a partire dal 1° dicembre.
+ Santa Snap sarà disponibile a breve.
+ Palline di zucchero sarà disponibile il 1° dicembre.
+ Memory sarà disponibile il 1° dicembre.
+ Rocket Sleigh sarà disponibile il 1° dicembre.
+ Ballo di Natale sarà disponibile il 1° dicembre.
+ Il gioco Indovina la città sarà disponibile a partire dal 1° dicembre.
+ %1$s non è al momento disponibile.
+ %1$s non è ancora disponibile. Controlla più tardi.
+ Video
+ Il video verrà sbloccato il %1$d dicembre.
+ Il video attualmente non è disponibile.
+ Gioca
+ Guarda
+
diff --git a/playgames/src/main/res/values-ja/strings_gumball.xml b/playgames/src/main/res/values-ja/strings_gumball.xml
new file mode 100644
index 000000000..a7e0983d1
--- /dev/null
+++ b/playgames/src/main/res/values-ja/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ ゲームを一時停止
+ ゲームを再開
+
diff --git a/playgames/src/main/res/values-ja/strings_memory.xml b/playgames/src/main/res/values-ja/strings_memory.xml
new file mode 100644
index 000000000..5185464e9
--- /dev/null
+++ b/playgames/src/main/res/values-ja/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ スコア
+ レベル
+ もう一度プレイ
+ ゲームを一時停止
+ ゲームを再開
+
diff --git a/playgames/src/main/res/values-ja/strings_village.xml b/playgames/src/main/res/values-ja/strings_village.xml
new file mode 100644
index 000000000..3cfcb9028
--- /dev/null
+++ b/playgames/src/main/res/values-ja/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ 12月24日はサンタさんを追跡しましょう。
+ プレゼント クエストは 12 月 1 日よりプレイできます。
+ Santa Snap はまもなくご利用いただけるようになります。
+ ガムボールは 12 月 1 日よりプレイできます。
+ 記憶ゲームは 12 月 1 日よりプレイできます。
+ ロケットそりは 12 月 1 日よりプレイできます。
+ ダッシャー ダンサーは 12 月 1 日よりプレイできます。
+ 都市クイズは 12 月 1 日よりプレイできます。
+ %1$s は現在プレイできません。
+ %1$s はまだご利用いただけません。しばらくしてからもう一度ご確認ください。
+ 動画
+ 動画は12月%1$d日よりご覧いただけます。
+ 動画は現在ご覧いただけません。
+ 遊ぶ
+ 見る
+
diff --git a/playgames/src/main/res/values-ko/strings_gumball.xml b/playgames/src/main/res/values-ko/strings_gumball.xml
new file mode 100644
index 000000000..95456da3a
--- /dev/null
+++ b/playgames/src/main/res/values-ko/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ 게임 일시중지
+ 게임 계속하기
+
diff --git a/playgames/src/main/res/values-ko/strings_memory.xml b/playgames/src/main/res/values-ko/strings_memory.xml
new file mode 100644
index 000000000..2b0f3056d
--- /dev/null
+++ b/playgames/src/main/res/values-ko/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ 점수
+ 레벨
+ 다시 하기
+ 게임 일시중지
+ 게임 계속하기
+
diff --git a/playgames/src/main/res/values-ko/strings_village.xml b/playgames/src/main/res/values-ko/strings_village.xml
new file mode 100644
index 000000000..5a1017568
--- /dev/null
+++ b/playgames/src/main/res/values-ko/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ 12월 24일에 산타를 추적해 보세요.
+ 선물 찾기 게임은 12월 1일부터 즐길 수 있습니다.
+ 산타 셀카가 곧 제공됩니다.
+ 풍선껌 게임은 12월 1일부터 즐길 수 있습니다.
+ 기억력 게임은 12월 1일부터 즐길 수 있습니다.
+ 로켓 썰매 게임은 12월 1일부터 즐길 수 있습니다.
+ 대셔 댄서 게임은 12월 1일부터 즐길 수 있습니다.
+ 도시 퀴즈 게임은 12월 1일부터 즐길 수 있습니다.
+ 현재 %1$s 게임을 할 수 없습니다.
+ %1$s은(는) 아직 사용할 수 없습니다. 나중에 다시 확인해 주세요.
+ 동영상
+ 동영상 잠금은 12월 %1$d일에 해제됩니다.
+ 현재 동영상을 시청할 수 없습니다.
+ 게임하기
+ 보기
+
diff --git a/playgames/src/main/res/values-ln/strings_gumball.xml b/playgames/src/main/res/values-ln/strings_gumball.xml
new file mode 100644
index 000000000..7d016596c
--- /dev/null
+++ b/playgames/src/main/res/values-ln/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Mettre la partie sur pause
+ Reprendre la partie
+
diff --git a/playgames/src/main/res/values-ln/strings_memory.xml b/playgames/src/main/res/values-ln/strings_memory.xml
new file mode 100644
index 000000000..bb582981c
--- /dev/null
+++ b/playgames/src/main/res/values-ln/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCORE
+ NIVEAU
+ REJOUER
+ Mettre la partie sur pause
+ Reprendre la partie
+
diff --git a/playgames/src/main/res/values-ln/strings_village.xml b/playgames/src/main/res/values-ln/strings_village.xml
new file mode 100644
index 000000000..21a36e878
--- /dev/null
+++ b/playgames/src/main/res/values-ln/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Suivre le père Noël le 24 décembre
+ La quête des cadeaux sera disponible le 1er décembre.
+ Le jeu Selfie de lutin sera bientôt disponible.
+ Gumball sera disponible le 1er décembre.
+ Memory sera disponible le 1er décembre.
+ Rocket Sleigh sera disponible le 1er décembre.
+ Dasher Dancer sera disponible le 1er décembre.
+ Le questionnaire des villes sera disponible le 1er décembre.
+ %1$s n\'est pas disponible actuellement.
+ %1$s n\'est pas encore disponible. Réessayez plus tard.
+ Vidéo
+ La vidéo sera accessible le %1$d décembre.
+ La vidéo est actuellement indisponible.
+ Lire
+ Regarder
+
diff --git a/playgames/src/main/res/values-lt/strings_gumball.xml b/playgames/src/main/res/values-lt/strings_gumball.xml
new file mode 100644
index 000000000..6d977760b
--- /dev/null
+++ b/playgames/src/main/res/values-lt/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pristabdyti žaidimą
+ Tęsti žaidimą
+
diff --git a/playgames/src/main/res/values-lt/strings_memory.xml b/playgames/src/main/res/values-lt/strings_memory.xml
new file mode 100644
index 000000000..d47a7459a
--- /dev/null
+++ b/playgames/src/main/res/values-lt/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ REZULTATAS
+ LYGIS
+ ŽAISTI DAR KARTĄ
+ Pristabdyti žaidimą
+ Tęsti žaidimą
+
diff --git a/playgames/src/main/res/values-lt/strings_village.xml b/playgames/src/main/res/values-lt/strings_village.xml
new file mode 100644
index 000000000..a1eaff116
--- /dev/null
+++ b/playgames/src/main/res/values-lt/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sekite Kalėdų Senelį gruodžio 24 d.
+ „Dovanų ieškynės“ bus pasiekiamas nuo gruodžio 1 d.
+ Žaidimą „Kalėdų Senelio asmenukė“ galėsite žaisti jau netrukus.
+ „Gumball“ bus pasiekiamas gruodžio 1 d.
+ „Memory“ bus pasiekiamas gruodžio 1 d.
+ „Rocket Sleigh“ bus pasiekiamas gruodžio 1 d.
+ „Dasher Dancer“ bus pasiekiamas gruodžio 1 d.
+ Žaidimas „Miestų viktorina“ bus pasiekiamas nuo gruodžio 1 d.
+ „%1$s“ šiuo metu nepasiekiamas.
+ „%1$s“ dar nepasiekiamas. Apsilankykite vėliau!
+ Vaizdo įrašas
+ Vaizdo įrašas bus atrakintas gruodžio %1$d d.
+ Vaizdo įrašas šiuo metu nepasiekiamas.
+ Leisti
+ Žiūrėti
+
diff --git a/playgames/src/main/res/values-lv/strings_gumball.xml b/playgames/src/main/res/values-lv/strings_gumball.xml
new file mode 100644
index 000000000..1cb230f59
--- /dev/null
+++ b/playgames/src/main/res/values-lv/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Apturēt spēli
+ Atsākt spēli
+
diff --git a/playgames/src/main/res/values-lv/strings_memory.xml b/playgames/src/main/res/values-lv/strings_memory.xml
new file mode 100644
index 000000000..ac44e9bb1
--- /dev/null
+++ b/playgames/src/main/res/values-lv/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ REZULTĀTS
+ LĪMENIS
+ SPĒLĒT VĒLREIZ
+ Apturēt spēli
+ Atsākt spēli
+
diff --git a/playgames/src/main/res/values-lv/strings_village.xml b/playgames/src/main/res/values-lv/strings_village.xml
new file mode 100644
index 000000000..6beb76bca
--- /dev/null
+++ b/playgames/src/main/res/values-lv/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sekojiet Ziemassvētku vecītim 24. decembrī!
+ Dāvanu meklēšanas spēle (Present Quest) būs pieejama no 1. decembra.
+ Drīzumā būs pieejamas Ziemassvētku vecīša pašbildes.
+ Spēle “Gumball” būs pieejama no 1. decembra.
+ Spēle “Memory” būs pieejama no 1. decembra.
+ Spēle “Rocket Sleigh” būs pieejama no 1. decembra.
+ Spēle “Dasher Dancer” būs pieejama no 1. decembra.
+ Pilsētu viktorīnas spēle (City Quiz) būs pieejama no 1. decembra.
+ Spēle %1$s pašlaik nav pieejama.
+ Spēle %1$s vēl nav pieejama. Pārbaudiet vēlāk.
+ Videoklips
+ Videoklips tiks iespējots %1$d. decembrī.
+ Videoklips pašlaik nav pieejams.
+ Atskaņot
+ Skatīties
+
diff --git a/playgames/src/main/res/values-ml/strings_gumball.xml b/playgames/src/main/res/values-ml/strings_gumball.xml
new file mode 100644
index 000000000..3dc178ce4
--- /dev/null
+++ b/playgames/src/main/res/values-ml/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ ഗെയിം തൽക്കാലം നിർത്തുക
+ ഗെയിം പുനരാരംഭിക്കുക
+
diff --git a/playgames/src/main/res/values-ml/strings_memory.xml b/playgames/src/main/res/values-ml/strings_memory.xml
new file mode 100644
index 000000000..49f4b0227
--- /dev/null
+++ b/playgames/src/main/res/values-ml/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ സ്കോർ
+ ലെവൽ
+ വീണ്ടും കളിക്കുക
+ ഗെയിം തൽക്കാലം നിർത്തുക
+ ഗെയിം പുനരാരംഭിക്കുക
+
diff --git a/playgames/src/main/res/values-ml/strings_village.xml b/playgames/src/main/res/values-ml/strings_village.xml
new file mode 100644
index 000000000..85fa405eb
--- /dev/null
+++ b/playgames/src/main/res/values-ml/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ ഡിസംബർ 24-ന് സാന്തയെ പിന്തുടരുക.
+ പ്രസന്റ് ക്വസ്റ്റ് ഡിസംബർ 1-ന് ലഭ്യമാകും.
+ സാന്താ സ്നാപ്പ് ഉടൻ ലഭ്യമാകും.
+ ഗംബോൾ ഡിസംബർ 1-ന് ലഭ്യമാകും.
+ മെമ്മറി ഡിസംബർ 1-ന് ലഭ്യമാകും.
+ റോക്കറ്റ് ഹിമവണ്ടി ഡിസംബർ 1-ന് ലഭ്യമാകും.
+ ഡാഷർ ഡാൻസർ ഡിസംബർ 1-ന് ലഭ്യമാകും.
+ സിറ്റി ക്വിസ് ഗെയിം ഡിസംബർ 1-ന് ലഭ്യമാകും.
+ %1$s നിലവിൽ ലഭ്യമല്ല.
+ %1$s ഇതുവരെ ലഭ്യമായിട്ടില്ല. പിന്നീട് വീണ്ടും പരിശോധിക്കുക!
+ വീഡിയോ
+ വീഡിയോ ഡിസംബർ %1$d-ന് അൺലോക്കുചെയ്യും.
+ വീഡിയോ നിലവിൽ ലഭ്യമല്ല.
+ പ്ലേ ചെയ്യുക
+ കാണുക
+
diff --git a/playgames/src/main/res/values-mo/strings_gumball.xml b/playgames/src/main/res/values-mo/strings_gumball.xml
new file mode 100644
index 000000000..441b15780
--- /dev/null
+++ b/playgames/src/main/res/values-mo/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Întrerupe jocul
+ Reia jocul
+
diff --git a/playgames/src/main/res/values-mo/strings_memory.xml b/playgames/src/main/res/values-mo/strings_memory.xml
new file mode 100644
index 000000000..a31598892
--- /dev/null
+++ b/playgames/src/main/res/values-mo/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCOR
+ NIVEL
+ JOACĂ DIN NOU
+ Întrerupe jocul
+ Reia jocul
+
diff --git a/playgames/src/main/res/values-mo/strings_village.xml b/playgames/src/main/res/values-mo/strings_village.xml
new file mode 100644
index 000000000..d7781642f
--- /dev/null
+++ b/playgames/src/main/res/values-mo/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Urmărește-l pe Moș Crăciun pe 24 decembrie.
+ Jocul În căutarea cadourilor va fi disponibil pe 1 decembrie.
+ Jocul Sesiune foto va fi disponibil în curând.
+ Gumball va fi disponibil la 1 decembrie.
+ Memory va fi disponibil la 1 decembrie.
+ Sania-rachetă va fi disponibil la 1 decembrie.
+ Dansează cu Dasher va fi disponibil la 1 decembrie.
+ Jocul Găsește orașul va fi disponibil pe 1 decembrie.
+ Jocul %1$s nu este disponibil momentan.
+ %1$s nu este disponibil încă. Revino mai târziu!
+ Videoclip
+ Videoclipul va fi disponibil la %1$d decembrie.
+ Videoclipul nu este disponibil momentan.
+ Joacă
+ Vizionează
+
diff --git a/playgames/src/main/res/values-nb/strings_gumball.xml b/playgames/src/main/res/values-nb/strings_gumball.xml
new file mode 100644
index 000000000..d6d36e8e3
--- /dev/null
+++ b/playgames/src/main/res/values-nb/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Sett spillet på pause
+ Gjenoppta spillet
+
diff --git a/playgames/src/main/res/values-nb/strings_memory.xml b/playgames/src/main/res/values-nb/strings_memory.xml
new file mode 100644
index 000000000..187a18318
--- /dev/null
+++ b/playgames/src/main/res/values-nb/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ POENG
+ NIVÅ
+ SPILL PÅ NYTT
+ Sett spillet på pause
+ Gjenoppta spillet
+
diff --git a/playgames/src/main/res/values-nb/strings_village.xml b/playgames/src/main/res/values-nb/strings_village.xml
new file mode 100644
index 000000000..264c3a350
--- /dev/null
+++ b/playgames/src/main/res/values-nb/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Følg julenissen på julaften.
+ Gavejakt blir tilgjengelig 1. desember.
+ Nisseknips blir snart tilgjengelig.
+ Rulledrops blir tilgjengelig 1. desember.
+ Memory blir tilgjengelig 1. desember.
+ Rakettsleden blir tilgjengelig 1. desember.
+ Nissedans blir tilgjengelig 1. desember.
+ Byquiz-spillet blir tilgjengelig 1. desember.
+ %1$s er ikke tilgjengelig.
+ %1$s er ikke tilgjengelig ennå. Kom tilbake senere.
+ Instream-video
+ Videoen blir tilgjengelig %1$d. desember.
+ Videoen er ikke tilgjengelig for øyeblikket.
+ Spill
+ Se
+
diff --git a/playgames/src/main/res/values-no/strings_gumball.xml b/playgames/src/main/res/values-no/strings_gumball.xml
new file mode 100644
index 000000000..d6d36e8e3
--- /dev/null
+++ b/playgames/src/main/res/values-no/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Sett spillet på pause
+ Gjenoppta spillet
+
diff --git a/playgames/src/main/res/values-no/strings_memory.xml b/playgames/src/main/res/values-no/strings_memory.xml
new file mode 100644
index 000000000..187a18318
--- /dev/null
+++ b/playgames/src/main/res/values-no/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ POENG
+ NIVÅ
+ SPILL PÅ NYTT
+ Sett spillet på pause
+ Gjenoppta spillet
+
diff --git a/playgames/src/main/res/values-no/strings_village.xml b/playgames/src/main/res/values-no/strings_village.xml
new file mode 100644
index 000000000..264c3a350
--- /dev/null
+++ b/playgames/src/main/res/values-no/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Følg julenissen på julaften.
+ Gavejakt blir tilgjengelig 1. desember.
+ Nisseknips blir snart tilgjengelig.
+ Rulledrops blir tilgjengelig 1. desember.
+ Memory blir tilgjengelig 1. desember.
+ Rakettsleden blir tilgjengelig 1. desember.
+ Nissedans blir tilgjengelig 1. desember.
+ Byquiz-spillet blir tilgjengelig 1. desember.
+ %1$s er ikke tilgjengelig.
+ %1$s er ikke tilgjengelig ennå. Kom tilbake senere.
+ Instream-video
+ Videoen blir tilgjengelig %1$d. desember.
+ Videoen er ikke tilgjengelig for øyeblikket.
+ Spill
+ Se
+
diff --git a/playgames/src/main/res/values-pl/strings_gumball.xml b/playgames/src/main/res/values-pl/strings_gumball.xml
new file mode 100644
index 000000000..e2e0e5006
--- /dev/null
+++ b/playgames/src/main/res/values-pl/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Wstrzymaj grę
+ Wznów grę
+
diff --git a/playgames/src/main/res/values-pl/strings_memory.xml b/playgames/src/main/res/values-pl/strings_memory.xml
new file mode 100644
index 000000000..8a5b894bf
--- /dev/null
+++ b/playgames/src/main/res/values-pl/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ WYNIK
+ POZIOM
+ ZAGRAJ PONOWNIE
+ Wstrzymaj grę
+ Wznów grę
+
diff --git a/playgames/src/main/res/values-pl/strings_village.xml b/playgames/src/main/res/values-pl/strings_village.xml
new file mode 100644
index 000000000..2028a238b
--- /dev/null
+++ b/playgames/src/main/res/values-pl/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Śledź Mikołaja w dniu 24 grudnia.
+ Gra Wyprawa po prezenty będzie dostępna od 1 grudnia.
+ Gra Mikołajowe fotki będzie dostępna już wkrótce.
+ Gra Guma w kulkach będzie dostępna od 1 grudnia.
+ Gra Pamięć będzie dostępna od 1 grudnia.
+ Gra Sanie rakietowe będzie dostępna od 1 grudnia.
+ Gra Fircyk i Tancerz będzie dostępna od 1 grudnia.
+ Gra Miejski quiz będzie dostępna od 1 grudnia
+ Gra %1$s jest w tej chwili niedostępna.
+ Gra %1$s jeszcze nie jest dostępna. Sprawdź jeszcze raz później.
+ Film
+ Film zostanie odblokowany %1$d grudnia.
+ Film jest obecnie niedostępny.
+ Zagraj
+ Obejrzyj
+
diff --git a/playgames/src/main/res/values-pt-rBR/strings_gumball.xml b/playgames/src/main/res/values-pt-rBR/strings_gumball.xml
new file mode 100644
index 000000000..b09e3bd64
--- /dev/null
+++ b/playgames/src/main/res/values-pt-rBR/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar jogo
+ Retomar jogo
+
diff --git a/playgames/src/main/res/values-pt-rBR/strings_memory.xml b/playgames/src/main/res/values-pt-rBR/strings_memory.xml
new file mode 100644
index 000000000..257793a2e
--- /dev/null
+++ b/playgames/src/main/res/values-pt-rBR/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PONTUAÇÃO
+ NÍVEL
+ JOGAR NOVAMENTE
+ Pausar jogo
+ Retomar jogo
+
diff --git a/playgames/src/main/res/values-pt-rBR/strings_village.xml b/playgames/src/main/res/values-pt-rBR/strings_village.xml
new file mode 100644
index 000000000..f02318206
--- /dev/null
+++ b/playgames/src/main/res/values-pt-rBR/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Siga o Papai Noel em 24 de dezembro.
+ O jogo Caça ao presente estará disponível em 1º de dezembro.
+ O Selfie do Papai Noel estará disponível em breve.
+ O jogo Ladeira dos chicletes estará disponível em 1º de dezembro.
+ O Jogo da memória estará disponível em 1º de dezembro.
+ O jogo Trenó-foguete estará disponível em 1º de dezembro.
+ O jogo Dança das renas estará disponível em 1º de dezembro.
+ O Jogo das cidades está disponível em 1º de dezembro.
+ O %1$s está indisponível no momento.
+ %1$s ainda não está disponível. Volte mais tarde!
+ Vídeo
+ O vídeo será desbloqueado em %1$d de dezembro.
+ O vídeo está indisponível no momento.
+ Jogar
+ Assistir
+
diff --git a/playgames/src/main/res/values-pt-rPT/strings_gumball.xml b/playgames/src/main/res/values-pt-rPT/strings_gumball.xml
new file mode 100644
index 000000000..8197bfcd9
--- /dev/null
+++ b/playgames/src/main/res/values-pt-rPT/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Colocar o jogo em pausa
+ Retomar o jogo
+
diff --git a/playgames/src/main/res/values-pt-rPT/strings_memory.xml b/playgames/src/main/res/values-pt-rPT/strings_memory.xml
new file mode 100644
index 000000000..27a65554c
--- /dev/null
+++ b/playgames/src/main/res/values-pt-rPT/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PONTUAÇÃO
+ NÍVEL
+ JOGAR DE NOVO
+ Colocar o jogo em pausa
+ Retomar o jogo
+
diff --git a/playgames/src/main/res/values-pt-rPT/strings_village.xml b/playgames/src/main/res/values-pt-rPT/strings_village.xml
new file mode 100644
index 000000000..ba3bfc504
--- /dev/null
+++ b/playgames/src/main/res/values-pt-rPT/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Siga o Pai Natal no dia 24 de dezembro.
+ O Caça aos presentes estará disponível a 1 de dezembro.
+ As Selfies do Pai Natal vão estar disponíveis em breve.
+ O Pastilha Elástica estará disponível em 1 de dezembro.
+ O Memória estará disponível em 1 de dezembro.
+ O Trenó-foguete estará disponível em 1 de dezembro.
+ O Dançarino Veloz estará disponível em 1 de dezembro.
+ O jogo Questionário de cidades estará disponível a 1 de dezembro.
+ Neste momento, o %1$s não está disponível.
+ %1$s ainda não está disponível. Regresse mais tarde!
+ Vídeo
+ O vídeo será desbloqueado em %1$d de dezembro.
+ O vídeo não está disponível atualmente.
+ Jogar
+ Ver
+
diff --git a/playgames/src/main/res/values-pt/strings_gumball.xml b/playgames/src/main/res/values-pt/strings_gumball.xml
new file mode 100644
index 000000000..b09e3bd64
--- /dev/null
+++ b/playgames/src/main/res/values-pt/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausar jogo
+ Retomar jogo
+
diff --git a/playgames/src/main/res/values-pt/strings_memory.xml b/playgames/src/main/res/values-pt/strings_memory.xml
new file mode 100644
index 000000000..257793a2e
--- /dev/null
+++ b/playgames/src/main/res/values-pt/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ PONTUAÇÃO
+ NÍVEL
+ JOGAR NOVAMENTE
+ Pausar jogo
+ Retomar jogo
+
diff --git a/playgames/src/main/res/values-pt/strings_village.xml b/playgames/src/main/res/values-pt/strings_village.xml
new file mode 100644
index 000000000..f02318206
--- /dev/null
+++ b/playgames/src/main/res/values-pt/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Siga o Papai Noel em 24 de dezembro.
+ O jogo Caça ao presente estará disponível em 1º de dezembro.
+ O Selfie do Papai Noel estará disponível em breve.
+ O jogo Ladeira dos chicletes estará disponível em 1º de dezembro.
+ O Jogo da memória estará disponível em 1º de dezembro.
+ O jogo Trenó-foguete estará disponível em 1º de dezembro.
+ O jogo Dança das renas estará disponível em 1º de dezembro.
+ O Jogo das cidades está disponível em 1º de dezembro.
+ O %1$s está indisponível no momento.
+ %1$s ainda não está disponível. Volte mais tarde!
+ Vídeo
+ O vídeo será desbloqueado em %1$d de dezembro.
+ O vídeo está indisponível no momento.
+ Jogar
+ Assistir
+
diff --git a/playgames/src/main/res/values-ro/strings_gumball.xml b/playgames/src/main/res/values-ro/strings_gumball.xml
new file mode 100644
index 000000000..441b15780
--- /dev/null
+++ b/playgames/src/main/res/values-ro/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Întrerupe jocul
+ Reia jocul
+
diff --git a/playgames/src/main/res/values-ro/strings_memory.xml b/playgames/src/main/res/values-ro/strings_memory.xml
new file mode 100644
index 000000000..a31598892
--- /dev/null
+++ b/playgames/src/main/res/values-ro/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ SCOR
+ NIVEL
+ JOACĂ DIN NOU
+ Întrerupe jocul
+ Reia jocul
+
diff --git a/playgames/src/main/res/values-ro/strings_village.xml b/playgames/src/main/res/values-ro/strings_village.xml
new file mode 100644
index 000000000..d7781642f
--- /dev/null
+++ b/playgames/src/main/res/values-ro/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Urmărește-l pe Moș Crăciun pe 24 decembrie.
+ Jocul În căutarea cadourilor va fi disponibil pe 1 decembrie.
+ Jocul Sesiune foto va fi disponibil în curând.
+ Gumball va fi disponibil la 1 decembrie.
+ Memory va fi disponibil la 1 decembrie.
+ Sania-rachetă va fi disponibil la 1 decembrie.
+ Dansează cu Dasher va fi disponibil la 1 decembrie.
+ Jocul Găsește orașul va fi disponibil pe 1 decembrie.
+ Jocul %1$s nu este disponibil momentan.
+ %1$s nu este disponibil încă. Revino mai târziu!
+ Videoclip
+ Videoclipul va fi disponibil la %1$d decembrie.
+ Videoclipul nu este disponibil momentan.
+ Joacă
+ Vizionează
+
diff --git a/playgames/src/main/res/values-ru/strings_gumball.xml b/playgames/src/main/res/values-ru/strings_gumball.xml
new file mode 100644
index 000000000..4d643ee90
--- /dev/null
+++ b/playgames/src/main/res/values-ru/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Приостановить игру
+ Продолжить игру
+
diff --git a/playgames/src/main/res/values-ru/strings_memory.xml b/playgames/src/main/res/values-ru/strings_memory.xml
new file mode 100644
index 000000000..056b88ba4
--- /dev/null
+++ b/playgames/src/main/res/values-ru/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ СЧЕТ
+ УРОВЕНЬ
+ СЫГРАТЬ ЕЩЁ РАЗ
+ Приостановить игру
+ Продолжить игру
+
diff --git a/playgames/src/main/res/values-ru/strings_village.xml b/playgames/src/main/res/values-ru/strings_village.xml
new file mode 100644
index 000000000..824cf1402
--- /dev/null
+++ b/playgames/src/main/res/values-ru/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Санта отправится в путь 24 декабря.
+ Игра \"Найди подарок\" выйдет 1 декабря
+ Игра \"Полет за подарками\" пока недоступна.
+ Игра \"Жвачка\" выйдет 1 декабря.
+ Игра \"Память\" выйдет 1 декабря.
+ Игра \"Реактивные сани\" выйдет 1 декабря.
+ Игра \"Лучший танцор\" выйдет 1 декабря.
+ Игра \"Угадай город\" выйдет 1 декабря
+ Игра \"%1$s\" пока недоступна
+ Игра \"%1$s\" пока недоступна.
+ Видео
+ Видео станет доступно %1$d декабря.
+ Видео пока недоступно.
+ Играть
+ Смотреть
+
diff --git a/playgames/src/main/res/values-sl/strings_gumball.xml b/playgames/src/main/res/values-sl/strings_gumball.xml
new file mode 100644
index 000000000..1f762600c
--- /dev/null
+++ b/playgames/src/main/res/values-sl/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Zaustavi igro
+ Nadaljuj igro
+
diff --git a/playgames/src/main/res/values-sl/strings_memory.xml b/playgames/src/main/res/values-sl/strings_memory.xml
new file mode 100644
index 000000000..0ec7a23e0
--- /dev/null
+++ b/playgames/src/main/res/values-sl/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ REZULTAT
+ STOPNJA
+ IGRAJ ZNOVA
+ Zaustavi igro
+ Nadaljuj igro
+
diff --git a/playgames/src/main/res/values-sl/strings_village.xml b/playgames/src/main/res/values-sl/strings_village.xml
new file mode 100644
index 000000000..844f65d29
--- /dev/null
+++ b/playgames/src/main/res/values-sl/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Spremljajte Božička 24. decembra.
+ Iskanje daril bo na voljo 1. decembra.
+ Božičkovi sebki bodo kmalu na voljo.
+ Igra Gumball bo na voljo 1. decembra.
+ Igra Memory bo na voljo 1. decembra.
+ Igra Rocket Sleigh bo na voljo 1. decembra.
+ Igra Dasher Dancer bo na voljo 1. decembra.
+ Ugibanje mest bo na voljo 1. decembra.
+ %1$s trenutno ni na voljo.
+ %1$s še ni na voljo. Preverite znova pozneje.
+ Videoposnetek
+ Videoposnetek bo odklenjen %1$d. decembra.
+ Videoposnetek trenutno ni na voljo.
+ Igranje
+ Ogled
+
diff --git a/playgames/src/main/res/values-sv/strings_gumball.xml b/playgames/src/main/res/values-sv/strings_gumball.xml
new file mode 100644
index 000000000..a1ccb5b96
--- /dev/null
+++ b/playgames/src/main/res/values-sv/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Pausa spelet
+ Fortsätt spela
+
diff --git a/playgames/src/main/res/values-sv/strings_memory.xml b/playgames/src/main/res/values-sv/strings_memory.xml
new file mode 100644
index 000000000..88bfdf6cc
--- /dev/null
+++ b/playgames/src/main/res/values-sv/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ POÄNG
+ NIVÅ
+ SPELA IGEN
+ Pausa spelet
+ Fortsätt spela
+
diff --git a/playgames/src/main/res/values-sv/strings_village.xml b/playgames/src/main/res/values-sv/strings_village.xml
new file mode 100644
index 000000000..987c096dc
--- /dev/null
+++ b/playgames/src/main/res/values-sv/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Följ tomten den 24 december.
+ Klappjakten släpps 1 december.
+ Tomteselfies kommer snart.
+ Spelet Gumball går att spela den 1 december.
+ Spelet Memory går att spela den 1 december.
+ Spelet Rocket Sleigh går att spela den 1 december.
+ Spelet Dasher Dancer går att spela den 1 december.
+ Stadsfrågor blir tillgängligt 1 december.
+ %1$s är inte tillgängligt just nu.
+ %1$s är inte tillgängligt än. Kom tillbaka senare!
+ Strömmad video
+ Vi låser upp videon den %1$d december.
+ Videon går inte att spela upp just nu.
+ Spela
+ Titta
+
diff --git a/playgames/src/main/res/values-ta/strings_gumball.xml b/playgames/src/main/res/values-ta/strings_gumball.xml
new file mode 100644
index 000000000..00e9059a8
--- /dev/null
+++ b/playgames/src/main/res/values-ta/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ கேமை இடைநிறுத்து
+ கேமை மீண்டும் தொடங்கு
+
diff --git a/playgames/src/main/res/values-ta/strings_memory.xml b/playgames/src/main/res/values-ta/strings_memory.xml
new file mode 100644
index 000000000..a5501c5d4
--- /dev/null
+++ b/playgames/src/main/res/values-ta/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ ஸ்கோர்
+ நிலை
+ மீண்டும் விளையாடுக
+ கேமை இடைநிறுத்து
+ கேமை மீண்டும் தொடங்கு
+
diff --git a/playgames/src/main/res/values-ta/strings_village.xml b/playgames/src/main/res/values-ta/strings_village.xml
new file mode 100644
index 000000000..70ea5a981
--- /dev/null
+++ b/playgames/src/main/res/values-ta/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ டிசம்பர் 24 ஆம் தேதி சான்டாவைப் பின்தொடரவும்.
+ டிசம்பர் 1 ஆம் தேதி முதல் பிரசென்ட் குவெஸ்ட் கேம் கிடைக்கும்.
+ சான்டா ஸ்னாப் விரைவில் கிடைக்கும்.
+ டிசம்பர் 1 ஆம் தேதி முதல் கம் பால் கேம் கிடைக்கும்.
+ டிசம்பர் 1 ஆம் தேதி முதல் மெமரி கேம் கிடைக்கும்.
+ டிசம்பர் 1 ஆம் தேதி முதல் ராக்கெட் ஸ்லெய் கேம் கிடைக்கும்.
+ டிசம்பர் 1 ஆம் தேதி முதல் டேஷர் டான்சர் கேம் கிடைக்கும்.
+ டிசம்பர் 1 ஆம் தேதி முதல் சிட்டி வினாடி வினா கேம் கிடைக்கும்.
+ %1$s தற்போது இல்லை.
+ %1$s தற்போது இல்லை. பிறகு பார்க்கவும்!
+ வீடியோ
+ டிசம்பர் %1$d ஆம் தேதி முதல் வீடியோவைப் பார்க்கலாம்.
+ வீடியோ தற்போது இல்லை.
+ விளையாடுக
+ பார்க்க
+
diff --git a/playgames/src/main/res/values-th/strings_gumball.xml b/playgames/src/main/res/values-th/strings_gumball.xml
new file mode 100644
index 000000000..ee9d41ada
--- /dev/null
+++ b/playgames/src/main/res/values-th/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ หยุดเกมชั่วคราว
+ กลับมาเล่นเกมต่อ
+
diff --git a/playgames/src/main/res/values-th/strings_memory.xml b/playgames/src/main/res/values-th/strings_memory.xml
new file mode 100644
index 000000000..d67150f30
--- /dev/null
+++ b/playgames/src/main/res/values-th/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ คะแนน
+ ระดับ
+ เล่นอีกครั้ง
+ หยุดเกมชั่วคราว
+ กลับมาเล่นเกมต่อ
+
diff --git a/playgames/src/main/res/values-th/strings_village.xml b/playgames/src/main/res/values-th/strings_village.xml
new file mode 100644
index 000000000..497ec65a7
--- /dev/null
+++ b/playgames/src/main/res/values-th/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ ติดตามซานต้าในวันที่ 24 ธันวาคม
+ Present Quest จะเปิดให้เล่นในวันที่ 1 ธันวาคม
+ ซานต้าเซลฟีจะพร้อมใช้งานในเร็วๆ นี้
+ Gumball จะมีให้เล่นในวันที่ 1 ธันวาคม
+ Memory จะมีให้เล่นในวันที่ 1 ธันวาคม
+ Rocket Sleigh จะมีให้เล่นในวันที่ 1 ธันวาคม
+ Dasher Dancer จะมีให้เล่นในวันที่ 1 ธันวาคม
+ เกม City Quiz จะเปิดให้เล่นในวันที่ 1 ธันวาคม
+ %1$s ยังไม่สามารถเล่นได้ในขณะนี้
+ %1$s ยังไม่พร้อมใช้งาน กลับมาดูใหม่ในภายหลัง
+ วิดีโอ
+ วิดีโอจะปลดล็อกในวันที่ %1$d ธันวาคม
+ ตอนนี้วิดีโอยังไม่สามารถดูได้
+ เล่น
+ ดู
+
diff --git a/playgames/src/main/res/values-tl/strings_gumball.xml b/playgames/src/main/res/values-tl/strings_gumball.xml
new file mode 100644
index 000000000..3ad5866b5
--- /dev/null
+++ b/playgames/src/main/res/values-tl/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ I-pause ang laro
+ Ipagpatuloy ang laro
+
diff --git a/playgames/src/main/res/values-tl/strings_memory.xml b/playgames/src/main/res/values-tl/strings_memory.xml
new file mode 100644
index 000000000..1f0922786
--- /dev/null
+++ b/playgames/src/main/res/values-tl/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ MARKA
+ LEVEL
+ MAGLARONG MULI
+ I-pause ang laro
+ Ipagpatuloy ang laro
+
diff --git a/playgames/src/main/res/values-tl/strings_village.xml b/playgames/src/main/res/values-tl/strings_village.xml
new file mode 100644
index 000000000..bd86105ca
--- /dev/null
+++ b/playgames/src/main/res/values-tl/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Sundan si Santa sa ika-24 ng Disyembre.
+ Magiging available sa ika-1 ng Disyembre ang Present Quest.
+ Malapit nang maging available ang Santa Snap.
+ Magiging available ang Gumball sa ika-1 ng Disyembre.
+ Magiging available ang Memory sa ika-1 ng Disyembre.
+ Magiging available ang Rocket Sleigh sa ika-1 ng Disyembre.
+ Magiging available ang Dasher Dancer sa ika-1 ng Disyembre.
+ Magiging available sa ika-1 ng Disyembre ang larong City Quiz.
+ Kasalukuyang hindi available ang %1$s.
+ Hindi pa available ang %1$s. Tingnang muli sa ibang pagkakataon!
+ Video
+ Maa-unlock ang video sa Disyembre %1$d.
+ Kasalukuyang hind available ang video.
+ I-play
+ Panoorin
+
diff --git a/playgames/src/main/res/values-uk/strings_gumball.xml b/playgames/src/main/res/values-uk/strings_gumball.xml
new file mode 100644
index 000000000..fb86d8c2c
--- /dev/null
+++ b/playgames/src/main/res/values-uk/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Призупинити гру
+ Відновити гру
+
diff --git a/playgames/src/main/res/values-uk/strings_memory.xml b/playgames/src/main/res/values-uk/strings_memory.xml
new file mode 100644
index 000000000..c9429f21d
--- /dev/null
+++ b/playgames/src/main/res/values-uk/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ РАХУНОК
+ РІВЕНЬ
+ ПОЧАТИ ЗАНОВО
+ Призупинити гру
+ Відновити гру
+
diff --git a/playgames/src/main/res/values-uk/strings_village.xml b/playgames/src/main/res/values-uk/strings_village.xml
new file mode 100644
index 000000000..59667cc17
--- /dev/null
+++ b/playgames/src/main/res/values-uk/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Стежте за Дідом Морозом 24 грудня.
+ Гра \"Знайди подарунок\" вийде 1 грудня.
+ Гра \"Фотоквест від Діда Мороза\" буде доступна незабаром.
+ Гра \"Жувальна гумка\" буде доступна з 1 грудня.
+ Гра \"Пам’ять\" буде доступна з 1 грудня.
+ Гра \"Реактивні санчата\" буде доступна з 1 грудня.
+ Гра \"Олені\" буде доступна з 1 грудня.
+ Гра \"Угадай місто\" вийде 1 грудня.
+ Гра \"%1$s\" ще не доступна.
+ Гра \"%1$s\" ще не доступна. Спробуйте пізніше.
+ Відео
+ Відео можна буде переглянути %1$d грудня.
+ Відео зараз недоступне.
+ Грати
+ Дивитися
+
diff --git a/playgames/src/main/res/values-vi/strings_gumball.xml b/playgames/src/main/res/values-vi/strings_gumball.xml
new file mode 100644
index 000000000..240aae2e8
--- /dev/null
+++ b/playgames/src/main/res/values-vi/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ Tạm dừng trò chơi
+ Tiếp tục trò chơi
+
diff --git a/playgames/src/main/res/values-vi/strings_memory.xml b/playgames/src/main/res/values-vi/strings_memory.xml
new file mode 100644
index 000000000..20ed18caa
--- /dev/null
+++ b/playgames/src/main/res/values-vi/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ ĐIỂM SỐ
+ CẤP
+ CHƠI LẠI
+ Tạm dừng trò chơi
+ Tiếp tục trò chơi
+
diff --git a/playgames/src/main/res/values-vi/strings_village.xml b/playgames/src/main/res/values-vi/strings_village.xml
new file mode 100644
index 000000000..b3f8b7ab8
--- /dev/null
+++ b/playgames/src/main/res/values-vi/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ Theo dõi ông già Noel vào ngày 24 tháng 12.
+ Săn tìm quà tặng sẽ có vào ngày 1 tháng 12.
+ Trò chơi Santa Snap sẽ sớm ra mắt.
+ Gumball sẽ có vào ngày 1 tháng 12.
+ Memory sẽ có vào ngày 1 tháng 12.
+ Rocket Sleigh sẽ có vào ngày 1 tháng 12.
+ Dasher Dancer sẽ có vào ngày 1 tháng 12.
+ Trò chơi Đoán tên thành phố sẽ có vào ngày 1 tháng 12.
+ %1$s hiện không có sẵn.
+ Chưa có %1$s. Hãy kiểm tra lại sau!
+ Video
+ Video sẽ được mở khóa vào ngày %1$d tháng 12.
+ Video hiện không có.
+ Chơi
+ Xem
+
diff --git a/playgames/src/main/res/values-xhdpi/dimens.xml b/playgames/src/main/res/values-xhdpi/dimens.xml
new file mode 100644
index 000000000..aa43e42cb
--- /dev/null
+++ b/playgames/src/main/res/values-xhdpi/dimens.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+ 95dp
+ 133dp
+ 25dp
+ 21dp
+ 20dp
+ 22dp
+ 25dp
+ 16sp
+ 200dp
+ 200dp
+ 60
+ 250dp
+ 36dp
+
diff --git a/playgames/src/main/res/values-zh-rCN/strings_gumball.xml b/playgames/src/main/res/values-zh-rCN/strings_gumball.xml
new file mode 100644
index 000000000..5aad8ae00
--- /dev/null
+++ b/playgames/src/main/res/values-zh-rCN/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ 暂停游戏
+ 继续游戏
+
diff --git a/playgames/src/main/res/values-zh-rCN/strings_memory.xml b/playgames/src/main/res/values-zh-rCN/strings_memory.xml
new file mode 100644
index 000000000..e24dbbfab
--- /dev/null
+++ b/playgames/src/main/res/values-zh-rCN/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ 得分
+ 关卡
+ 重玩
+ 暂停游戏
+ 继续游戏
+
diff --git a/playgames/src/main/res/values-zh-rCN/strings_village.xml b/playgames/src/main/res/values-zh-rCN/strings_village.xml
new file mode 100644
index 000000000..d4354b7ef
--- /dev/null
+++ b/playgames/src/main/res/values-zh-rCN/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ 等到 12 月 24 日就能追踪圣诞老人啦。
+ 《寻找礼物》将于 12 月 1 日推出。
+ 《圣诞老人快拍》很快就会推出。
+ 《掉落口香糖》将于 12 月 1 日推出。
+ 《翻牌配对》将于 12 月 1 日推出。
+ 《火箭雪橇》将于 12 月 1 日推出。
+ 《猛冲者跳舞》将于 12 月 1 日推出。
+ “城市知多少”游戏将于 12 月 1 日推出。
+ 目前无法玩“%1$s”。
+ 《%1$s》现在还不能玩。稍后再来看看吧!
+ 视频
+ 视频将于 12 月 %1$d 日解锁。
+ 暂时无法观看视频。
+ 开始玩
+ 观看
+
diff --git a/playgames/src/main/res/values-zh-rHK/strings_gumball.xml b/playgames/src/main/res/values-zh-rHK/strings_gumball.xml
new file mode 100644
index 000000000..2c976da76
--- /dev/null
+++ b/playgames/src/main/res/values-zh-rHK/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ 暫停遊戲
+ 繼續遊戲
+
diff --git a/playgames/src/main/res/values-zh-rHK/strings_memory.xml b/playgames/src/main/res/values-zh-rHK/strings_memory.xml
new file mode 100644
index 000000000..20fe82cc6
--- /dev/null
+++ b/playgames/src/main/res/values-zh-rHK/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ 得分
+ 關卡
+ 再玩一次
+ 暫停遊戲
+ 繼續遊戲
+
diff --git a/playgames/src/main/res/values-zh-rHK/strings_village.xml b/playgames/src/main/res/values-zh-rHK/strings_village.xml
new file mode 100644
index 000000000..3ea0cbbd0
--- /dev/null
+++ b/playgames/src/main/res/values-zh-rHK/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ 在 12 月 24 日追蹤聖誕老人。
+ 「禮物尋寶」遊戲將於 12 月 1 日推出。
+ 「聖誕老人快拍」即將推出
+ Gumball 即將在 12 月 1 日推出。
+ Memory 即將在 12 月 1 日推出。
+ 「火箭雪橇」即將在 12 月 1 日推出。
+ 「猛衝‧跳舞」即將在 12 月 1 日推出。
+ 「城市問答」遊戲將於 12 月 1 日推出。
+ 目前無法玩「%1$s」。
+ %1$s尚未推出,請稍後再回來查看!
+ 影片
+ 影片將於 12 月解鎖%1$d。
+ 影片目前無法提供。
+ 玩遊戲
+ 觀看
+
diff --git a/playgames/src/main/res/values-zh-rTW/strings_gumball.xml b/playgames/src/main/res/values-zh-rTW/strings_gumball.xml
new file mode 100644
index 000000000..2c976da76
--- /dev/null
+++ b/playgames/src/main/res/values-zh-rTW/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ 暫停遊戲
+ 繼續遊戲
+
diff --git a/playgames/src/main/res/values-zh-rTW/strings_memory.xml b/playgames/src/main/res/values-zh-rTW/strings_memory.xml
new file mode 100644
index 000000000..314985992
--- /dev/null
+++ b/playgames/src/main/res/values-zh-rTW/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ 分數
+ 關卡
+ 再玩一次
+ 暫停遊戲
+ 繼續遊戲
+
diff --git a/playgames/src/main/res/values-zh-rTW/strings_village.xml b/playgames/src/main/res/values-zh-rTW/strings_village.xml
new file mode 100644
index 000000000..5b3492822
--- /dev/null
+++ b/playgames/src/main/res/values-zh-rTW/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ 在 12 月 24 日當天追蹤聖誕老人。
+ 「禮物尋寶」遊戲將於 12 月 1 日推出。
+ 即將推出「聖誕老公公快照」遊戲。
+ 「口香糖球」遊戲將於 12 月 1 日推出。
+ 「翻牌配對」遊戲將於 12 月 1 日推出。
+ 「火箭雪橇」將於 12 月 1 日推出。
+ 「馴鹿快跑」將於 12 月 1 日推出。
+ 「城市猜謎」遊戲將於 12 月 1 日推出。
+ 目前無法玩「%1$s」。
+ 「%1$s」尚未推出,晚一點再回來看看吧!
+ 影片
+ 影片將於 12 月 %1$d開放觀賞。
+ 目前無法觀看影片。
+ 玩遊戲
+ 觀看
+
diff --git a/playgames/src/main/res/values-zh/strings_gumball.xml b/playgames/src/main/res/values-zh/strings_gumball.xml
new file mode 100644
index 000000000..5aad8ae00
--- /dev/null
+++ b/playgames/src/main/res/values-zh/strings_gumball.xml
@@ -0,0 +1,20 @@
+
+
+
+ 暂停游戏
+ 继续游戏
+
diff --git a/playgames/src/main/res/values-zh/strings_memory.xml b/playgames/src/main/res/values-zh/strings_memory.xml
new file mode 100644
index 000000000..e24dbbfab
--- /dev/null
+++ b/playgames/src/main/res/values-zh/strings_memory.xml
@@ -0,0 +1,23 @@
+
+
+
+ 得分
+ 关卡
+ 重玩
+ 暂停游戏
+ 继续游戏
+
diff --git a/playgames/src/main/res/values-zh/strings_village.xml b/playgames/src/main/res/values-zh/strings_village.xml
new file mode 100644
index 000000000..d4354b7ef
--- /dev/null
+++ b/playgames/src/main/res/values-zh/strings_village.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ 等到 12 月 24 日就能追踪圣诞老人啦。
+ 《寻找礼物》将于 12 月 1 日推出。
+ 《圣诞老人快拍》很快就会推出。
+ 《掉落口香糖》将于 12 月 1 日推出。
+ 《翻牌配对》将于 12 月 1 日推出。
+ 《火箭雪橇》将于 12 月 1 日推出。
+ 《猛冲者跳舞》将于 12 月 1 日推出。
+ “城市知多少”游戏将于 12 月 1 日推出。
+ 目前无法玩“%1$s”。
+ 《%1$s》现在还不能玩。稍后再来看看吧!
+ 视频
+ 视频将于 12 月 %1$d 日解锁。
+ 暂时无法观看视频。
+ 开始玩
+ 观看
+
diff --git a/playgames/src/main/res/values/attrs.xml b/playgames/src/main/res/values/attrs.xml
new file mode 100644
index 000000000..6a7ca0e97
--- /dev/null
+++ b/playgames/src/main/res/values/attrs.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/values/colors.xml b/playgames/src/main/res/values/colors.xml
new file mode 100644
index 000000000..0ac0e66b5
--- /dev/null
+++ b/playgames/src/main/res/values/colors.xml
@@ -0,0 +1,53 @@
+
+
+
+
+ #ddf3f3f3
+ #99000000
+ #ff9c9c9c
+ #283593
+
+ #ffff5255
+ #ffba0004
+ #FFFFFF
+ #9affb4
+ #d7fbff
+
+ #64DDF6
+ #08397E
+
+ #51CFE4
+ #08397E
+
+ #51cfe4
+ #CA222B
+ #6E97AE
+
+ #EBB06CE0
+ #EB44D4D7
+ #EBE9C75B
+ #EB24DA76
+ #EBED6B61
+
+ #3DDAF2
+ #A2EDF9
+
+ #00cc81
+ #64006842
+ #45DDBD
+ #cd00c3ea
+
diff --git a/playgames/src/main/res/values/common.xml b/playgames/src/main/res/values/common.xml
new file mode 100644
index 000000000..9ffedbd61
--- /dev/null
+++ b/playgames/src/main/res/values/common.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ 25
+ 30
+ 1
+ 25
+
+ 1024
+ 115
+ 120
+ 5
+ 0
+ 512
+
diff --git a/playgames/src/main/res/values/common_wear.xml b/playgames/src/main/res/values/common_wear.xml
new file mode 100644
index 000000000..84c0db37d
--- /dev/null
+++ b/playgames/src/main/res/values/common_wear.xml
@@ -0,0 +1,33 @@
+
+
+
+
+ 120
+
+ @integer/planePercentagePerSecond
+ @integer/ufoPercentagePerSecond
+ @integer/cloudPercentagePerSecond
+ @integer/cloudSpeedJitterPercent
+
+ @integer/referenceHeight
+ @integer/ufoVerticalOffset
+ @integer/planeVerticalOffset
+ @integer/numClouds
+ @integer/skyStart
+ @integer/cloudsEnd
+
+
diff --git a/playgames/src/main/res/values/config-build.xml b/playgames/src/main/res/values/config-build.xml
new file mode 100644
index 000000000..1cb520c73
--- /dev/null
+++ b/playgames/src/main/res/values/config-build.xml
@@ -0,0 +1,31 @@
+
+
+
+ android
+
+
+ XXXXX
+
+
+ https://santa-api.appspot.com/info?client=%1$s\u0026rand=%2$f\u0026routeOffset=%3$d\u0026streamOffset=%4$d\u0026tz=%5$d\u0026language=%6$s\u0026fingerprint=%7$s
+
+
+ https://santa-playability-api.appspot.com/api
+
+
+ XXXXX
+
diff --git a/playgames/src/main/res/values/config.xml b/playgames/src/main/res/values/config.xml
new file mode 100644
index 000000000..d72a84243
--- /dev/null
+++ b/playgames/src/main/res/values/config.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ 30000
+
+ 300000
+
+ 150
+
+
+ google.streetview:panoid=%s&cbp=0,%f
+
+
+
+ http/google.com/santatracker/android
+
+ gumball
+ jetpack
+ memory
+ cityquiz
+
+
diff --git a/playgames/src/main/res/values/dimens.xml b/playgames/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..523d4ed97
--- /dev/null
+++ b/playgames/src/main/res/values/dimens.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+ - 1.0
+ 100dp
+ 30dp
+ -60dp
+
+
+ 82dp
+ 120dp
+ 25dp
+ 19dp
+ 20dp
+ 22dp
+ 2dp
+
+
+
+
+
+
+
+ 10dp
+
+
+
+ 46dp
+
+ 8dp
+ 8dp
+ 4dp
+ 0dp
+ 0dp
+
+ 48dp
+ 27dp
+ 12dp
+
+ 75dp
+ 20dp
+
+ 16dp
+ 16dp
+ -43dp
+ 48sp
+
diff --git a/playgames/src/main/res/values/donottranslate.xml b/playgames/src/main/res/values/donottranslate.xml
new file mode 100644
index 000000000..df69aacd7
--- /dev/null
+++ b/playgames/src/main/res/values/donottranslate.xml
@@ -0,0 +1,19 @@
+
+
+
+ -
+
diff --git a/playgames/src/main/res/values/game_colors.xml b/playgames/src/main/res/values/game_colors.xml
new file mode 100644
index 000000000..e9b2ae86d
--- /dev/null
+++ b/playgames/src/main/res/values/game_colors.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+ #B2E3F9
+ #885931
+ #ffcc0000
+ #CCB2E3F9
+ #CC0A712E
+
+
diff --git a/playgames/src/main/res/values/game_ids.xml b/playgames/src/main/res/values/game_ids.xml
new file mode 100644
index 000000000..7b545187a
--- /dev/null
+++ b/playgames/src/main/res/values/game_ids.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ 80719462666
+ CgkIioKF2qwCEAIQEw
+ CgkIioKF2qwCEAIQFA
+
diff --git a/playgames/src/main/res/values/snowflake.xml b/playgames/src/main/res/values/snowflake.xml
new file mode 100644
index 000000000..61faccd0d
--- /dev/null
+++ b/playgames/src/main/res/values/snowflake.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ 100
+ 0.01
+
diff --git a/playgames/src/main/res/values/strings.xml b/playgames/src/main/res/values/strings.xml
new file mode 100644
index 000000000..781def617
--- /dev/null
+++ b/playgames/src/main/res/values/strings.xml
@@ -0,0 +1,18 @@
+
+ 1:00
+ %1$d
+
diff --git a/playgames/src/main/res/values/strings_cast.xml b/playgames/src/main/res/values/strings_cast.xml
new file mode 100644
index 000000000..d45ee44eb
--- /dev/null
+++ b/playgames/src/main/res/values/strings_cast.xml
@@ -0,0 +1,15 @@
+
diff --git a/playgames/src/main/res/values/strings_cast_mrp_errors.xml b/playgames/src/main/res/values/strings_cast_mrp_errors.xml
new file mode 100644
index 000000000..de2beec8d
--- /dev/null
+++ b/playgames/src/main/res/values/strings_cast_mrp_errors.xml
@@ -0,0 +1,16 @@
+
+
diff --git a/playgames/src/main/res/values/strings_city_quiz.xml b/playgames/src/main/res/values/strings_city_quiz.xml
new file mode 100644
index 000000000..de2beec8d
--- /dev/null
+++ b/playgames/src/main/res/values/strings_city_quiz.xml
@@ -0,0 +1,16 @@
+
+
diff --git a/playgames/src/main/res/values/strings_gumball.xml b/playgames/src/main/res/values/strings_gumball.xml
new file mode 100644
index 000000000..d295bbd6c
--- /dev/null
+++ b/playgames/src/main/res/values/strings_gumball.xml
@@ -0,0 +1,18 @@
+
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values/strings_jetpack.xml b/playgames/src/main/res/values/strings_jetpack.xml
new file mode 100644
index 000000000..de2beec8d
--- /dev/null
+++ b/playgames/src/main/res/values/strings_jetpack.xml
@@ -0,0 +1,16 @@
+
+
diff --git a/playgames/src/main/res/values/strings_memory.xml b/playgames/src/main/res/values/strings_memory.xml
new file mode 100644
index 000000000..2312074cd
--- /dev/null
+++ b/playgames/src/main/res/values/strings_memory.xml
@@ -0,0 +1,21 @@
+
+ SCORE
+ LEVEL
+ PLAY AGAIN
+ Pause game
+ Resume game
+
diff --git a/playgames/src/main/res/values/strings_snowglobe.xml b/playgames/src/main/res/values/strings_snowglobe.xml
new file mode 100644
index 000000000..d45ee44eb
--- /dev/null
+++ b/playgames/src/main/res/values/strings_snowglobe.xml
@@ -0,0 +1,15 @@
+
diff --git a/playgames/src/main/res/values/strings_village.xml b/playgames/src/main/res/values/strings_village.xml
new file mode 100644
index 000000000..1c24ebb67
--- /dev/null
+++ b/playgames/src/main/res/values/strings_village.xml
@@ -0,0 +1,32 @@
+
+
+ Follow Santa on December 24th.
+ Present Quest will be available on December 1st.
+ Santa Snap will be available soon.
+ Gumball will be available on December 1st.
+ Memory will be available on December 1st.
+ Rocket Sleigh will be available on December 1st.
+ Dasher Dancer will be available on December 1st.
+ City Quiz game will be available on December 1st.
+ %1$s is currently unavailable.
+ %1$s is not yet available. Check back later!
+ Video
+ Video will be unlocked on December %1$d.
+ Video is currently unavailable.
+ Play
+ Watch
+
diff --git a/playgames/src/main/res/values/styles.xml b/playgames/src/main/res/values/styles.xml
new file mode 100644
index 000000000..8acdf5ec4
--- /dev/null
+++ b/playgames/src/main/res/values/styles.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/values/values-map.xml b/playgames/src/main/res/values/values-map.xml
new file mode 100644
index 000000000..0bf737a25
--- /dev/null
+++ b/playgames/src/main/res/values/values-map.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/playgames/src/main/res/values/values_cast_controller.xml b/playgames/src/main/res/values/values_cast_controller.xml
new file mode 100644
index 000000000..0bdd2437c
--- /dev/null
+++ b/playgames/src/main/res/values/values_cast_controller.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/values/village_badges.xml b/playgames/src/main/res/values/village_badges.xml
new file mode 100644
index 000000000..aed7b0ae4
--- /dev/null
+++ b/playgames/src/main/res/values/village_badges.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
diff --git a/playgames/src/main/res/values/village_markers.xml b/playgames/src/main/res/values/village_markers.xml
new file mode 100644
index 000000000..7ea25d3f4
--- /dev/null
+++ b/playgames/src/main/res/values/village_markers.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/common/.gitignore b/presentquest/.gitignore
similarity index 100%
rename from common/.gitignore
rename to presentquest/.gitignore
diff --git a/presentquest/build.gradle b/presentquest/build.gradle
new file mode 100644
index 000000000..0d9451774
--- /dev/null
+++ b/presentquest/build.gradle
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019. Google LLC
+ *
+ * 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
+ *
+ * https://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.
+ */
+
+apply plugin: 'com.android.dynamic-feature'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.tools
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+
+ javaCompileOptions {
+ annotationProcessorOptions {
+ arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
+ }
+ }
+ }
+}
+
+dependencies {
+ implementation project(':santa-tracker')
+
+ implementation rootProject.ext.playServicesMaps
+ implementation rootProject.ext.playServicesLocation
+ implementation rootProject.ext.playServicesPlaces
+
+ // In this project, Kotlin is only used for compiling and testing
+ annotationProcessor rootProject.ext.kotlinRuntime
+ testImplementation rootProject.ext.kotlinRuntime
+
+ // Architecture Components
+ annotationProcessor rootProject.ext.archLifecycleCompiler
+ annotationProcessor rootProject.ext.archRoomCompiler
+ testImplementation rootProject.ext.archRoomTesting
+
+ implementation rootProject.ext.easypermissions
+}
diff --git a/presentquest/schemas/com.google.android.apps.santatracker.presentquest.db.PQDatabase/1.json b/presentquest/schemas/com.google.android.apps.santatracker.presentquest.db.PQDatabase/1.json
new file mode 100644
index 000000000..63554ab20
--- /dev/null
+++ b/presentquest/schemas/com.google.android.apps.santatracker.presentquest.db.PQDatabase/1.json
@@ -0,0 +1,181 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 1,
+ "identityHash": "65896311b96f76ced28d61ba9eacc6b5",
+ "entities": [
+ {
+ "tableName": "User",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `presentsCollected` INTEGER NOT NULL, `presentsReturned` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentsCollected",
+ "columnName": "presentsCollected",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentsReturned",
+ "columnName": "presentsReturned",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Present",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `lat` TEXT, `lng` TEXT, `updated` INTEGER NOT NULL, `isLarge` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lat",
+ "columnName": "lat",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lng",
+ "columnName": "lng",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updated",
+ "columnName": "updated",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isLarge",
+ "columnName": "isLarge",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Place",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `used` INTEGER NOT NULL, `lat` TEXT, `lng` TEXT, `updated` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "used",
+ "columnName": "used",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lat",
+ "columnName": "lat",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lng",
+ "columnName": "lng",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updated",
+ "columnName": "updated",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Place_lat_lng",
+ "unique": true,
+ "columnNames": [
+ "lat",
+ "lng"
+ ],
+ "createSql": "CREATE UNIQUE INDEX `index_Place_lat_lng` ON `${TABLE_NAME}` (`lat`, `lng`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Workshop",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `lat` TEXT, `lng` TEXT, `updated` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lat",
+ "columnName": "lat",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lng",
+ "columnName": "lng",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updated",
+ "columnName": "updated",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"65896311b96f76ced28d61ba9eacc6b5\")"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/presentquest/src/dogfood/res/values/config.xml b/presentquest/src/dogfood/res/values/config.xml
new file mode 100644
index 000000000..3be9ecf35
--- /dev/null
+++ b/presentquest/src/dogfood/res/values/config.xml
@@ -0,0 +1,19 @@
+
+
+
+ https://santa-playability-api.appspot.com/api
+
diff --git a/presentquest/src/main/AndroidManifest.xml b/presentquest/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..0a0901a2e
--- /dev/null
+++ b/presentquest/src/main/AndroidManifest.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/PlacesIntentService.java b/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/PlacesIntentService.java
new file mode 100644
index 000000000..d491a7ec2
--- /dev/null
+++ b/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/PlacesIntentService.java
@@ -0,0 +1,478 @@
+/*
+ * 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.presentquest;
+
+import android.app.IntentService;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.WorkerThread;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import com.google.android.apps.santatracker.presentquest.repository.PQRepository;
+import com.google.android.apps.santatracker.presentquest.util.Config;
+import com.google.android.apps.santatracker.presentquest.util.Distance;
+import com.google.android.apps.santatracker.presentquest.util.PreferencesUtil;
+import com.google.android.apps.santatracker.presentquest.vo.Place;
+import com.google.android.apps.santatracker.presentquest.vo.Present;
+import com.google.android.apps.santatracker.util.SantaLog;
+import com.google.android.gms.maps.model.LatLng;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.security.MessageDigest;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.net.ssl.HttpsURLConnection;
+
+public class PlacesIntentService extends IntentService {
+
+ private static final String TAG = "PQ(PlacesService)";
+ private static final String ACTION_SEARCH_NEARBY = "ACTION_SEARCH_NEARBY";
+
+ private static final String EXTRA_LAT_LNG = "extra_lat_lng";
+ private static final String EXTRA_RADIUS = "extra_radius";
+ private static final String EXTRA_PLACE_RESULT = "extra_place_result";
+ private static final int MAX_QUERIES_IN_PROGRESS = 1;
+
+ private AtomicInteger mQueriesInProgress = new AtomicInteger(0);
+
+ private String mAppSignature;
+
+ // Shared Prefs
+ private PreferencesUtil mPreferences;
+
+ // Firebase Config
+ private Config mConfig;
+
+ // Repository
+ PQRepository repository;
+
+ public PlacesIntentService() {
+ super(TAG);
+ }
+
+ @NonNull
+ public static IntentFilter getNearbySearchIntentFilter() {
+ return new IntentFilter(ACTION_SEARCH_NEARBY);
+ }
+
+ public static void startNearbySearch(Context context, LatLng center, int radius) {
+ SantaLog.d(TAG, "startNearbySearch: radius=" + radius);
+ Intent intent = new Intent(context, PlacesIntentService.class);
+ intent.setAction(ACTION_SEARCH_NEARBY);
+ intent.putExtra(EXTRA_LAT_LNG, center);
+ intent.putExtra(EXTRA_RADIUS, radius);
+ context.startService(intent);
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+
+ // TODO inject this
+ repository = PQRepository.getInstance(this);
+ if (intent != null) {
+ final String action = intent.getAction();
+ switch (action) {
+ case ACTION_SEARCH_NEARBY:
+ // Don't allow more than X queries at once.
+ if (mQueriesInProgress.get() >= MAX_QUERIES_IN_PROGRESS) {
+ SantaLog.d(TAG, "Dropping excess query");
+ return;
+ }
+
+ // Mark query started
+ mQueriesInProgress.incrementAndGet();
+
+ if (mPreferences == null) {
+ mPreferences = new PreferencesUtil(this);
+ }
+ if (mConfig == null) {
+ mConfig = new Config();
+ }
+
+ // Perform query
+ final LatLng center = intent.getParcelableExtra(EXTRA_LAT_LNG);
+ final int radius = intent.getIntExtra(EXTRA_RADIUS, 0);
+ getPlaceAndBroadcast(center, radius);
+
+ // Mark query finished
+ mQueriesInProgress.decrementAndGet();
+ break;
+ default:
+ SantaLog.w(TAG, "Unknown action: " + action);
+ }
+ }
+ }
+
+ @WorkerThread
+ private void getPlaceAndBroadcast(LatLng center, int radius) {
+
+ long now = System.currentTimeMillis();
+ boolean useCache = now - mPreferences.getLastPlacesApiRequest() < mConfig.CACHE_REFRESH_MS;
+
+ // Try and retrieve place from DB cache if CACHE_REFRESH_MS has not elapsed
+ // since last API request.
+ Place place = null;
+ if (useCache) {
+ place = getCachedPlace(center, radius);
+ }
+
+ // If CACHE_REFRESH_MS has elapsed, or no nearby places in cache, fetch from API and
+ // cache the results, then return one of them. Guaranteed to have results since we
+ // back-fill with random locations if too few returned from Places API.
+ if (place == null) {
+ // Set the last API request time with a +/- 30 sec jitter.
+ int jitter = ((new Random()).nextInt(60) - 30) * 1000;
+ mPreferences.setLastPlacesApiRequest(now + jitter);
+ SantaLog.d(
+ TAG,
+ "getPlaceAndBroadcast: " + (useCache ? "cache miss" : "cache refresh elapsed"));
+ place = fetchPlacesAndGetCached(center, radius);
+ } else {
+ SantaLog.d(TAG, "getPlaceAndBroadcast: cache hit");
+ }
+
+ // If the place is STILL null, just bail
+ if (place == null) {
+ SantaLog.w(TAG, "getPlaceAndBroadcast: total cache failure");
+ return;
+ }
+
+ // Log some stats about the place picked
+ int distance = Distance.between(center, place.getLatLng());
+ SantaLog.d(TAG, "getPlaceAndBroadcast: distance=" + distance + ", used=" + place.used);
+
+ // Create result intent and broadcast the result.
+ Intent intent = new Intent();
+ intent.setAction(ACTION_SEARCH_NEARBY);
+ intent.putExtra(EXTRA_PLACE_RESULT, place.getLatLng());
+
+ boolean received = LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
+ SantaLog.d(TAG, "getPlaceAndBroadcast: received=" + received);
+ if (received) {
+ // Increments usage counter.
+ repository.usePlace(place);
+ }
+ }
+
+ /**
+ * Compares cached places by their distance from the requesting center, weighing their distance
+ * by the number of times the place has been used.
+ */
+ private static class PlaceComparator implements Comparator {
+
+ LatLng center;
+ int radius;
+ double usedPlaceRadiusWeight;
+
+ PlaceComparator(LatLng center, int radius, double usedPlaceRadiusWeight) {
+ this.center = center;
+ this.radius = radius;
+ this.usedPlaceRadiusWeight = usedPlaceRadiusWeight;
+ }
+
+ private int weightedDistanceTo(Place place) {
+ return Distance.between(center, place.getLatLng())
+ + (int) (place.used * radius * usedPlaceRadiusWeight);
+ }
+
+ @Override
+ public int compare(Place a, Place b) {
+ return weightedDistanceTo(a) - weightedDistanceTo(b);
+ }
+ }
+
+ // TODO move to repository
+ @Nullable
+ private Place getCachedPlace(LatLng center, int radius) {
+
+ // Build a set of present locations we can use to check that we
+ // don't choose a place that already exists as a present.
+ Set presents = new HashSet<>();
+ for (Present present : repository.getAllPresents()) {
+ presents.add(present.getLatLng());
+ }
+
+ // Sort all places by distance, and filter down to the top X in correct proximity.
+ // We'll then choose one of these randomly as the result.
+ List allPlaces = repository.getAllPlaces();
+ Collections.sort(
+ allPlaces, new PlaceComparator(center, radius, mConfig.USED_PLACE_RADIUS_WEIGHT));
+ List potentialPlaces = new ArrayList<>();
+ for (Place place : allPlaces) {
+ int distance = Distance.between(center, place.getLatLng());
+ boolean closeEnough = distance <= radius;
+ boolean farEnough = distance > mConfig.REACHABLE_RADIUS_METERS;
+ if (closeEnough && farEnough && !presents.contains(place.getLatLng())) {
+ potentialPlaces.add(place);
+ if (potentialPlaces.size() >= mConfig.MAX_CACHE_RANDOM_SAMPLE_SIZE) {
+ break;
+ }
+ }
+ }
+
+ // Choose a random place from the possible results, or null for a cache miss.
+ if (!potentialPlaces.isEmpty()) {
+ return potentialPlaces.get(new Random().nextInt(potentialPlaces.size()));
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Fetches places from the Places API, back-filling with random locations if too few returned,
+ * and caches them all for future use.
+ *
+ * @param center
+ * @param radius
+ * @return
+ */
+ private Place fetchPlacesAndGetCached(LatLng center, int radius) {
+ // Before we start, mark if this is the first run
+ boolean firstRun = repository.getPlaceCount() == 0; // Place.count(Place.class)
+
+ // Make places API request using double the radius, to have cached items while travelling.
+ ArrayList places = fetchPlacesFromAPI(center, radius * 2);
+
+ // TODO need to figure this one out
+ // could make the id a combination of lat long...
+ // these could each be executed in separate statements ... which would be terrible
+
+ // TODO This should probably happen automatically, along with the places being loaded in
+ // the repository
+ repository.cachePlaces(places, mConfig, center, radius);
+
+ // If it's the first run, try to return a particularly well-suited place
+ if (firstRun) {
+ Place firstRunPlace = getCachedFirstPlace(center);
+ if (firstRunPlace != null) {
+ return firstRunPlace;
+ }
+ }
+
+ // Now that the cache is populated, use the logic to get a cached place and return it
+ return getCachedPlace(center, radius);
+ }
+
+ // TODO move to repository
+ /** Get a place from the cache that's particularly suited for the first drop. */
+ @Nullable
+ private Place getCachedFirstPlace(LatLng center) {
+ // Try to find one in the cache
+ List places = repository.getAllPlaces();
+ for (Place place : places) {
+ if (isValidFirstPlace(center, place.getLatLng())) {
+ SantaLog.d(TAG, "getCachedFirstPlace: cache hit");
+ return place;
+ }
+ }
+
+ // If that didn't work, try to randomly generate one, we will search within
+ // 1.5x the radius we want so that we have a better chance of a random hit.
+ int maxSearchRadius =
+ (int) (1.5 * mConfig.FIRST_PLACE_RADIUS_WEIGHT * mConfig.REACHABLE_RADIUS_METERS);
+ int maxRandomTries = 100;
+ for (int i = 0; i < maxRandomTries; i++) {
+ LatLng latLng = PQRepository.randomLatLng(center, maxSearchRadius);
+ if (isValidFirstPlace(center, latLng)) {
+ SantaLog.d(TAG, "getCachedFirstPlace: got random, attempt " + i);
+ SantaLog.d(
+ TAG,
+ "getCachedFirstPlace: distance is " + Distance.between(center, latLng));
+
+ // Save place and return
+ Place place = new Place(latLng);
+ repository.savePlace(place);
+
+ return place;
+ }
+ }
+
+ // We got really, really unlucky
+ SantaLog.d(TAG, "getCachedFirstPlace: no hits");
+ return null;
+ }
+
+ private boolean isValidFirstPlace(LatLng center, LatLng placeLatLng) {
+ int distance = Distance.between(center, placeLatLng);
+ int minDistance = mConfig.REACHABLE_RADIUS_METERS;
+ int maxDistance =
+ (int) (mConfig.REACHABLE_RADIUS_METERS * mConfig.FIRST_PLACE_RADIUS_WEIGHT);
+ return distance > minDistance && distance < maxDistance;
+ }
+
+ private ArrayList fetchPlacesFromAPI(LatLng center, int radius) {
+ ArrayList places = new ArrayList<>();
+ radius = Math.min(radius, 50000); // Max accepted radius is 50km.
+ // For privacy, round latlng to 2 decimal places
+ double roundFactor = 10000;
+ double lat = Math.round(center.latitude * roundFactor) / roundFactor;
+ double lng = Math.round(center.longitude * roundFactor) / roundFactor;
+
+ try {
+ InputStream is = null;
+ URL url =
+ new URL(
+ getString(R.string.places_api_url)
+ + "?location="
+ + lat
+ + ","
+ + lng
+ + "&radius="
+ + radius);
+ SantaLog.d(TAG, "fetchPlacesFromAPI for " + center + ": " + url);
+
+ HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
+ conn.setReadTimeout(10000);
+ conn.setConnectTimeout(15000);
+ conn.setRequestMethod("GET");
+ conn.setDoInput(true);
+
+ // Pass package name and signature as part of request
+ String packageName = getPackageName();
+ String signature = getAppSignature();
+
+ conn.setRequestProperty("X-App-Package", packageName);
+ conn.setRequestProperty("X-App-Signature", signature);
+
+ conn.connect();
+ int response = conn.getResponseCode();
+ if (response != 200) {
+ SantaLog.e(TAG, "Places API HTTP error: " + response + " / " + url);
+ } else {
+ BufferedReader reader;
+ StringBuilder builder = new StringBuilder();
+ reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
+ for (String line; (line = reader.readLine()) != null; ) {
+ builder.append(line);
+ }
+ JSONArray resultsJson =
+ (new JSONObject(builder.toString())).getJSONArray("results");
+ for (int i = 0; i < resultsJson.length(); i++) {
+ JSONObject latLngJson =
+ ((JSONObject) resultsJson.get(i))
+ .getJSONObject("geometry")
+ .getJSONObject("location");
+ places.add(
+ new LatLng(latLngJson.getDouble("lat"), latLngJson.getDouble("lng")));
+ }
+ }
+ } catch (Exception e) {
+ SantaLog.e(TAG, "Exception parsing places API: " + e.toString());
+ }
+
+ return places;
+ }
+
+ @Nullable
+ private String getAppSignature() {
+ // Cache this so we don't need to calculate the signature on every request
+ if (mAppSignature != null) {
+ return mAppSignature;
+ }
+
+ try {
+ // Get signatures for the package
+ Signature[] sigs =
+ getPackageManager()
+ .getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES)
+ .signatures;
+
+ // There should only be one signature, anything else is suspicious
+ if (sigs == null || sigs.length > 1 || sigs.length == 0) {
+ SantaLog.w(TAG, "Either 0 or >1 signatures, returning null");
+ return null;
+ }
+
+ byte[] certBytes = sigs[0].toByteArray();
+
+ InputStream input = new ByteArrayInputStream(certBytes);
+ CertificateFactory cf = CertificateFactory.getInstance("X509");
+ X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
+
+ MessageDigest md = MessageDigest.getInstance("SHA1");
+ byte[] publicKey = md.digest(cert.getEncoded());
+
+ // Build a hex string of the SHA1 Digest
+ StringBuilder hexString = new StringBuilder();
+ for (byte aPublicKey : publicKey) {
+ // Convert each byte to hex
+ String appendString = Integer.toHexString(0xFF & aPublicKey);
+ if (appendString.length() == 1) {
+ hexString.append("0");
+ }
+
+ // Convert to upper case and add ":" separators so it matches keytool output
+ appendString = appendString.toUpperCase() + ":";
+
+ hexString.append(appendString);
+ }
+
+ // Convert to string, chop off trailing colon
+ String signature = hexString.toString();
+ if (signature.endsWith(":")) {
+ signature = signature.substring(0, signature.length() - 1);
+ }
+
+ // Set and return
+ mAppSignature = signature;
+ return mAppSignature;
+ } catch (Exception e) {
+ SantaLog.e(TAG, "getSignature", e);
+ }
+
+ return null;
+ }
+
+ /** BroadcastReceiver to get result of nearby search. */
+ public abstract static class NearbyResultReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ LatLng place = intent.getParcelableExtra(EXTRA_PLACE_RESULT);
+ onResult(place);
+ }
+
+ /**
+ * Called when a new result is returned.
+ *
+ * @param place resulting {@link LatLng}.
+ */
+ public abstract void onResult(LatLng place);
+ }
+}
diff --git a/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/db/PQDatabase.java b/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/db/PQDatabase.java
new file mode 100644
index 000000000..417c0fb57
--- /dev/null
+++ b/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/db/PQDatabase.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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.presentquest.db;
+
+import android.content.Context;
+
+import androidx.room.Database;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+
+import com.google.android.apps.santatracker.presentquest.vo.Place;
+import com.google.android.apps.santatracker.presentquest.vo.Present;
+import com.google.android.apps.santatracker.presentquest.vo.User;
+import com.google.android.apps.santatracker.presentquest.vo.Workshop;
+import com.google.android.apps.santatracker.util.SantaLog;
+
+@Database(
+ entities = {User.class, Present.class, Place.class, Workshop.class},
+ version = 1)
+public abstract class PQDatabase extends RoomDatabase {
+ private static final String LOG_TAG = PQDatabase.class.getSimpleName();
+ public static final String DATABASE_NAME = "present-quest";
+
+ public abstract UserDao userDao();
+
+ public abstract PresentDao presentDao();
+
+ public abstract PlaceDao placeDao();
+
+ public abstract WorkshopDao workshopDao();
+
+ // For Singleton instantiation
+ private static final Object LOCK = new Object();
+ private static PQDatabase database;
+
+ public static PQDatabase getInstance(Context context) {
+ SantaLog.d(LOG_TAG, "Getting the database");
+ if (database == null) {
+ synchronized (LOCK) {
+ database =
+ Room.databaseBuilder(
+ context.getApplicationContext(),
+ PQDatabase.class,
+ PQDatabase.DATABASE_NAME)
+ .allowMainThreadQueries()
+ .build();
+ // TODO switch off main thread
+ SantaLog.d(LOG_TAG, "Made new database");
+ }
+ }
+ return database;
+ }
+}
diff --git a/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/db/PlaceDao.java b/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/db/PlaceDao.java
new file mode 100644
index 000000000..18522a839
--- /dev/null
+++ b/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/db/PlaceDao.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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.presentquest.db;
+
+import androidx.room.Dao;
+import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
+import androidx.room.Query;
+import androidx.room.Update;
+
+import com.google.android.apps.santatracker.presentquest.vo.Place;
+
+import java.util.List;
+
+@Dao
+public interface PlaceDao {
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
+ void insertPlace(Place place);
+
+ @Update
+ int updatePlace(Place place);
+
+ @Query("DELETE FROM place")
+ void deleteAll();
+
+ @Query("SELECT * FROM place")
+ List getAll();
+
+ @Query("SELECT COUNT(*) FROM place")
+ int count();
+
+ @Query("SELECT * FROM place WHERE lat = :latitude AND lng = :longitude")
+ Place getByLatLong(double latitude, double longitude);
+
+ @Query(
+ "DELETE FROM place WHERE id IN (SELECT id FROM place ORDER BY id ASC LIMIT :numberToCull)")
+ void deleteOldestById(int numberToCull);
+}
diff --git a/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/db/PresentDao.java b/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/db/PresentDao.java
new file mode 100644
index 000000000..7e64f7284
--- /dev/null
+++ b/presentquest/src/main/java/com/google/android/apps/santatracker/presentquest/db/PresentDao.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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.presentquest.db;
+
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
+import androidx.room.Query;
+import androidx.room.Update;
+
+import com.google.android.apps.santatracker.presentquest.vo.Present;
+
+import java.util.List;
+
+@Dao
+public interface PresentDao {
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
+ void insertPresent(Present present);
+
+ @Query("DELETE FROM present")
+ void deleteAll();
+
+ @Query("SELECT * FROM present")
+ List