Loading packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java +85 −72 Original line number Diff line number Diff line Loading @@ -60,12 +60,12 @@ import java.util.TimeZone; */ public class KeyguardTransportControlView extends FrameLayout { 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 static final boolean ANIMATE_TRANSITIONS = true; protected static final long QUIESCENT_PLAYBACK_FACTOR = 1000; private ViewGroup mMetadataContainer; private ViewGroup mInfoContainer; Loading @@ -89,11 +89,9 @@ public class KeyguardTransportControlView extends FrameLayout { private ImageView mBadge; private boolean mSeekEnabled; private boolean mUserSeeking; private java.text.DateFormat mFormat; private Date mTimeElapsed; private Date mTrackDuration; private Date mTempDate = new Date(); /** * The metadata which should be populated into the view once we've been attached Loading @@ -111,18 +109,25 @@ public class KeyguardTransportControlView extends FrameLayout { @Override public void onClientPlaybackStateUpdate(int state) { setSeekBarsEnabled(false); updatePlayPauseState(state); } @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 + ")"); removeCallbacks(mUpdateSeekBars); // Since the music client may be responding to historical events that cause the // playback state to change dramatically, wait until things become quiescent before // resuming automatic scrub position update. if (mTransientSeek.getVisibility() == View.VISIBLE && playbackPositionShouldMove(mCurrentPlayState)) { postDelayed(mUpdateSeekBars, QUIESCENT_PLAYBACK_FACTOR); } } @Override Loading @@ -136,15 +141,21 @@ public class KeyguardTransportControlView extends FrameLayout { } }; private final Runnable mUpdateSeekBars = new Runnable() { private class UpdateSeekBarRunnable implements Runnable { public void run() { if (updateSeekBars()) { boolean seekAble = updateOnce(); if (seekAble) { removeCallbacks(this); postDelayed(this, 1000); } } public boolean updateOnce() { return updateSeekBars(); } }; private final UpdateSeekBarRunnable mUpdateSeekBars = new UpdateSeekBarRunnable(); private final Runnable mResetToMetadata = new Runnable() { public void run() { resetToMetadata(); Loading @@ -163,6 +174,7 @@ public class KeyguardTransportControlView extends FrameLayout { } if (keyCode != -1) { sendMediaButtonClick(keyCode); delayResetToMetadata(); // if the scrub bar is showing, keep showing it. } } }; Loading @@ -177,25 +189,67 @@ public class KeyguardTransportControlView extends FrameLayout { } }; // This class is here to throttle scrub position updates to the music client class FutureSeekRunnable implements Runnable { private int mProgress; private boolean mPending; public void run() { scrubTo(mProgress); mPending = false; } void setProgress(int progress) { mProgress = progress; if (!mPending) { mPending = true; postDelayed(this, 30); } } }; // This is here because RemoteControlClient's method isn't visible :/ private final static boolean playbackPositionShouldMove(int playstate) { switch(playstate) { case RemoteControlClient.PLAYSTATE_STOPPED: case RemoteControlClient.PLAYSTATE_PAUSED: case RemoteControlClient.PLAYSTATE_BUFFERING: case RemoteControlClient.PLAYSTATE_ERROR: case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: return false; case RemoteControlClient.PLAYSTATE_PLAYING: case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: case RemoteControlClient.PLAYSTATE_REWINDING: default: return true; } } private final FutureSeekRunnable mFutureSeekRunnable = new FutureSeekRunnable(); private final SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { scrubTo(progress); mFutureSeekRunnable.setProgress(progress); delayResetToMetadata(); } mTempDate.setTime(progress); mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate)); } else { updateSeekDisplay(); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { mUserSeeking = true; delayResetToMetadata(); removeCallbacks(mUpdateSeekBars); // don't update during user interaction } @Override public void onStopTrackingTouch(SeekBar seekBar) { mUserSeeking = false; } }; Loading Loading @@ -247,17 +301,11 @@ public class KeyguardTransportControlView extends FrameLayout { if (enabled == mSeekEnabled) return; mSeekEnabled = enabled; if (mTransientSeek.getVisibility() == VISIBLE) { if (mTransientSeek.getVisibility() == VISIBLE && !enabled) { mTransientSeek.setVisibility(INVISIBLE); mMetadataContainer.setVisibility(VISIBLE); mUserSeeking = false; cancelResetToMetadata(); } if (enabled) { mUpdateSeekBars.run(); } else { removeCallbacks(mUpdateSeekBars); } } public void setTransportControlCallback(KeyguardHostView.TransportControlCallback Loading Loading @@ -294,6 +342,8 @@ public class KeyguardTransportControlView extends FrameLayout { } final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn(); setEnableMarquee(screenOn); // Allow long-press anywhere else in this view to show the seek bar setOnLongClickListener(mTransportShowSeekBarListener); } @Override Loading Loading @@ -326,7 +376,6 @@ public class KeyguardTransportControlView extends FrameLayout { mAudioManager.unregisterRemoteController(mRemoteController); KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitor); mMetadata.clear(); mUserSeeking = false; removeCallbacks(mUpdateSeekBars); } Loading Loading @@ -484,18 +533,12 @@ public class KeyguardTransportControlView extends FrameLayout { void updateSeekDisplay() { if (mMetadata != null && mRemoteController != null && mFormat != null) { if (mTimeElapsed == null) { mTimeElapsed = new Date(); } if (mTrackDuration == null) { mTrackDuration = new Date(); } mTimeElapsed.setTime(mRemoteController.getEstimatedMediaPosition()); mTrackDuration.setTime(mMetadata.duration); mTransientSeekTimeElapsed.setText(mFormat.format(mTimeElapsed)); mTransientSeekTimeTotal.setText(mFormat.format(mTrackDuration)); mTempDate.setTime(mRemoteController.getEstimatedMediaPosition()); mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate)); mTempDate.setTime(mMetadata.duration); mTransientSeekTimeTotal.setText(mFormat.format(mTempDate)); if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTimeElapsed + if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTempDate + " duration=" + mMetadata.duration); } } Loading @@ -508,10 +551,16 @@ public class KeyguardTransportControlView extends FrameLayout { mTransientSeek.setVisibility(INVISIBLE); mMetadataContainer.setVisibility(VISIBLE); cancelResetToMetadata(); removeCallbacks(mUpdateSeekBars); // don't update if scrubber isn't visible } else { mTransientSeek.setVisibility(VISIBLE); mMetadataContainer.setVisibility(INVISIBLE); delayResetToMetadata(); if (playbackPositionShouldMove(mCurrentPlayState)) { mUpdateSeekBars.run(); } else { mUpdateSeekBars.updateOnce(); } } mTransportControlCallback.userActivity(); return true; Loading Loading @@ -573,9 +622,6 @@ public class KeyguardTransportControlView extends FrameLayout { case RemoteControlClient.PLAYSTATE_PLAYING: imageResId = R.drawable.ic_media_pause; imageDescId = R.string.keyguard_transport_pause_description; if (mSeekEnabled) { mUpdateSeekBars.run(); } break; case RemoteControlClient.PLAYSTATE_BUFFERING: Loading @@ -590,10 +636,9 @@ public class KeyguardTransportControlView extends FrameLayout { break; } if (state != RemoteControlClient.PLAYSTATE_PLAYING) { removeCallbacks(mUpdateSeekBars); updateSeekBars(); } boolean clientSupportsSeek = mMetadata != null && mMetadata.duration > 0; setSeekBarsEnabled(clientSupportsSeek); mBtnPlay.setImageResource(imageResId); mBtnPlay.setContentDescription(getResources().getString(imageDescId)); mCurrentPlayState = state; Loading @@ -601,11 +646,9 @@ public class KeyguardTransportControlView extends FrameLayout { boolean updateSeekBars() { final int position = (int) mRemoteController.getEstimatedMediaPosition(); if (DEBUG) Log.v(TAG, "Estimated time:" + position); if (position >= 0) { if (DEBUG) Log.v(TAG, "Seek to " + position); if (!mUserSeeking) { mTransientSeekBar.setProgress(position); } return true; } Log.w(TAG, "Updating seek bars; received invalid estimated media position (" + Loading Loading @@ -671,34 +714,4 @@ public class KeyguardTransportControlView extends FrameLayout { public boolean providesClock() { return false; } private boolean wasPlayingRecently(int state, long stateChangeTimeMs) { switch (state) { case RemoteControlClient.PLAYSTATE_PLAYING: case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: case RemoteControlClient.PLAYSTATE_REWINDING: case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: case RemoteControlClient.PLAYSTATE_BUFFERING: // actively playing or about to play return true; case RemoteControlClient.PLAYSTATE_NONE: return false; case RemoteControlClient.PLAYSTATE_STOPPED: case RemoteControlClient.PLAYSTATE_PAUSED: case RemoteControlClient.PLAYSTATE_ERROR: // we have stopped playing, check how long ago if (DEBUG) { if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) { Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently"); } else { Log.v(TAG, "wasPlayingRecently: time > TIMEOUT"); } } return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS); default: Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()"); return false; } } } Loading
packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java +85 −72 Original line number Diff line number Diff line Loading @@ -60,12 +60,12 @@ import java.util.TimeZone; */ public class KeyguardTransportControlView extends FrameLayout { 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 static final boolean ANIMATE_TRANSITIONS = true; protected static final long QUIESCENT_PLAYBACK_FACTOR = 1000; private ViewGroup mMetadataContainer; private ViewGroup mInfoContainer; Loading @@ -89,11 +89,9 @@ public class KeyguardTransportControlView extends FrameLayout { private ImageView mBadge; private boolean mSeekEnabled; private boolean mUserSeeking; private java.text.DateFormat mFormat; private Date mTimeElapsed; private Date mTrackDuration; private Date mTempDate = new Date(); /** * The metadata which should be populated into the view once we've been attached Loading @@ -111,18 +109,25 @@ public class KeyguardTransportControlView extends FrameLayout { @Override public void onClientPlaybackStateUpdate(int state) { setSeekBarsEnabled(false); updatePlayPauseState(state); } @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 + ")"); removeCallbacks(mUpdateSeekBars); // Since the music client may be responding to historical events that cause the // playback state to change dramatically, wait until things become quiescent before // resuming automatic scrub position update. if (mTransientSeek.getVisibility() == View.VISIBLE && playbackPositionShouldMove(mCurrentPlayState)) { postDelayed(mUpdateSeekBars, QUIESCENT_PLAYBACK_FACTOR); } } @Override Loading @@ -136,15 +141,21 @@ public class KeyguardTransportControlView extends FrameLayout { } }; private final Runnable mUpdateSeekBars = new Runnable() { private class UpdateSeekBarRunnable implements Runnable { public void run() { if (updateSeekBars()) { boolean seekAble = updateOnce(); if (seekAble) { removeCallbacks(this); postDelayed(this, 1000); } } public boolean updateOnce() { return updateSeekBars(); } }; private final UpdateSeekBarRunnable mUpdateSeekBars = new UpdateSeekBarRunnable(); private final Runnable mResetToMetadata = new Runnable() { public void run() { resetToMetadata(); Loading @@ -163,6 +174,7 @@ public class KeyguardTransportControlView extends FrameLayout { } if (keyCode != -1) { sendMediaButtonClick(keyCode); delayResetToMetadata(); // if the scrub bar is showing, keep showing it. } } }; Loading @@ -177,25 +189,67 @@ public class KeyguardTransportControlView extends FrameLayout { } }; // This class is here to throttle scrub position updates to the music client class FutureSeekRunnable implements Runnable { private int mProgress; private boolean mPending; public void run() { scrubTo(mProgress); mPending = false; } void setProgress(int progress) { mProgress = progress; if (!mPending) { mPending = true; postDelayed(this, 30); } } }; // This is here because RemoteControlClient's method isn't visible :/ private final static boolean playbackPositionShouldMove(int playstate) { switch(playstate) { case RemoteControlClient.PLAYSTATE_STOPPED: case RemoteControlClient.PLAYSTATE_PAUSED: case RemoteControlClient.PLAYSTATE_BUFFERING: case RemoteControlClient.PLAYSTATE_ERROR: case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: return false; case RemoteControlClient.PLAYSTATE_PLAYING: case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: case RemoteControlClient.PLAYSTATE_REWINDING: default: return true; } } private final FutureSeekRunnable mFutureSeekRunnable = new FutureSeekRunnable(); private final SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { scrubTo(progress); mFutureSeekRunnable.setProgress(progress); delayResetToMetadata(); } mTempDate.setTime(progress); mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate)); } else { updateSeekDisplay(); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { mUserSeeking = true; delayResetToMetadata(); removeCallbacks(mUpdateSeekBars); // don't update during user interaction } @Override public void onStopTrackingTouch(SeekBar seekBar) { mUserSeeking = false; } }; Loading Loading @@ -247,17 +301,11 @@ public class KeyguardTransportControlView extends FrameLayout { if (enabled == mSeekEnabled) return; mSeekEnabled = enabled; if (mTransientSeek.getVisibility() == VISIBLE) { if (mTransientSeek.getVisibility() == VISIBLE && !enabled) { mTransientSeek.setVisibility(INVISIBLE); mMetadataContainer.setVisibility(VISIBLE); mUserSeeking = false; cancelResetToMetadata(); } if (enabled) { mUpdateSeekBars.run(); } else { removeCallbacks(mUpdateSeekBars); } } public void setTransportControlCallback(KeyguardHostView.TransportControlCallback Loading Loading @@ -294,6 +342,8 @@ public class KeyguardTransportControlView extends FrameLayout { } final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn(); setEnableMarquee(screenOn); // Allow long-press anywhere else in this view to show the seek bar setOnLongClickListener(mTransportShowSeekBarListener); } @Override Loading Loading @@ -326,7 +376,6 @@ public class KeyguardTransportControlView extends FrameLayout { mAudioManager.unregisterRemoteController(mRemoteController); KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitor); mMetadata.clear(); mUserSeeking = false; removeCallbacks(mUpdateSeekBars); } Loading Loading @@ -484,18 +533,12 @@ public class KeyguardTransportControlView extends FrameLayout { void updateSeekDisplay() { if (mMetadata != null && mRemoteController != null && mFormat != null) { if (mTimeElapsed == null) { mTimeElapsed = new Date(); } if (mTrackDuration == null) { mTrackDuration = new Date(); } mTimeElapsed.setTime(mRemoteController.getEstimatedMediaPosition()); mTrackDuration.setTime(mMetadata.duration); mTransientSeekTimeElapsed.setText(mFormat.format(mTimeElapsed)); mTransientSeekTimeTotal.setText(mFormat.format(mTrackDuration)); mTempDate.setTime(mRemoteController.getEstimatedMediaPosition()); mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate)); mTempDate.setTime(mMetadata.duration); mTransientSeekTimeTotal.setText(mFormat.format(mTempDate)); if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTimeElapsed + if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTempDate + " duration=" + mMetadata.duration); } } Loading @@ -508,10 +551,16 @@ public class KeyguardTransportControlView extends FrameLayout { mTransientSeek.setVisibility(INVISIBLE); mMetadataContainer.setVisibility(VISIBLE); cancelResetToMetadata(); removeCallbacks(mUpdateSeekBars); // don't update if scrubber isn't visible } else { mTransientSeek.setVisibility(VISIBLE); mMetadataContainer.setVisibility(INVISIBLE); delayResetToMetadata(); if (playbackPositionShouldMove(mCurrentPlayState)) { mUpdateSeekBars.run(); } else { mUpdateSeekBars.updateOnce(); } } mTransportControlCallback.userActivity(); return true; Loading Loading @@ -573,9 +622,6 @@ public class KeyguardTransportControlView extends FrameLayout { case RemoteControlClient.PLAYSTATE_PLAYING: imageResId = R.drawable.ic_media_pause; imageDescId = R.string.keyguard_transport_pause_description; if (mSeekEnabled) { mUpdateSeekBars.run(); } break; case RemoteControlClient.PLAYSTATE_BUFFERING: Loading @@ -590,10 +636,9 @@ public class KeyguardTransportControlView extends FrameLayout { break; } if (state != RemoteControlClient.PLAYSTATE_PLAYING) { removeCallbacks(mUpdateSeekBars); updateSeekBars(); } boolean clientSupportsSeek = mMetadata != null && mMetadata.duration > 0; setSeekBarsEnabled(clientSupportsSeek); mBtnPlay.setImageResource(imageResId); mBtnPlay.setContentDescription(getResources().getString(imageDescId)); mCurrentPlayState = state; Loading @@ -601,11 +646,9 @@ public class KeyguardTransportControlView extends FrameLayout { boolean updateSeekBars() { final int position = (int) mRemoteController.getEstimatedMediaPosition(); if (DEBUG) Log.v(TAG, "Estimated time:" + position); if (position >= 0) { if (DEBUG) Log.v(TAG, "Seek to " + position); if (!mUserSeeking) { mTransientSeekBar.setProgress(position); } return true; } Log.w(TAG, "Updating seek bars; received invalid estimated media position (" + Loading Loading @@ -671,34 +714,4 @@ public class KeyguardTransportControlView extends FrameLayout { public boolean providesClock() { return false; } private boolean wasPlayingRecently(int state, long stateChangeTimeMs) { switch (state) { case RemoteControlClient.PLAYSTATE_PLAYING: case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: case RemoteControlClient.PLAYSTATE_REWINDING: case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: case RemoteControlClient.PLAYSTATE_BUFFERING: // actively playing or about to play return true; case RemoteControlClient.PLAYSTATE_NONE: return false; case RemoteControlClient.PLAYSTATE_STOPPED: case RemoteControlClient.PLAYSTATE_PAUSED: case RemoteControlClient.PLAYSTATE_ERROR: // we have stopped playing, check how long ago if (DEBUG) { if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) { Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently"); } else { Log.v(TAG, "wasPlayingRecently: time > TIMEOUT"); } } return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS); default: Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()"); return false; } } }