diff options
author | Adam Powell <adamp@google.com> | 2013-09-30 16:16:24 -0700 |
---|---|---|
committer | Adam Powell <adamp@google.com> | 2013-10-03 14:55:18 -0700 |
commit | f8895248e2ac4dbb46622f3e04c7256f03175b4f (patch) | |
tree | 191c1c11a865e2ac3bc4fe2ba51ebbae387320b0 /packages/Keyguard/src/com/android/keyguard | |
parent | 95867a652410b5f0193cf301f5737381bcbd3a88 (diff) | |
download | frameworks_base-f8895248e2ac4dbb46622f3e04c7256f03175b4f.zip frameworks_base-f8895248e2ac4dbb46622f3e04c7256f03175b4f.tar.gz frameworks_base-f8895248e2ac4dbb46622f3e04c7256f03175b4f.tar.bz2 |
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
Diffstat (limited to 'packages/Keyguard/src/com/android/keyguard')
-rw-r--r-- | packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java | 9 | ||||
-rw-r--r-- | packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java | 514 |
2 files changed, 346 insertions, 177 deletions
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java index bc8c866..63aab4d 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java @@ -134,6 +134,10 @@ public class KeyguardHostView extends KeyguardViewBase { void userActivity(); } + interface TransportControlCallback { + void userActivity(); + } + /*package*/ interface OnDismissAction { /* returns true if the dismiss should be deferred */ boolean onDismiss(); @@ -1222,6 +1226,11 @@ public class KeyguardHostView extends KeyguardViewBase { LayoutInflater inflater = LayoutInflater.from(mContext); mTransportControl = (KeyguardTransportControlView) inflater.inflate(R.layout.keyguard_transport_control_view, this, false); + mTransportControl.setTransportControlCallback(new TransportControlCallback() { + public void userActivity() { + mViewMediatorCallback.userActivity(); + } + }); } return mTransportControl; } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java index 2a5f979..83d8ab1 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java @@ -16,191 +16,263 @@ package com.android.keyguard; -import android.app.PendingIntent; -import android.app.PendingIntent.CanceledException; import android.content.Context; -import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.drawable.Drawable; import android.media.AudioManager; -import android.media.IRemoteControlDisplay; +import android.media.MediaMetadataEditor; import android.media.MediaMetadataRetriever; import android.media.RemoteControlClient; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; +import android.media.RemoteController; import android.os.Parcel; import android.os.Parcelable; -import android.os.RemoteException; import android.os.SystemClock; -import android.text.Spannable; import android.text.TextUtils; -import android.text.style.ForegroundColorSpan; +import android.text.format.DateFormat; +import android.transition.ChangeBounds; +import android.transition.ChangeText; +import android.transition.Fade; +import android.transition.TransitionManager; +import android.transition.TransitionSet; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.KeyEvent; import android.view.View; -import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.SeekBar; import android.widget.TextView; -import java.lang.ref.WeakReference; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + /** * This is the widget responsible for showing music controls in keyguard. */ -public class KeyguardTransportControlView extends FrameLayout implements OnClickListener { +public class KeyguardTransportControlView extends FrameLayout { - private static final int MSG_UPDATE_STATE = 100; - private static final int MSG_SET_METADATA = 101; - private static final int MSG_SET_TRANSPORT_CONTROLS = 102; - private static final int MSG_SET_ARTWORK = 103; - private static final int MSG_SET_GENERATION_ID = 104; private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s + private static final int RESET_TO_METADATA_DELAY = 5000; protected static final boolean DEBUG = false; protected static final String TAG = "TransportControlView"; - private ImageView mAlbumArt; + private static final boolean ANIMATE_TRANSITIONS = false; + + private ViewGroup mMetadataContainer; + private ViewGroup mInfoContainer; private TextView mTrackTitle; + private TextView mTrackArtistAlbum; + + private View mTransientSeek; + private SeekBar mTransientSeekBar; + private TextView mTransientSeekTimeElapsed; + private TextView mTransientSeekTimeRemaining; + private ImageView mBtnPrev; private ImageView mBtnPlay; private ImageView mBtnNext; - private int mClientGeneration; private Metadata mMetadata = new Metadata(); - private boolean mAttached; - private PendingIntent mClientIntent; private int mTransportControlFlags; private int mCurrentPlayState; private AudioManager mAudioManager; - private IRemoteControlDisplayWeak mIRCD; + private RemoteController mRemoteController; + + private ImageView mBadge; + + private boolean mSeekEnabled; + private boolean mUserSeeking; + private java.text.DateFormat mFormat; /** * The metadata which should be populated into the view once we've been attached */ - private Bundle mPopulateMetadataWhenAttached = null; + private RemoteController.MetadataEditor mPopulateMetadataWhenAttached = null; - // This handler is required to ensure messages from IRCD are handled in sequence and on - // the UI thread. - private Handler mHandler = new Handler() { + private RemoteController.OnClientUpdateListener mRCClientUpdateListener = + new RemoteController.OnClientUpdateListener() { @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_UPDATE_STATE: - if (mClientGeneration == msg.arg1) updatePlayPauseState(msg.arg2); - break; + public void onClientChange(boolean clearing) { + if (clearing) { + clearMetadata(); + } + } - case MSG_SET_METADATA: - if (mClientGeneration == msg.arg1) updateMetadata((Bundle) msg.obj); - break; + @Override + public void onClientPlaybackStateUpdate(int state) { + setSeekBarsEnabled(false); + updatePlayPauseState(state); + } - case MSG_SET_TRANSPORT_CONTROLS: - if (mClientGeneration == msg.arg1) updateTransportControls(msg.arg2); - break; + @Override + public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs, + long currentPosMs, float speed) { + setSeekBarsEnabled(mMetadata != null && mMetadata.duration > 0); + updatePlayPauseState(state); + if (DEBUG) Log.d(TAG, "onClientPlaybackStateUpdate(state=" + state + + ", stateChangeTimeMs=" + stateChangeTimeMs + ", currentPosMs=" + currentPosMs + + ", speed=" + speed + ")"); + } - case MSG_SET_ARTWORK: - if (mClientGeneration == msg.arg1) { - mMetadata.bitmap = (Bitmap) msg.obj; - KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground( - mMetadata.bitmap); - } - break; + @Override + public void onClientTransportControlUpdate(int transportControlFlags) { + updateTransportControls(transportControlFlags); + } - case MSG_SET_GENERATION_ID: - if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2); - mClientGeneration = msg.arg1; - mClientIntent = (PendingIntent) msg.obj; - break; + @Override + public void onClientMetadataUpdate(RemoteController.MetadataEditor metadataEditor) { + updateMetadata(metadataEditor); + } + }; + private final Runnable mUpdateSeekBars = new Runnable() { + public void run() { + if (updateSeekBars()) { + postDelayed(this, 1000); } } }; - /** - * This class is required to have weak linkage to the current TransportControlView - * because the remote process can hold a strong reference to this binder object and - * we can't predict when it will be GC'd in the remote process. Without this code, it - * would allow a heavyweight object to be held on this side of the binder when there's - * no requirement to run a GC on the other side. - */ - private static class IRemoteControlDisplayWeak extends IRemoteControlDisplay.Stub { - private WeakReference<Handler> mLocalHandler; - - IRemoteControlDisplayWeak(Handler handler) { - mLocalHandler = new WeakReference<Handler>(handler); + private final Runnable mResetToMetadata = new Runnable() { + public void run() { + resetToMetadata(); } + }; - public void setPlaybackState(int generationId, int state, long stateChangeTimeMs, - long currentPosMs, float speed) { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget(); + private final OnClickListener mTransportCommandListener = new OnClickListener() { + public void onClick(View v) { + int keyCode = -1; + if (v == mBtnPrev) { + keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS; + } else if (v == mBtnNext) { + keyCode = KeyEvent.KEYCODE_MEDIA_NEXT; + } else if (v == mBtnPlay) { + keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE; } - } - - public void setMetadata(int generationId, Bundle metadata) { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget(); + if (keyCode != -1) { + sendMediaButtonClick(keyCode); } } + }; - public void setTransportControlInfo(int generationId, int flags, int posCapabilities) { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags) - .sendToTarget(); + private final OnLongClickListener mTransportShowSeekBarListener = new OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + if (mSeekEnabled) { + return tryToggleSeekBar(); } + return false; } + }; - public void setArtwork(int generationId, Bitmap bitmap) { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget(); + private final SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = + new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + scrubTo(progress); + delayResetToMetadata(); } + updateSeekDisplay(); } - public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget(); - handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget(); - } + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + mUserSeeking = true; } - public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent, - boolean clearing) throws RemoteException { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_SET_GENERATION_ID, - clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget(); - } + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + mUserSeeking = false; } }; + private static final int TRANSITION_DURATION = 200; + private final TransitionSet mMetadataChangeTransition; + + KeyguardHostView.TransportControlCallback mTransportControlCallback; + public KeyguardTransportControlView(Context context, AttributeSet attrs) { super(context, attrs); if (DEBUG) Log.v(TAG, "Create TCV " + this); mAudioManager = new AudioManager(mContext); mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback - mIRCD = new IRemoteControlDisplayWeak(mHandler); + mRemoteController = new RemoteController(context); + mRemoteController.setOnClientUpdateListener(mRCClientUpdateListener); + + final DisplayMetrics dm = context.getResources().getDisplayMetrics(); + final int dim = Math.max(dm.widthPixels, dm.heightPixels); + mRemoteController.setArtworkConfiguration(true, dim, dim); + + final ChangeText tc = new ChangeText(); + tc.setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT_IN); + final TransitionSet inner = new TransitionSet(); + inner.addTransition(tc).addTransition(new ChangeBounds()); + final TransitionSet tg = new TransitionSet(); + tg.addTransition(new Fade(Fade.OUT)).addTransition(inner). + addTransition(new Fade(Fade.IN)); + tg.setOrdering(TransitionSet.ORDERING_SEQUENTIAL); + tg.setDuration(TRANSITION_DURATION); + mMetadataChangeTransition = tg; } private void updateTransportControls(int transportControlFlags) { mTransportControlFlags = transportControlFlags; + setSeekBarsEnabled( + (transportControlFlags & RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE) != 0); + } + + void setSeekBarsEnabled(boolean enabled) { + if (enabled == mSeekEnabled) return; + + mSeekEnabled = enabled; + if (mTransientSeek.getVisibility() == VISIBLE) { + mTransientSeek.setVisibility(INVISIBLE); + mMetadataContainer.setVisibility(VISIBLE); + mUserSeeking = false; + cancelResetToMetadata(); + } + if (enabled) { + mUpdateSeekBars.run(); + postDelayed(mUpdateSeekBars, 1000); + } else { + removeCallbacks(mUpdateSeekBars); + } + } + + public void setTransportControlCallback(KeyguardHostView.TransportControlCallback + transportControlCallback) { + mTransportControlCallback = transportControlCallback; } @Override public void onFinishInflate() { super.onFinishInflate(); + mInfoContainer = (ViewGroup) findViewById(R.id.info_container); + mMetadataContainer = (ViewGroup) findViewById(R.id.metadata_container); + mBadge = (ImageView) findViewById(R.id.badge); mTrackTitle = (TextView) findViewById(R.id.title); mTrackTitle.setSelected(true); // enable marquee - mAlbumArt = (ImageView) findViewById(R.id.albumart); + mTrackArtistAlbum = (TextView) findViewById(R.id.artist_album); + mTrackArtistAlbum.setSelected(true); + mTransientSeek = findViewById(R.id.transient_seek); + mTransientSeekBar = (SeekBar) findViewById(R.id.transient_seek_bar); + mTransientSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener); + mTransientSeekTimeElapsed = (TextView) findViewById(R.id.transient_seek_time_elapsed); + mTransientSeekTimeRemaining = (TextView) findViewById(R.id.transient_seek_time_remaining); mBtnPrev = (ImageView) findViewById(R.id.btn_prev); mBtnPlay = (ImageView) findViewById(R.id.btn_play); mBtnNext = (ImageView) findViewById(R.id.btn_next); final View buttons[] = { mBtnPrev, mBtnPlay, mBtnNext }; for (View view : buttons) { - view.setOnClickListener(this); + view.setOnClickListener(mTransportCommandListener); + view.setOnLongClickListener(mTransportShowSeekBarListener); } } @@ -212,32 +284,34 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick updateMetadata(mPopulateMetadataWhenAttached); mPopulateMetadataWhenAttached = null; } - if (!mAttached) { - if (DEBUG) Log.v(TAG, "Registering TCV " + this); - mAudioManager.registerRemoteControlDisplay(mIRCD); - } - mAttached = true; + if (DEBUG) Log.v(TAG, "Registering TCV " + this); + mAudioManager.registerRemoteController(mRemoteController); } @Override - protected void onSizeChanged (int w, int h, int oldw, int oldh) { - if (mAttached) { - final DisplayMetrics dm = getContext().getResources().getDisplayMetrics(); - int dim = Math.max(dm.widthPixels, dm.heightPixels); - if (DEBUG) Log.v(TAG, "TCV uses bitmap size=" + dim); - mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim); - } + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + final DisplayMetrics dm = getContext().getResources().getDisplayMetrics(); + final int dim = Math.max(dm.widthPixels, dm.heightPixels); + mRemoteController.setArtworkConfiguration(true, dim, dim); } @Override public void onDetachedFromWindow() { if (DEBUG) Log.v(TAG, "onDetachFromWindow()"); super.onDetachedFromWindow(); - if (mAttached) { - if (DEBUG) Log.v(TAG, "Unregistering TCV " + this); - mAudioManager.unregisterRemoteControlDisplay(mIRCD); - } - mAttached = false; + if (DEBUG) Log.v(TAG, "Unregistering TCV " + this); + mAudioManager.unregisterRemoteController(mRemoteController); + mUserSeeking = false; + } + + void setBadgeIcon(Drawable bmp) { + mBadge.setImageDrawable(bmp); + + final ColorMatrix cm = new ColorMatrix(); + cm.setSaturation(0); + mBadge.setColorFilter(new ColorMatrixColorFilter(cm)); + mBadge.setImageAlpha(0xef); } class Metadata { @@ -245,21 +319,39 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick private String trackTitle; private String albumTitle; private Bitmap bitmap; + private long duration; + + public void clear() { + artist = null; + trackTitle = null; + albumTitle = null; + bitmap = null; + duration = -1; + } public String toString() { - return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" + albumTitle + "]"; + return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + + " albumTitle=" + albumTitle + " duration=" + duration + "]"; } } - private String getMdString(Bundle data, int id) { - return data.getString(Integer.toString(id)); + void clearMetadata() { + mPopulateMetadataWhenAttached = null; + mMetadata.clear(); + populateMetadata(); } - private void updateMetadata(Bundle data) { - if (mAttached) { - mMetadata.artist = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST); - mMetadata.trackTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_TITLE); - mMetadata.albumTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUM); + void updateMetadata(RemoteController.MetadataEditor data) { + if (isAttachedToWindow()) { + mMetadata.artist = data.getString(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, + mMetadata.artist); + mMetadata.trackTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_TITLE, + mMetadata.trackTitle); + mMetadata.albumTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_ALBUM, + mMetadata.albumTitle); + mMetadata.duration = data.getLong(MediaMetadataRetriever.METADATA_KEY_DURATION, -1); + mMetadata.bitmap = data.getBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK, + mMetadata.bitmap); populateMetadata(); } else { mPopulateMetadataWhenAttached = data; @@ -270,12 +362,22 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick * Populates the given metadata into the view */ private void populateMetadata() { - StringBuilder sb = new StringBuilder(); - int trackTitleLength = 0; + if (ANIMATE_TRANSITIONS && isLaidOut() && mMetadataContainer.getVisibility() == VISIBLE) { + TransitionManager.beginDelayedTransition(mMetadataContainer, mMetadataChangeTransition); + } + + final String remoteClientPackage = mRemoteController.getRemoteControlClientPackageName(); + Drawable badgeIcon = null; + try { + badgeIcon = getContext().getPackageManager().getApplicationIcon(remoteClientPackage); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Couldn't get remote control client package icon", e); + } + setBadgeIcon(badgeIcon); if (!TextUtils.isEmpty(mMetadata.trackTitle)) { - sb.append(mMetadata.trackTitle); - trackTitleLength = mMetadata.trackTitle.length(); + mTrackTitle.setText(mMetadata.trackTitle); } + StringBuilder sb = new StringBuilder(); if (!TextUtils.isEmpty(mMetadata.artist)) { if (sb.length() != 0) { sb.append(" - "); @@ -288,16 +390,27 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick } sb.append(mMetadata.albumTitle); } - mTrackTitle.setText(sb.toString(), TextView.BufferType.SPANNABLE); - Spannable str = (Spannable) mTrackTitle.getText(); - if (trackTitleLength != 0) { - str.setSpan(new ForegroundColorSpan(0xffffffff), 0, trackTitleLength, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - trackTitleLength++; - } - if (sb.length() > trackTitleLength) { - str.setSpan(new ForegroundColorSpan(0x7fffffff), trackTitleLength, sb.length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + mTrackArtistAlbum.setText(sb.toString()); + + if (mMetadata.duration >= 0) { + setSeekBarsEnabled(true); + setSeekBarDuration(mMetadata.duration); + + final String skeleton; + + if (mMetadata.duration >= 86400000) { + skeleton = "DDD kk mm ss"; + } else if (mMetadata.duration >= 3600000) { + skeleton = "kk mm ss"; + } else { + skeleton = "mm ss"; + } + mFormat = new SimpleDateFormat(DateFormat.getBestDateTimePattern( + getContext().getResources().getConfiguration().locale, + skeleton)); + mFormat.setTimeZone(TimeZone.getTimeZone("GMT+0")); + } else { + setSeekBarsEnabled(false); } KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground( @@ -314,6 +427,66 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick updatePlayPauseState(mCurrentPlayState); } + void updateSeekDisplay() { + if (mMetadata != null && mRemoteController != null && mFormat != null) { + final long timeElapsed = mRemoteController.getEstimatedMediaPosition(); + final long duration = mMetadata.duration; + final long remaining = duration - timeElapsed; + + mTransientSeekTimeElapsed.setText(mFormat.format(new Date(timeElapsed))); + mTransientSeekTimeRemaining.setText(mFormat.format(new Date(remaining))); + + if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + timeElapsed + + " duration=" + duration + " remaining=" + remaining); + } + } + + boolean tryToggleSeekBar() { + if (ANIMATE_TRANSITIONS) { + TransitionManager.beginDelayedTransition(mInfoContainer); + } + if (mTransientSeek.getVisibility() == VISIBLE) { + mTransientSeek.setVisibility(INVISIBLE); + mMetadataContainer.setVisibility(VISIBLE); + cancelResetToMetadata(); + } else { + mTransientSeek.setVisibility(VISIBLE); + mMetadataContainer.setVisibility(INVISIBLE); + delayResetToMetadata(); + } + mTransportControlCallback.userActivity(); + return true; + } + + void resetToMetadata() { + if (ANIMATE_TRANSITIONS) { + TransitionManager.beginDelayedTransition(mInfoContainer); + } + if (mTransientSeek.getVisibility() == VISIBLE) { + mTransientSeek.setVisibility(INVISIBLE); + mMetadataContainer.setVisibility(VISIBLE); + } + // TODO Also hide ratings, if applicable + } + + void delayResetToMetadata() { + removeCallbacks(mResetToMetadata); + postDelayed(mResetToMetadata, RESET_TO_METADATA_DELAY); + } + + void cancelResetToMetadata() { + removeCallbacks(mResetToMetadata); + } + + void setSeekBarDuration(long duration) { + mTransientSeekBar.setMax((int) duration); + } + + void scrubTo(int progress) { + mRemoteController.seekTo(progress); + mTransportControlCallback.userActivity(); + } + private static void setVisibilityBasedOnFlag(View view, int flags, int flag) { if ((flags & flag) != 0) { view.setVisibility(View.VISIBLE); @@ -341,6 +514,9 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick case RemoteControlClient.PLAYSTATE_PLAYING: imageResId = R.drawable.ic_media_pause; imageDescId = R.string.keyguard_transport_pause_description; + if (mSeekEnabled) { + postDelayed(mUpdateSeekBars, 1000); + } break; case RemoteControlClient.PLAYSTATE_BUFFERING: @@ -354,11 +530,30 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick imageDescId = R.string.keyguard_transport_play_description; break; } + + if (state != RemoteControlClient.PLAYSTATE_PLAYING) { + removeCallbacks(mUpdateSeekBars); + updateSeekBars(); + } mBtnPlay.setImageResource(imageResId); mBtnPlay.setContentDescription(getResources().getString(imageDescId)); mCurrentPlayState = state; } + boolean updateSeekBars() { + final int position = (int) mRemoteController.getEstimatedMediaPosition(); + if (position >= 0) { + if (!mUserSeeking) { + mTransientSeekBar.setProgress(position); + } + return true; + } + Log.w(TAG, "Updating seek bars; received invalid estimated media position (" + + position + "). Disabling seek."); + setSeekBarsEnabled(false); + return false; + } + static class SavedState extends BaseSavedState { boolean clientPresent; @@ -389,48 +584,13 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick }; } - public void onClick(View v) { - int keyCode = -1; - if (v == mBtnPrev) { - keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS; - } else if (v == mBtnNext) { - keyCode = KeyEvent.KEYCODE_MEDIA_NEXT; - } else if (v == mBtnPlay) { - keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE; - - } - if (keyCode != -1) { - sendMediaButtonClick(keyCode); - } - } - private void sendMediaButtonClick(int keyCode) { - if (mClientIntent == null) { - // Shouldn't be possible because this view should be hidden in this case. - Log.e(TAG, "sendMediaButtonClick(): No client is currently registered"); - return; - } - // use the registered PendingIntent that will be processed by the registered - // media button event receiver, which is the component of mClientIntent - KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); - Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON); - intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); - try { - mClientIntent.send(getContext(), 0, intent); - } catch (CanceledException e) { - Log.e(TAG, "Error sending intent for media button down: "+e); - e.printStackTrace(); - } + // TODO We should think about sending these up/down events accurately with touch up/down + // on the buttons, but in the near term this will interfere with the long press behavior. + mRemoteController.sendMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode)); + mRemoteController.sendMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode)); - keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode); - intent = new Intent(Intent.ACTION_MEDIA_BUTTON); - intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); - try { - mClientIntent.send(getContext(), 0, intent); - } catch (CanceledException e) { - Log.e(TAG, "Error sending intent for media button up: "+e); - e.printStackTrace(); - } + mTransportControlCallback.userActivity(); } public boolean providesClock() { |