Skip to content

Commit 223ce5c

Browse files
author
Jim Miller
committed
Implement music and user priority scheme in keyguard
This fixes an issue where the music transport hangs around indefinitely. It used to get dismissed when music stopped playing and a notification came in. This was due to a bug in JB. Now that the bug is fixed, the music control hangs around indefinitely until the application actually releases it. Since we have widget support, we can now leave the transport control in place for as long as it's possible to resume music (state = playing | paused). If music is playing, we start with the trasport showing If not, and multi-user is enabled for more than one user, we show the user switcher. Otherwise, we show the clock. Bug 7290707 Change-Id: I6f0553a64b7b66bac7b35eca6d8a8793c15b918c
1 parent eb7f157 commit 223ce5c

File tree

3 files changed

+139
-48
lines changed

3 files changed

+139
-48
lines changed

policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java

Lines changed: 104 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import android.graphics.Canvas;
3434
import android.graphics.Rect;
3535
import android.os.Looper;
36+
import android.os.Parcel;
37+
import android.os.Parcelable;
3638
import android.os.UserManager;
3739
import android.util.AttributeSet;
3840
import android.util.Log;
@@ -43,12 +45,14 @@
4345
import android.view.View;
4446
import android.view.ViewGroup;
4547
import android.view.WindowManager;
48+
import android.view.View.BaseSavedState;
4649
import android.view.animation.AnimationUtils;
4750
import android.widget.RemoteViews.OnClickHandler;
4851
import android.widget.ViewFlipper;
4952

5053
import com.android.internal.R;
5154
import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
55+
import com.android.internal.policy.impl.keyguard.KeyguardTransportControlView.SavedState;
5256
import com.android.internal.widget.LockPatternUtils;
5357

