Skip to content

Commit 4e6d358

Browse files
author
Jim Miller
committed
Fix 5358124: Better transport control visibility management in lock screen
This changes TransportControlView to be "sticky" on lockscreen. Basically, once it appears on lockscreen, it stays there until unlocked and then locked again in paused state. Tested basic design goals (using Music2): - play then lock -> shows - pause then lock -> not shown - toggle pause to play while locked and not shown -> shows - pause after played once while locked -> stays until we unlock and lock again while paused - remote control play while paused & sleeping -> resume lockscreen -> shows Also tested: - configuration changes (orientation) to ensure widget continues to show after it once appears - remote events while lock screen on -> keeps lockscreen on. - remote events while sleeping -> doesn't wake. Change-Id: I23418c5f7dfd1457c0844d2683772e8a3ed0abd1
1 parent 3406886 commit 4e6d358

File tree

3 files changed

+123
-19
lines changed

3 files changed

+123
-19
lines changed

core/java/com/android/internal/widget/LockScreenWidgetCallback.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ public interface LockScreenWidgetCallback {
2929
// Sends a message to lock screen requesting the view to be hidden.
3030
public void requestHide(View self);
3131

32+
// Whether or not this view is currently visible on LockScreen
33+
public boolean isVisible(View self);
34+
3235
// Sends a message to lock screen that user has interacted with widget. This should be used
3336
// exclusively in response to user activity, i.e. user hits a button in the view.
3437
public void userActivity(View self);

core/java/com/android/internal/widget/TransportControlView.java

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import android.os.Bundle;
3535
import android.os.Handler;
3636
import android.os.Message;
37+
import android.os.Parcel;
38+
import android.os.Parcelable;
3739
import android.os.RemoteException;
3840
import android.os.SystemClock;
3941
import android.text.Spannable;
@@ -61,7 +63,7 @@ public class TransportControlView extends FrameLayout implements OnClickListener
6163
private static final int MSG_SET_GENERATION_ID = 104;
6264
private static final int MAXDIM = 512;
6365
private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
64-
protected static final boolean DEBUG = true;
66+
protected static final boolean DEBUG = false;
6567
protected static final String TAG = "TransportControlView";
6668

6769
private ImageView mAlbumArt;
@@ -74,7 +76,7 @@ public class TransportControlView extends FrameLayout implements OnClickListener
7476
private boolean mAttached;
7577
private PendingIntent mClientIntent;
7678
private int mTransportControlFlags;
77-
private int mPlayState;
79+
private int mCurrentPlayState;
7880
private AudioManager mAudioManager;
7981
private LockScreenWidgetCallback mWidgetCallbacks;
8082
private IRemoteControlDisplayWeak mIRCD;
@@ -84,6 +86,11 @@ public class TransportControlView extends FrameLayout implements OnClickListener
8486
*/
8587
private Bundle mPopulateMetadataWhenAttached = null;
8688

89+
/**
90+
* Whether to clear the interface next time it is shown (i.e. the generation id changed)
91+
*/
92+
private boolean mClearOnNextShow;
93+
8794
// This handler is required to ensure messages from IRCD are handled in sequence and on
8895
// the UI thread.
8996
private Handler mHandler = new Handler() {
@@ -113,15 +120,10 @@ public void handleMessage(Message msg) {
113120
break;
114121

115122
case MSG_SET_GENERATION_ID:
116-
if (mWidgetCallbacks != null) {
117-
boolean clearing = msg.arg2 != 0;
118-
if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + clearing);
119-
if (!clearing) {
120-
mWidgetCallbacks.requestShow(TransportControlView.this);
121-
} else {
122-
mWidgetCallbacks.requestHide(TransportControlView.this);
123-
}
123+
if (msg.arg2 != 0) {
124+
mClearOnNextShow = true; // TODO: handle this
124125
}
126+
if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
125127
mClientGeneration = msg.arg1;
126128
mClientIntent = (PendingIntent) msg.obj;
127129
break;
@@ -195,6 +197,7 @@ public TransportControlView(Context context, AttributeSet attrs) {
195197
super(context, attrs);
196198
Log.v(TAG, "Create TCV " + this);
197199
mAudioManager = new AudioManager(mContext);
200+
mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
198201
mIRCD = new IRemoteControlDisplayWeak(mHandler);
199202
}
200203

@@ -319,7 +322,7 @@ private void populateMetadata() {
319322
| RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
320323
| RemoteControlClient.FLAG_KEY_MEDIA_STOP);
321324

322-
updatePlayPauseState(mPlayState);
325+
updatePlayPauseState(mCurrentPlayState);
323326
}
324327

325328
private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
@@ -332,32 +335,92 @@ private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
332335

333336
private void updatePlayPauseState(int state) {
334337
if (DEBUG) Log.v(TAG,
335-
"updatePlayPauseState(), old=" + mPlayState + ", state=" + state);
336-
if (state == mPlayState) {
338+
"updatePlayPauseState(), old=" + mCurrentPlayState + ", state=" + state);
339+
if (state == mCurrentPlayState) {
337340
return;
338341
}
339342
final int imageResId;
340343
final int imageDescId;
344+
final boolean showIfHidden;
341345
switch (state) {
342346
case RemoteControlClient.PLAYSTATE_PLAYING:
343347
imageResId = com.android.internal.R.drawable.ic_media_pause;
344348
imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description;
349+
showIfHidden = true;
345350
break;
346351

347352
case RemoteControlClient.PLAYSTATE_BUFFERING:
348353
imageResId = com.android.internal.R.drawable.ic_media_stop;
349354
imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description;
355+
showIfHidden = true;
350356
break;
351357

352358
case RemoteControlClient.PLAYSTATE_PAUSED:
353359
default:
354360
imageResId = com.android.internal.R.drawable.ic_media_play;
355361
imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
362+
showIfHidden = false;
356363
break;
357364
}
358365
mBtnPlay.setImageResource(imageResId);
359366
mBtnPlay.setContentDescription(getResources().getString(imageDescId));
360-
mPlayState = state;
367+
if (showIfHidden && mWidgetCallbacks != null && !mWidgetCallbacks.isVisible(this)) {
368+
mWidgetCallbacks.requestShow(this);
369+
}
370+
mCurrentPlayState = state;
371+
}
372+
373+
static class SavedState extends BaseSavedState {
374+
boolean wasShowing;
375+
376+
SavedState(Parcelable superState) {
377+
super(superState);
378+
}
379+
380+
private SavedState(Parcel in) {
381+
super(in);
382+
this.wasShowing = in.readInt() != 0;
383+
}
384+
385+
@Override
386+
public void writeToParcel(Parcel out, int flags) {
387+
super.writeToParcel(out, flags);
388+
out.writeInt(this.wasShowing ? 1 : 0);
389+
}
390+
391+
public static final Parcelable.Creator<SavedState> CREATOR
392+
= new Parcelable.Creator<SavedState>() {
393+
public SavedState createFromParcel(Parcel in) {
394+
return new SavedState(in);
395+
}
396+
397+
public SavedState[] newArray(int size) {
398+
return new SavedState[size];
399+
}
400+
};
401+
}
402+
403+
@Override
404+
public Parcelable onSaveInstanceState() {
405+
if (DEBUG) Log.v(TAG, "onSaveInstanceState()");
406+
Parcelable superState = super.onSaveInstanceState();
407+
SavedState ss = new SavedState(superState);
408+
ss.wasShowing = mWidgetCallbacks.isVisible(this);
409+
return ss;
410+
}
411+
412+
@Override
413+
public void onRestoreInstanceState(Parcelable state) {
414+
if (DEBUG) Log.v(TAG, "onRestoreInstanceState()");
415+
if (!(state instanceof SavedState)) {
416+
super.onRestoreInstanceState(state);
417+
return;
418+
}
419+
SavedState ss = (SavedState) state;
420+
super.onRestoreInstanceState(ss.getSuperState());
421+
if (ss.wasShowing) {
422+
mWidgetCallbacks.requestShow(this);
423+
}
361424
}
362425

363426
public void onClick(View v) {

policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import android.os.Handler;
5050
import android.os.Message;
5151
import android.os.IBinder;
52+
import android.os.Parcelable;
5253
import android.os.RemoteException;
5354
import android.os.SystemClock;
5455
import android.os.SystemProperties;
@@ -221,6 +222,7 @@ enum UnlockMode {
221222
private Runnable mRecreateRunnable = new Runnable() {
222223
public void run() {
223224
updateScreen(mMode, true);
225+
restoreWidgetState();
224226
}
225227
};
226228

@@ -244,8 +246,20 @@ public void requestHide(View view) {
244246
// TODO: examine all widgets to derive clock status
245247
mUpdateMonitor.reportClockVisible(true);
246248
}
249+
250+
public boolean isVisible(View self) {
251+
// TODO: this should be up to the lockscreen to determine if the view
252+
// is currently showing. The idea is it can be used for the widget to
253+
// avoid doing work if it's not visible. For now just returns the view's
254+
// actual visibility.
255+
return self.getVisibility() == View.VISIBLE;
256+
}
247257
};
248258

259+
private TransportControlView mTransportControlView;
260+
261+
private Parcelable mSavedState;
262+
249263
/**
250264
* @return Whether we are stuck on the lock screen because the sim is
251265
* missing.
@@ -365,6 +379,7 @@ public void pokeWakelock(int millis) {
365379

366380
public void keyguardDone(boolean authenticated) {
367381
getCallback().keyguardDone(authenticated);
382+
mSavedState = null; // clear state so we re-establish when locked again
368383
}
369384

370385
public void keyguardDoneDrawing() {
@@ -528,6 +543,8 @@ public void onScreenTurnedOff() {
528543
((KeyguardScreen) mUnlockScreen).onPause();
529544
}
530545

546+
saveWidgetState();
547+
531548
// When screen is turned off, need to unbind from FaceLock service if using FaceLock
532549
stopAndUnbindFromFaceLock();
533550
}
@@ -558,8 +575,28 @@ public void onScreenTurnedOn() {
558575
mScreenOn = true;
559576
runFaceLock = mWindowFocused;
560577
}
578+
561579
show();
562-
if(runFaceLock) activateFaceLockIfAble();
580+
581+
restoreWidgetState();
582+
583+
if (runFaceLock) activateFaceLockIfAble();
584+
}
585+
586+
private void saveWidgetState() {
587+
if (mTransportControlView != null) {
588+
if (DEBUG) Log.v(TAG, "Saving widget state");
589+
mSavedState = mTransportControlView.onSaveInstanceState();
590+
}
591+
}
592+
593+
private void restoreWidgetState() {
594+
if (mTransportControlView != null) {
595+
if (DEBUG) Log.v(TAG, "Restoring widget state");
596+
if (mSavedState != null) {
597+
mTransportControlView.onRestoreInstanceState(mSavedState);
598+
}
599+
}
563600
}
564601

565602
/** Unbind from facelock if something covers this window (such as an alarm)
@@ -643,6 +680,7 @@ protected void onConfigurationChanged(Configuration newConfig) {
643680
mShowLockBeforeUnlock = resources.getBoolean(R.bool.config_enableLockBeforeUnlockScreen);
644681
mConfiguration = newConfig;
645682
if (DEBUG_CONFIGURATION) Log.v(TAG, "**** re-creating lock screen since config changed");
683+
saveWidgetState();
646684
removeCallbacks(mRecreateRunnable);
647685
post(mRecreateRunnable);
648686
}
@@ -895,13 +933,13 @@ View createUnlockScreenFor(UnlockMode unlockMode) {
895933
}
896934

897935
private void initializeTransportControlView(View view) {
898-
TransportControlView tcv = (TransportControlView) view.findViewById(R.id.transport);
899-
if (tcv == null) {
936+
mTransportControlView = (TransportControlView) view.findViewById(R.id.transport);
937+
if (mTransportControlView == null) {
900938
if (DEBUG) Log.w(TAG, "Couldn't find transport control widget");
901939
} else {
902940
mUpdateMonitor.reportClockVisible(true);
903-
tcv.setVisibility(View.GONE); // hide until it requests being shown.
904-
tcv.setCallback(mWidgetCallback);
941+
mTransportControlView.setVisibility(View.GONE); // hide until it requests being shown.
942+
mTransportControlView.setCallback(mWidgetCallback);
905943
}
906944
}
907945

0 commit comments

Comments
 (0)