Loading policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +98 −80 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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"); } Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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); Loading @@ -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() { Loading Loading @@ -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; } Loading @@ -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); } Loading @@ -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)) { Loading @@ -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(); Loading @@ -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) Loading policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java +0 −60 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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; } Loading Loading @@ -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); Loading Loading @@ -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 { Loading Loading @@ -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) { Loading Loading @@ -522,8 +466,4 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick return false; } } public void setKeyguardCallback(KeyguardHostView.TransportCallback transportCallback) { mTransportCallback = transportCallback; } } policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java +102 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -163,8 +170,63 @@ 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); } }; Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -838,4 +934,8 @@ public class KeyguardUpdateMonitor { || simState == IccCardConstants.State.PUK_REQUIRED || simState == IccCardConstants.State.PERM_DISABLED); } public DisplayClientState getCachedDisplayClientState() { return mDisplayClientState; } } policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java +14 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.internal.policy.impl.keyguard; import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.media.AudioManager; Loading Loading @@ -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) { } } policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java +0 −16 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading Loading @@ -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) { Loading Loading
policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +98 −80 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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"); } Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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); Loading @@ -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() { Loading Loading @@ -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; } Loading @@ -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); } Loading @@ -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)) { Loading @@ -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(); Loading @@ -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) Loading
policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java +0 −60 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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; } Loading Loading @@ -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); Loading Loading @@ -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 { Loading Loading @@ -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) { Loading Loading @@ -522,8 +466,4 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick return false; } } public void setKeyguardCallback(KeyguardHostView.TransportCallback transportCallback) { mTransportCallback = transportCallback; } }
policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java +102 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -163,8 +170,63 @@ 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); } }; Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -838,4 +934,8 @@ public class KeyguardUpdateMonitor { || simState == IccCardConstants.State.PUK_REQUIRED || simState == IccCardConstants.State.PERM_DISABLED); } public DisplayClientState getCachedDisplayClientState() { return mDisplayClientState; } }
policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java +14 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.internal.policy.impl.keyguard; import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.media.AudioManager; Loading Loading @@ -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) { } }
policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java +0 −16 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading Loading @@ -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) { Loading