5458
import java.io.File;
@@ -64,6 +68,10 @@ public class KeyguardHostView extends KeyguardViewBase {
6468
static final int APPWIDGET_HOST_ID = 0x4B455947;
6569
private static final String KEYGUARD_WIDGET_PREFS = "keyguard_widget_prefs";
6670

71+
private static final int TRANSPORT_GONE = 0;
72+
private static final int TRANSPORT_INVISIBLE = 1;
73+
private static final int TRANSPORT_VISIBLE = 2;
74+
6775
private AppWidgetHost mAppWidgetHost;
6876
private KeyguardWidgetRegion mAppWidgetRegion;
6977
private KeyguardWidgetPager mAppWidgetContainer;
@@ -83,10 +91,12 @@ public class KeyguardHostView extends KeyguardViewBase {
8391
private KeyguardSecurityModel mSecurityModel;
8492

8593
private Rect mTempRect = new Rect();
94+
private int mTransportState = TRANSPORT_GONE;
8695

8796
/*package*/ interface TransportCallback {
88-
void hide();
89-
void show();
97+
void onListenerDetached();
98+
void onListenerAttached();
99+
void onPlayStateChanged();
90100
}
91101

92102
/*package*/ interface UserSwitcherCallback {
@@ -185,7 +195,7 @@ protected void onAttachedToWindow() {
185195
mAppWidgetHost.startListening();
186196
maybePopulateWidgets();
187197
disableStatusViewInteraction();
188-
showAppropriateWidgetPage();
198+
post(mSwitchPageRunnable);
189199
}
190200

191201
private void disableStatusViewInteraction() {
@@ -712,7 +722,7 @@ private void addWidget(int appId) {
712722
private void addDefaultWidgets() {
713723
LayoutInflater inflater = LayoutInflater.from(mContext);
714724
inflater.inflate(R.layout.keyguard_status_view, mAppWidgetContainer, true);
715-
inflater.inflate(R.layout.keyguard_transport_control_view, mAppWidgetContainer, true);
725+
inflater.inflate(R.layout.keyguard_transport_control_view, this, true);
716726

717727
inflateAndAddUserSelectorWidgetIfNecessary();
718728
initializeTransportControl();
@@ -721,16 +731,16 @@ private void addDefaultWidgets() {
721731
private void initializeTransportControl() {
722732
mTransportControl =
723733
(KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
734+
mTransportControl.setVisibility(View.GONE);
724735

725736
// This code manages showing/hiding the transport control. We keep it around and only
726737
// add it to the hierarchy if it needs to be present.
727738
if (mTransportControl != null) {
728739
mTransportControl.setKeyguardCallback(new TransportCallback() {
729-
boolean mSticky = false;
730740
@Override
731-
public void hide() {
741+
public void onListenerDetached() {
732742
int page = getWidgetPosition(R.id.keyguard_transport_control);
733-
if (page != -1 && !mSticky) {
743+
if (page != -1) {
734744
if (page == mAppWidgetContainer.getCurrentPage()) {
735745
// Switch back to clock view if music was showing.
736746
mAppWidgetContainer
@@ -741,20 +751,23 @@ public void hide() {
741751
// from AudioManager
742752
KeyguardHostView.this.addView(mTransportControl);
743753
mTransportControl.setVisibility(View.GONE);
754+
mTransportState = TRANSPORT_GONE;
744755
}
745756
}
746757

747758
@Override
748-
public void show() {
759+
public void onListenerAttached() {
749760
if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
750761
KeyguardHostView.this.removeView(mTransportControl);
751-
mAppWidgetContainer.addView(mTransportControl,
752-
getWidgetPosition(R.id.keyguard_status_view) + 1);
762+
mAppWidgetContainer.addView(mTransportControl, 0);
753763
mTransportControl.setVisibility(View.VISIBLE);
754-
// Once shown, leave it showing
755-
mSticky = true;
756764
}
757765
}
766+
767+
@Override
768+
public void onPlayStateChanged() {
769+
mTransportControl.post(mSwitchPageRunnable);
770+
}
758771
});
759772
}
760773
}
@@ -796,12 +809,87 @@ private void maybePopulateWidgets() {
796809
}
797810
}
798811

812+
Runnable mSwitchPageRunnable = new Runnable() {
813+
@Override
814+
public void run() {
815+
showAppropriateWidgetPage();
816+
}
817+
};
818+
819+
static class SavedState extends BaseSavedState {
820+
int transportState;
821+
822+
SavedState(Parcelable superState) {
823+
super(superState);
824+
}
825+
826+
private SavedState(Parcel in) {
827+
super(in);
828+
this.transportState = in.readInt();
829+
}
830+
831+
@Override
832+
public void writeToParcel(Parcel out, int flags) {
833+
super.writeToParcel(out, flags);
834+
out.writeInt(this.transportState);
835+
}
836+
837+
public static final Parcelable.Creator<SavedState> CREATOR
838+
= new Parcelable.Creator<SavedState>() {
839+
public SavedState createFromParcel(Parcel in) {
840+
return new SavedState(in);
841+
}
842+
843+
public SavedState[] newArray(int size) {
844+
return new SavedState[size];
845+
}
846+
};
847+
}
848+
849+
@Override
850+
public Parcelable onSaveInstanceState() {
851+
Parcelable superState = super.onSaveInstanceState();
852+
SavedState ss = new SavedState(superState);
853+
ss.transportState = mTransportState;
854+
return ss;
855+
}
856+
857+
@Override
858+
public void onRestoreInstanceState(Parcelable state) {
859+
if (!(state instanceof SavedState)) {
860+
super.onRestoreInstanceState(state);
861+
return;
862+
}
863+
SavedState ss = (SavedState) state;
864+
super.onRestoreInstanceState(ss.getSuperState());
865+
mTransportState = ss.transportState;
866+
post(mSwitchPageRunnable);
867+
}
868+
799869
private void showAppropriateWidgetPage() {
800-
int page = mAppWidgetContainer.indexOfChild(findViewById(R.id.keyguard_status_view));
801-
if (mAppWidgetContainer.indexOfChild(mTransportControl) != -1) {
802-
page = mAppWidgetContainer.indexOfChild(mTransportControl);
870+
871+
// The following sets the priority for showing widgets. Transport should be shown if
872+
// music is playing, followed by the multi-user widget if enabled, followed by the
873+
// status widget.
874+
final int pageToShow;
875+
if (mTransportControl.isMusicPlaying() || mTransportState == TRANSPORT_VISIBLE) {
876+
mTransportState = TRANSPORT_VISIBLE;
877+
pageToShow = mAppWidgetContainer.indexOfChild(mTransportControl);
878+
} else {
879+
UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
880+
final View multiUserView = findViewById(R.id.keyguard_multi_user_selector);
881+
final int multiUserPosition = mAppWidgetContainer.indexOfChild(multiUserView);
882+
if (multiUserPosition != -1 && mUm.getUsers(true).size() > 1) {
883+
pageToShow = multiUserPosition;
884+
} else {
885+
final View statusView = findViewById(R.id.keyguard_status_view);
886+
pageToShow = mAppWidgetContainer.indexOfChild(statusView);
887+
}
888+
if (mTransportState == TRANSPORT_VISIBLE) {
889+
mTransportState = TRANSPORT_INVISIBLE;
890+
}
803891
}
804-
mAppWidgetContainer.setCurrentPage(page);
892+
mAppWidgetContainer.setCurrentPage(pageToShow);
805893
}
806894

807895
private void inflateAndAddUserSelectorWidgetIfNecessary() {

policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
import android.view.KeyEvent;
4343
import android.view.View;
4444
import android.view.View.OnClickListener;
45-
import android.widget.FrameLayout;
4645
import android.widget.ImageView;
4746
import android.widget.TextView;
4847

@@ -59,7 +58,7 @@ public class KeyguardTransportControlView extends KeyguardWidgetFrame implements
5958
private static final int MSG_SET_GENERATION_ID = 104;
6059
private static final int MAXDIM = 512;
6160
private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
62-
protected static final boolean DEBUG = false;
61+
protected static final boolean DEBUG = true;
6362
protected static final String TAG = "TransportControlView";
6463

6564
private ImageView mAlbumArt;
@@ -75,6 +74,7 @@ public class KeyguardTransportControlView extends KeyguardWidgetFrame implements
7574
private int mCurrentPlayState;
7675
private AudioManager mAudioManager;
7776
private IRemoteControlDisplayWeak mIRCD;
77+
private boolean mMusicClientPresent = true;
7878

7979
/**
8080
* The metadata which should be populated into the view once we've been attached
@@ -112,7 +112,9 @@ public void handleMessage(Message msg) {
112112
case MSG_SET_GENERATION_ID:
113113
if (msg.arg2 != 0) {
114114
// This means nobody is currently registered. Hide the view.
115-
hide();
115+
onListenerDetached();
116+
} else {
117+
onListenerAttached();
116118
}
117119
if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
118120
mClientGeneration = msg.arg1;
@@ -193,28 +195,26 @@ public KeyguardTransportControlView(Context context, AttributeSet attrs) {
193195
mIRCD = new IRemoteControlDisplayWeak(mHandler);
194196
}
195197

196-
protected void hide() {
197-
if (DEBUG) Log.v(TAG, "Transport was told to hide");
198+
protected void onListenerDetached() {
199+
mMusicClientPresent = false;
200+
if (DEBUG) Log.v(TAG, "onListenerDetached()");
198201
if (mTransportCallback != null) {
199-
mTransportCallback.hide();
202+
mTransportCallback.onListenerDetached();
200203
} else {
201-
Log.w(TAG, "Hide music, but callback wasn't set");
204+
Log.w(TAG, "onListenerDetached: no callback");
202205
}
203206
}
204207

205-
private void show() {
206-
if (DEBUG) Log.v(TAG, "Transport was told to show");
208+
private void onListenerAttached() {
209+
mMusicClientPresent = true;
210+
if (DEBUG) Log.v(TAG, "onListenerAttached()");
207211
if (mTransportCallback != null) {
208-
mTransportCallback.show();
212+
mTransportCallback.onListenerAttached();
209213
} else {
210-
Log.w(TAG, "Show music, but callback wasn't set");
214+
Log.w(TAG, "onListenerAttached(): no callback");
211215
}
212216
}
213217

214-
private void userActivity() {
215-
// TODO Auto-generated method stub
216-
}
217-
218218
private void updateTransportControls(int transportControlFlags) {
219219
mTransportControlFlags = transportControlFlags;
220220
}
@@ -341,6 +341,11 @@ private void populateMetadata() {
341341
updatePlayPauseState(mCurrentPlayState);
342342
}
343343

344+
public boolean isMusicPlaying() {
345+
return mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING
346+
|| mCurrentPlayState == RemoteControlClient.PLAYSTATE_BUFFERING;
347+
}
348+
344349
private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
345350
if ((flags & flag) != 0) {
346351
view.setVisibility(View.VISIBLE);
@@ -357,7 +362,6 @@ private void updatePlayPauseState(int state) {
357362
}
358363
final int imageResId;
359364
final int imageDescId;
360-
boolean showIfHidden = false;
361365
switch (state) {
362366
case RemoteControlClient.PLAYSTATE_ERROR:
363367
imageResId = com.android.internal.R.drawable.stat_sys_warning;
@@ -369,46 +373,41 @@ private void updatePlayPauseState(int state) {
369373
case RemoteControlClient.PLAYSTATE_PLAYING:
370374
imageResId = com.android.internal.R.drawable.ic_media_pause;
371375
imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description;
372-
showIfHidden = true;
373376
break;
374377

375378
case RemoteControlClient.PLAYSTATE_BUFFERING:
376379
imageResId = com.android.internal.R.drawable.ic_media_stop;
377380
imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description;
378-
showIfHidden = true;
379381
break;
380382

381383
case RemoteControlClient.PLAYSTATE_PAUSED:
382384
default:
383385
imageResId = com.android.internal.R.drawable.ic_media_play;
384386
imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
385-
showIfHidden = false;
386387
break;
387388
}
388389
mBtnPlay.setImageResource(imageResId);
389390
mBtnPlay.setContentDescription(getResources().getString(imageDescId));
390-
if (showIfHidden) {
391-
show();
392-
}
393391
mCurrentPlayState = state;
392+
mTransportCallback.onPlayStateChanged();
394393
}
395394

396395
static class SavedState extends BaseSavedState {
397-
boolean wasShowing;
396+
boolean clientPresent;
398397

399398
SavedState(Parcelable superState) {
400399
super(superState);
401400
}
402401

403402
private SavedState(Parcel in) {
404403
super(in);
405-
this.wasShowing = in.readInt() != 0;
404+
this.clientPresent = in.readInt() != 0;
406405
}
407406

408407
@Override
409408
public void writeToParcel(Parcel out, int flags) {
410409
super.writeToParcel(out, flags);
411-
out.writeInt(this.wasShowing ? 1 : 0);
410+
out.writeInt(this.clientPresent ? 1 : 0);
412411
}
413412

414413
public static final Parcelable.Creator<SavedState> CREATOR
@@ -425,24 +424,23 @@ public SavedState[] newArray(int size) {
425424

426425
@Override
427426
public Parcelable onSaveInstanceState() {
428-
if (DEBUG) Log.v(TAG, "onSaveInstanceState()");
429427
Parcelable superState = super.onSaveInstanceState();
430428
SavedState ss = new SavedState(superState);
431-
ss.wasShowing = getVisibility() == View.VISIBLE;
429+
ss.clientPresent = mMusicClientPresent;
432430
return ss;
433431
}
434432

435433
@Override
436434
public void onRestoreInstanceState(Parcelable state) {
437-
if (DEBUG) Log.v(TAG, "onRestoreInstanceState()");
438435
if (!(state instanceof SavedState)) {
439436
super.onRestoreInstanceState(state);
440437
return;
441438
}
442439
SavedState ss = (SavedState) state;
443440
super.onRestoreInstanceState(ss.getSuperState());
444-
if (ss.wasShowing) {
445-
show();
441+
if (ss.clientPresent) {
442+
if (DEBUG) Log.v(TAG, "Reattaching client because it was attached");
443+
onListenerAttached();
446444
}
447445
}
448446

@@ -458,7 +456,6 @@ public void onClick(View v) {
458456
}
459457
if (keyCode != -1) {
460458
sendMediaButtonClick(keyCode);
461-
userActivity();
462459
}
463460
}
464461

0 commit comments

Comments
 (0)