From f8895248e2ac4dbb46622f3e04c7256f03175b4f Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Mon, 30 Sep 2013 16:16:24 -0700 Subject: [PATCH] Add a scrubber to keyguard; layout tweaks Switch KeyguardTransportControlView over to using RemoteController instead of the internal API. Guard transition animations behind a flag until we can work out some intermittent issues. Change-Id: Ie9f41339ce6e735c5d524db88437672f2c9859e2 --- api/current.txt | 1 + .../android/media/RemoteControlClient.java | 2 +- .../java/android/media/RemoteController.java | 70 ++- .../keyguard_transport_control_view.xml | 163 ++++-- packages/Keyguard/res/values/strings.xml | 7 + .../android/keyguard/KeyguardHostView.java | 9 + .../KeyguardTransportControlView.java | 536 ++++++++++++------ 7 files changed, 563 insertions(+), 225 deletions(-) diff --git a/api/current.txt b/api/current.txt index 2ed9c5890a39c..d050c18ab6619 100644 --- a/api/current.txt +++ b/api/current.txt @@ -13356,6 +13356,7 @@ package android.media { ctor public RemoteController(android.content.Context, android.os.Looper) throws java.lang.IllegalArgumentException; method public int clearArtworkConfiguration(); method public android.media.RemoteController.MetadataEditor editMetadata(); + method public long getEstimatedMediaPosition(); method public int seekTo(long); method public int sendMediaKeyEvent(android.view.KeyEvent); method public int setArtworkConfiguration(int, int); diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java index ab6bd705e12dd..497b8b3695b64 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -1674,7 +1674,7 @@ public class RemoteControlClient * @return true during any form of playback, false if it's not playing anything while in this * playback state */ - private static boolean playbackPositionShouldMove(int playstate) { + static boolean playbackPositionShouldMove(int playstate) { switch(playstate) { case PLAYSTATE_STOPPED: case PLAYSTATE_PAUSED: diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java index 96f6a922755da..d056269e890fc 100644 --- a/media/java/android/media/RemoteController.java +++ b/media/java/android/media/RemoteController.java @@ -17,6 +17,7 @@ package android.media; import android.Manifest; +import android.app.ActivityManager; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.Context; @@ -30,6 +31,8 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemClock; +import android.util.DisplayMetrics; import android.util.Log; import android.view.KeyEvent; @@ -59,6 +62,7 @@ public final class RemoteController private final RcDisplay mRcd; private final Context mContext; private final AudioManager mAudioManager; + private final int mMaxBitmapDimension; private MetadataEditor mMetadataEditor; /** @@ -110,6 +114,13 @@ public final class RemoteController mContext = context; mRcd = new RcDisplay(); mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + + if (ActivityManager.isLowRamDeviceStatic()) { + mMaxBitmapDimension = MAX_BITMAP_DIMENSION; + } else { + final DisplayMetrics dm = context.getResources().getDisplayMetrics(); + mMaxBitmapDimension = Math.max(dm.widthPixels, dm.heightPixels); + } } @@ -142,7 +153,7 @@ public final class RemoteController * @param state one of the playback states authorized * in {@link RemoteControlClient#setPlaybackState(int)}. * @param stateChangeTimeMs the system time at which the state change was reported, - * expressed in ms. + * expressed in ms. Based on {@link android.os.SystemClock.elapsedRealtime()}. * @param currentPosMs a positive value for the current media playback position expressed * in ms, a negative value if the position is temporarily unknown. * @param speed a value expressed as a ratio of 1x playback: 1.0f is normal playback, @@ -200,6 +211,50 @@ public final class RemoteController } } + /** + * @hide + */ + public String getRemoteControlClientPackageName() { + return mClientPendingIntentCurrent != null ? + mClientPendingIntentCurrent.getCreatorPackage() : null; + } + + /** + * Return the estimated playback position of the current media track or a negative value + * if not available. + * + *

The value returned is estimated by the current process and may not be perfect. + * The time returned by this method is calculated from the last state change time based + * on the current play position at that time and the last known playback speed. + * An application may call {@link #setSynchronizationMode(int)} to apply + * a synchronization policy that will periodically re-sync the estimated position + * with the RemoteControlClient.

+ * + * @return the current estimated playback position in milliseconds or a negative value + * if not available + * + * @see OnClientUpdateListener#onClientPlaybackStateUpdate(int, long, long, float) + */ + public long getEstimatedMediaPosition() { + if (mLastPlaybackInfo != null) { + if (!RemoteControlClient.playbackPositionShouldMove(mLastPlaybackInfo.mState)) { + return mLastPlaybackInfo.mCurrentPosMs; + } + + // Take the current position at the time of state change and estimate. + final long thenPos = mLastPlaybackInfo.mCurrentPosMs; + if (thenPos < 0) { + return -1; + } + + final long now = SystemClock.elapsedRealtime(); + final long then = mLastPlaybackInfo.mStateChangeTimeMs; + final long sinceThen = now - then; + final long scaledSinceThen = (long) (sinceThen * mLastPlaybackInfo.mSpeed); + return thenPos + scaledSinceThen; + } + return -1; + } /** * Send a simulated key event for a media button to be received by the current client. @@ -301,8 +356,8 @@ public final class RemoteController synchronized (mInfoLock) { if (wantBitmap) { if ((width > 0) && (height > 0)) { - if (width > MAX_BITMAP_DIMENSION) { width = MAX_BITMAP_DIMENSION; } - if (height > MAX_BITMAP_DIMENSION) { height = MAX_BITMAP_DIMENSION; } + if (width > mMaxBitmapDimension) { width = mMaxBitmapDimension; } + if (height > mMaxBitmapDimension) { height = mMaxBitmapDimension; } mArtworkWidth = width; mArtworkHeight = height; } else { @@ -415,7 +470,13 @@ public final class RemoteController protected MetadataEditor(Bundle metadata, long editableKeys) { mEditorMetadata = metadata; mEditableKeys = editableKeys; - mEditorArtwork = null; + + mEditorArtwork = (Bitmap) metadata.getParcelable( + String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK)); + if (mEditorArtwork != null) { + cleanupBitmapFromBundle(MediaMetadataEditor.BITMAP_KEY_ARTWORK); + } + mMetadataChanged = true; mArtworkChanged = true; mApplied = false; @@ -706,6 +767,7 @@ public final class RemoteController // existing metadata, merge existing and new mMetadataEditor.mEditorMetadata.putAll(metadata); } + mMetadataEditor.putBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK, (Bitmap)metadata.getParcelable( String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK))); diff --git a/packages/Keyguard/res/layout/keyguard_transport_control_view.xml b/packages/Keyguard/res/layout/keyguard_transport_control_view.xml index 801999a7cbbfe..81c742504948f 100644 --- a/packages/Keyguard/res/layout/keyguard_transport_control_view.xml +++ b/packages/Keyguard/res/layout/keyguard_transport_control_view.xml @@ -22,34 +22,133 @@ android:gravity="center_horizontal" android:id="@+id/keyguard_transport_control"> - - - - - + + + android:layout_height="wrap_content"> + + + + + + + + + + + + + + + + + + + + + + - - - diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml index 89e72409f8b41..11f2e5480d09a 100644 --- a/packages/Keyguard/res/values/strings.xml +++ b/packages/Keyguard/res/values/strings.xml @@ -148,6 +148,13 @@ Play button Stop button + + Thumbs up + + Thumbs down + + Heart +