am b3ba365c: Merge "Use persistent IRCD in KeyguardUpdateMonitor to show/hide music" into jb-mr2-dev

* commit 'b3ba365c5c293dd0b82def17f1b5a5c3a6efec03':
  Use persistent IRCD in KeyguardUpdateMonitor to show/hide music
This commit is contained in:
Jim Miller
2013-03-20 00:06:14 +00:00
committed by Android Git Automerger
5 changed files with 214 additions and 158 deletions

View File

@@ -35,6 +35,7 @@ import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.media.RemoteControlClient;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
@@ -55,6 +56,7 @@ import android.widget.RemoteViews.OnClickHandler;
import com.android.internal.R;
import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.internal.policy.impl.keyguard.KeyguardUpdateMonitor.DisplayClientState;
import com.android.internal.widget.LockPatternUtils;
import java.io.File;
@@ -62,9 +64,16 @@ import java.util.List;
public class KeyguardHostView extends KeyguardViewBase {
private static final String TAG = "KeyguardHostView";
// transport control states
static final int TRANSPORT_GONE = 0;
static final int TRANSPORT_INVISIBLE = 1;
static final int TRANSPORT_VISIBLE = 2;
private int mTransportState = TRANSPORT_GONE;
// Use this to debug all of keyguard
public static boolean DEBUG = KeyguardViewMediator.DEBUG;
public static boolean DEBUGXPORT = true; // debug music transport control
// Found in KeyguardAppWidgetPickActivity.java
static final int APPWIDGET_HOST_ID = 0x4B455947;
@@ -109,11 +118,8 @@ public class KeyguardHostView extends KeyguardViewBase {
private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView;
/*package*/ interface TransportCallback {
void onListenerDetached();
void onListenerAttached();
void onPlayStateChanged();
}
protected int mPlaybackState;
protected int mClientGeneration;
/*package*/ interface UserSwitcherCallback {
void hideSecurityView(int duration);
@@ -183,6 +189,9 @@ public class KeyguardHostView extends KeyguardViewBase {
mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
// Ensure we have the current state *before* we call showAppropriateWidgetPage()
getInitialTransportState();
if (mSafeModeEnabled) {
Log.v(TAG, "Keyguard widgets disabled by safe mode");
}
@@ -194,6 +203,14 @@ public class KeyguardHostView extends KeyguardViewBase {
}
}
private void getInitialTransportState() {
DisplayClientState dcs = KeyguardUpdateMonitor.getInstance(mContext)
.getCachedDisplayClientState();
mTransportState = (dcs.clearing ? TRANSPORT_GONE :
(isMusicPlaying(dcs.playbackState) ? TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
mPlaybackState = dcs.playbackState;
}
private void cleanupAppWidgetIds() {
// Since this method may delete a widget (which we can't do until boot completed) we
// may have to defer it until after boot complete.
@@ -249,8 +266,44 @@ public class KeyguardHostView extends KeyguardViewBase {
mKeyguardMultiUserSelectorView.finalizeActiveUserView(true);
}
}
@Override
void onMusicClientIdChanged(
int clientGeneration, boolean clearing, android.app.PendingIntent intent) {
// Set transport state to invisible until we know music is playing (below)
if (DEBUGXPORT && (mClientGeneration != clientGeneration || clearing)) {
Log.v(TAG, (clearing ? "hide" : "show") + " transport, gen:" + clientGeneration);
}
mClientGeneration = clientGeneration;
mTransportState = (clearing ? TRANSPORT_GONE : TRANSPORT_INVISIBLE);
KeyguardHostView.this.post(mSwitchPageRunnable);
}
@Override
public void onMusicPlaybackStateChanged(int playbackState, long eventTime) {
mPlaybackState = playbackState;
if (DEBUGXPORT) Log.v(TAG, "music state changed: " + playbackState);
if (mTransportState != TRANSPORT_GONE) {
mTransportState = (isMusicPlaying(mPlaybackState) ?
TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE);
}
KeyguardHostView.this.post(mSwitchPageRunnable);
}
};
private static final boolean isMusicPlaying(int playbackState) {
// This should agree with the list in AudioService.isPlaystateActive()
switch (playbackState) {
case RemoteControlClient.PLAYSTATE_PLAYING:
case RemoteControlClient.PLAYSTATE_BUFFERING:
case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
case RemoteControlClient.PLAYSTATE_REWINDING:
case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
return true;
default:
return false;
}
}
private SlidingChallengeLayout mSlidingChallengeLayout;
@Override
@@ -1125,10 +1178,8 @@ public class KeyguardHostView extends KeyguardViewBase {
}
private void addDefaultWidgets() {
LayoutInflater inflater = LayoutInflater.from(mContext);
inflater.inflate(R.layout.keyguard_transport_control_view, this, true);
if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false);
mAppWidgetContainer.addWidget(addWidget, 0);
View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view);
@@ -1154,66 +1205,19 @@ public class KeyguardHostView extends KeyguardViewBase {
}
enableUserSelectorIfNecessary();
initializeTransportControl();
}
private boolean removeTransportFromWidgetPager() {
int page = getWidgetPosition(R.id.keyguard_transport_control);
if (page != -1) {
mAppWidgetContainer.removeWidget(mTransportControl);
// XXX keep view attached so we still get show/hide events from AudioManager
KeyguardHostView.this.addView(mTransportControl);
mTransportControl.setVisibility(View.GONE);
mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_GONE);
return true;
}
return false;
}
private void addTransportToWidgetPager() {
if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
KeyguardHostView.this.removeView(mTransportControl);
// insert to left of camera if it exists, otherwise after right-most widget
int lastWidget = mAppWidgetContainer.getChildCount() - 1;
int position = 0; // handle no widget case
if (lastWidget >= 0) {
position = mAppWidgetContainer.isCameraPage(lastWidget) ?
lastWidget : lastWidget + 1;
}
mAppWidgetContainer.addWidget(mTransportControl, position);
mTransportControl.setVisibility(View.VISIBLE);
}
}
private void initializeTransportControl() {
mTransportControl =
(KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
mTransportControl.setVisibility(View.GONE);
// This code manages showing/hiding the transport control. We keep it around and only
// add it to the hierarchy if it needs to be present.
if (mTransportControl != null) {
mTransportControl.setKeyguardCallback(new TransportCallback() {
@Override
public void onListenerDetached() {
if (removeTransportFromWidgetPager()) {
mTransportControl.post(mSwitchPageRunnable);
}
}
@Override
public void onListenerAttached() {
// Transport will be added when playstate changes...
mTransportControl.post(mSwitchPageRunnable);
}
@Override
public void onPlayStateChanged() {
mTransportControl.post(mSwitchPageRunnable);
}
});
/**
* Create KeyguardTransportControlView on demand.
* @return
*/
private KeyguardTransportControlView getTransportControlView() {
if (mTransportControl == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
mTransportControl = (KeyguardTransportControlView)
inflater.inflate(R.layout.keyguard_transport_control_view, this, false);
}
return mTransportControl;
}
private int getInsertPageIndex() {
@@ -1385,7 +1389,7 @@ public class KeyguardHostView extends KeyguardViewBase {
if (DEBUG) Log.d(TAG, "onSaveInstanceState");
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.transportState = mViewStateManager.getTransportState();
ss.transportState = mTransportState;
ss.appWidgetToShow = mAppWidgetToShow;
return ss;
}
@@ -1399,7 +1403,7 @@ public class KeyguardHostView extends KeyguardViewBase {
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
mViewStateManager.setTransportState(ss.transportState);
mTransportState = (ss.transportState);
mAppWidgetToShow = ss.appWidgetToShow;
post(mSwitchPageRunnable);
}
@@ -1420,19 +1424,33 @@ public class KeyguardHostView extends KeyguardViewBase {
}
private void showAppropriateWidgetPage() {
int state = mViewStateManager.getTransportState();
boolean isMusicPlaying = mTransportControl.isMusicPlaying()
|| state == KeyguardViewStateManager.TRANSPORT_VISIBLE;
if (isMusicPlaying) {
mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_VISIBLE);
addTransportToWidgetPager();
} else if (state == KeyguardViewStateManager.TRANSPORT_VISIBLE) {
mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_INVISIBLE);
}
int pageToShow = getAppropriateWidgetPage(isMusicPlaying);
int state = mTransportState;
ensureTransportPresentOrRemoved(state);
int pageToShow = getAppropriateWidgetPage(state);
mAppWidgetContainer.setCurrentPage(pageToShow);
}
private void ensureTransportPresentOrRemoved(int state) {
int page = getWidgetPosition(R.id.keyguard_transport_control);
if (state == TRANSPORT_INVISIBLE || state == TRANSPORT_VISIBLE) {
if (page == -1) {
if (DEBUGXPORT) Log.v(TAG, "add transport");
// insert to left of camera if it exists, otherwise after right-most widget
int lastWidget = mAppWidgetContainer.getChildCount() - 1;
int position = 0; // handle no widget case
if (lastWidget >= 0) {
position = mAppWidgetContainer.isCameraPage(lastWidget) ?
lastWidget : lastWidget + 1;
}
mAppWidgetContainer.addWidget(getTransportControlView(), position);
}
} else if (page != -1) {
if (DEBUGXPORT) Log.v(TAG, "remove transport");
mAppWidgetContainer.removeWidget(getTransportControlView());
mTransportControl = null;
}
}
private CameraWidgetFrame findCameraPage() {
for (int i = mAppWidgetContainer.getChildCount() - 1; i >= 0; i--) {
if (mAppWidgetContainer.isCameraPage(i)) {
@@ -1446,7 +1464,7 @@ public class KeyguardHostView extends KeyguardViewBase {
return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control);
}
private int getAppropriateWidgetPage(boolean isMusicPlaying) {
private int getAppropriateWidgetPage(int musicTransportState) {
// assumes at least one widget (besides camera + add)
if (mAppWidgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
final int childCount = mAppWidgetContainer.getChildCount();
@@ -1459,9 +1477,9 @@ public class KeyguardHostView extends KeyguardViewBase {
mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
}
// if music playing, show transport
if (isMusicPlaying) {
if (musicTransportState == TRANSPORT_VISIBLE) {
if (DEBUG) Log.d(TAG, "Music playing, show transport");
return mAppWidgetContainer.getWidgetPageIndex(mTransportControl);
return mAppWidgetContainer.getWidgetPageIndex(getTransportControlView());
}
// else show the right-most widget (except for camera)

View File

@@ -74,7 +74,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick
private int mCurrentPlayState;
private AudioManager mAudioManager;
private IRemoteControlDisplayWeak mIRCD;
private boolean mMusicClientPresent = true;
/**
* The metadata which should be populated into the view once we've been attached
@@ -110,12 +109,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick
break;
case MSG_SET_GENERATION_ID:
if (msg.arg2 != 0) {
// This means nobody is currently registered. Hide the view.
onListenerDetached();
} else {
onListenerAttached();
}
if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
mClientGeneration = msg.arg1;
mClientIntent = (PendingIntent) msg.obj;
@@ -124,7 +117,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick
}
}
};
private KeyguardHostView.TransportCallback mTransportCallback;
/**
* This class is required to have weak linkage to the current TransportControlView
@@ -195,26 +187,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick
mIRCD = new IRemoteControlDisplayWeak(mHandler);
}
protected void onListenerDetached() {
mMusicClientPresent = false;
if (DEBUG) Log.v(TAG, "onListenerDetached()");
if (mTransportCallback != null) {
mTransportCallback.onListenerDetached();
} else {
Log.w(TAG, "onListenerDetached: no callback");
}
}
private void onListenerAttached() {
mMusicClientPresent = true;
if (DEBUG) Log.v(TAG, "onListenerAttached()");
if (mTransportCallback != null) {
mTransportCallback.onListenerAttached();
} else {
Log.w(TAG, "onListenerAttached(): no callback");
}
}
private void updateTransportControls(int transportControlFlags) {
mTransportControlFlags = transportControlFlags;
}
@@ -342,11 +314,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick
updatePlayPauseState(mCurrentPlayState);
}
public boolean isMusicPlaying() {
return mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING
|| mCurrentPlayState == RemoteControlClient.PLAYSTATE_BUFFERING;
}
private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
if ((flags & flag) != 0) {
view.setVisibility(View.VISIBLE);
@@ -390,7 +357,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick
mBtnPlay.setImageResource(imageResId);
mBtnPlay.setContentDescription(getResources().getString(imageDescId));
mCurrentPlayState = state;
mTransportCallback.onPlayStateChanged();
}
static class SavedState extends BaseSavedState {
@@ -423,28 +389,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick
};
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.clientPresent = mMusicClientPresent;
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
if (ss.clientPresent) {
if (DEBUG) Log.v(TAG, "Reattaching client because it was attached");
onListenerAttached();
}
}
public void onClick(View v) {
int keyCode = -1;
if (v == mBtnPrev) {
@@ -522,8 +466,4 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick
return false;
}
}
public void setKeyguardCallback(KeyguardHostView.TransportCallback transportCallback) {
mTransportCallback = transportCallback;
}
}

View File

@@ -18,12 +18,15 @@ package com.android.internal.policy.impl.keyguard;
import android.app.ActivityManagerNative;
import android.app.IUserSwitchObserver;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import static android.os.BatteryManager.BATTERY_STATUS_FULL;
import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
@@ -32,7 +35,9 @@ import static android.os.BatteryManager.EXTRA_PLUGGED;
import static android.os.BatteryManager.EXTRA_LEVEL;
import static android.os.BatteryManager.EXTRA_HEALTH;
import android.media.AudioManager;
import android.media.IRemoteControlDisplay;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Message;
@@ -84,6 +89,8 @@ public class KeyguardUpdateMonitor {
private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312;
protected static final int MSG_BOOT_COMPLETED = 313;
private static final int MSG_USER_SWITCH_COMPLETE = 314;
private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
protected static final int MSG_SET_PLAYBACK_STATE = 316;
private static KeyguardUpdateMonitor sInstance;
@@ -163,11 +170,66 @@ public class KeyguardUpdateMonitor {
case MSG_BOOT_COMPLETED:
handleBootCompleted();
break;
case MSG_SET_CURRENT_CLIENT_ID:
handleSetGenerationId(msg.arg1, msg.arg2 != 0, (PendingIntent) msg.obj);
break;
case MSG_SET_PLAYBACK_STATE:
handleSetPlaybackState(msg.arg1, msg.arg2, (Long) msg.obj);
break;
}
}
};
private AudioManager mAudioManager;
static class DisplayClientState {
public int clientGeneration;
public boolean clearing;
public PendingIntent intent;
public int playbackState;
public long playbackEventTime;
}
private DisplayClientState mDisplayClientState = new DisplayClientState();
/**
* This currently implements the bare minimum required to enable showing and hiding
* KeyguardTransportControl. There's a lot of client state to maintain which is why
* KeyguardTransportControl maintains an independent connection while it's showing.
*/
private final IRemoteControlDisplay.Stub mRemoteControlDisplay =
new IRemoteControlDisplay.Stub() {
public void setPlaybackState(int generationId, int state, long stateChangeTimeMs) {
Message msg = mHandler.obtainMessage(MSG_SET_PLAYBACK_STATE,
generationId, state, stateChangeTimeMs);
mHandler.sendMessage(msg);
}
public void setMetadata(int generationId, Bundle metadata) {
}
public void setTransportControlFlags(int generationId, int flags) {
}
public void setArtwork(int generationId, Bitmap bitmap) {
}
public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
}
public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
boolean clearing) throws RemoteException {
Message msg = mHandler.obtainMessage(MSG_SET_CURRENT_CLIENT_ID,
clientGeneration, (clearing ? 1 : 0), mediaIntent);
mHandler.sendMessage(msg);
}
};
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
@@ -324,6 +386,32 @@ public class KeyguardUpdateMonitor {
return sInstance;
}
protected void handleSetGenerationId(int clientGeneration, boolean clearing, PendingIntent p) {
mDisplayClientState.clientGeneration = clientGeneration;
mDisplayClientState.clearing = clearing;
mDisplayClientState.intent = p;
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onMusicClientIdChanged(clientGeneration, clearing, p);
}
}
}
protected void handleSetPlaybackState(int generationId, int playbackState, long eventTime) {
if (generationId == mDisplayClientState.clientGeneration) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onMusicPlaybackStateChanged(playbackState, eventTime);
}
}
} else {
Log.w(TAG, "Ignoring generation id " + generationId + " because it's not current");
}
}
private KeyguardUpdateMonitor(Context context) {
mContext = context;
@@ -457,6 +545,8 @@ public class KeyguardUpdateMonitor {
*/
protected void handleBootCompleted() {
mBootCompleted = true;
mAudioManager = new AudioManager(mContext);
mAudioManager.registerRemoteControlDisplay(mRemoteControlDisplay);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -466,7 +556,7 @@ public class KeyguardUpdateMonitor {
}
/**
* We need to store this state in the KeyguardUpdateMonitor since this class will not be
* We need to store this state in the KeyguardUpdateMonitor since this class will not be
* destroyed.
*/
public boolean hasBootCompleted() {
@@ -735,6 +825,12 @@ public class KeyguardUpdateMonitor {
callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
callback.onClockVisibilityChanged();
callback.onSimStateChanged(mSimState);
callback.onMusicClientIdChanged(
mDisplayClientState.clientGeneration,
mDisplayClientState.clearing,
mDisplayClientState.intent);
callback.onMusicPlaybackStateChanged(mDisplayClientState.playbackState,
mDisplayClientState.playbackEventTime);
}
public void sendKeyguardVisibilityChanged(boolean showing) {
@@ -838,4 +934,8 @@ public class KeyguardUpdateMonitor {
|| simState == IccCardConstants.State.PUK_REQUIRED
|| simState == IccCardConstants.State.PERM_DISABLED);
}
public DisplayClientState getCachedDisplayClientState() {
return mDisplayClientState;
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.android.internal.policy.impl.keyguard;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.media.AudioManager;
@@ -112,4 +113,17 @@ class KeyguardUpdateMonitorCallback {
* KeyguardUpdateMonitor.
*/
void onBootCompleted() { }
/**
* Called when audio client attaches or detaches from AudioManager.
*/
void onMusicClientIdChanged(int clientGeneration, boolean clearing, PendingIntent intent) { }
/**
* Called when the audio playback state changes.
* @param playbackState
* @param eventTime
*/
public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { }
}

View File

@@ -15,7 +15,6 @@
*/
package com.android.internal.policy.impl.keyguard;
import android.appwidget.AppWidgetManager;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
@@ -35,13 +34,6 @@ public class KeyguardViewStateManager implements
private static final int SCREEN_ON_RING_HINT_DELAY = 300;
Handler mMainQueue = new Handler(Looper.myLooper());
// transport control states
static final int TRANSPORT_GONE = 0;
static final int TRANSPORT_INVISIBLE = 1;
static final int TRANSPORT_VISIBLE = 2;
private int mTransportState = TRANSPORT_GONE;
int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
// Paged view state
@@ -310,14 +302,6 @@ public class KeyguardViewStateManager implements
}
}
public void setTransportState(int state) {
mTransportState = state;
}
public int getTransportState() {
return mTransportState;
}
// ChallengeLayout.OnBouncerStateChangedListener
@Override
public void onBouncerStateChanged(boolean bouncerActive) {