From 67c036b1bad9f81dad809f30ed97751b08520cdd Mon Sep 17 00:00:00 2001 From: David Stevens Date: Wed, 23 Aug 2017 18:41:49 -0700 Subject: [PATCH] Handle showWhenLocked on secondary displays The keyguard has windows on the default display and the remote display selected by MediaRouter. Keyguard occlusion only applies to the default display. To make the activity showWhenLocked flag work on secondary displays, pass the display id of the locked secondary display from the SystemUi to KeyguardController and make its isKeyguardShowing method take a displayId. Test: android.server.cts.ActivityManagerDisplayTests Test: #testSecondaryDisplayShowWhenLocked Bug: 64994006 Merged-In: Ib31fc76e9df469e97a59a181f09d457ceed4ef5f Change-Id: Ib31fc76e9df469e97a59a181f09d457ceed4ef5f --- core/java/android/app/IActivityManager.aidl | 10 +++- .../android/keyguard/KeyguardDisplayManager.java | 21 ++++++- .../com/android/keyguard/ViewMediatorCallback.java | 5 ++ .../systemui/keyguard/KeyguardViewMediator.java | 65 ++++++++++++++-------- .../android/server/am/ActivityManagerService.java | 8 +-- .../java/com/android/server/am/ActivityStack.java | 7 ++- .../com/android/server/am/KeyguardController.java | 30 ++++++---- .../policy/keyguard/KeyguardServiceDelegate.java | 7 ++- 8 files changed, 108 insertions(+), 45 deletions(-) diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 897e42bc2b22..18117481b0ea 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -308,7 +308,15 @@ interface IActivityManager { boolean shouldUpRecreateTask(in IBinder token, in String destAffinity); boolean navigateUpTo(in IBinder token, in Intent target, int resultCode, in Intent resultData); - void setLockScreenShown(boolean showing); + /** + * Informs ActivityManagerService that the keyguard is showing. + * + * @param showing True if the keyguard is showing, false otherwise. + * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard + * is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if + * showing is true. + */ + void setLockScreenShown(boolean showing, int secondaryDisplayShowing); boolean finishActivityAffinity(in IBinder token); // This is not public because you need to be very careful in how you // manage your activity to make sure it is always the uid you expect. diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 8de1d317c5ed..2bc0e45c725d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -15,6 +15,8 @@ */ package com.android.keyguard; +import static android.view.Display.INVALID_DISPLAY; + import android.app.Presentation; import android.content.Context; import android.content.DialogInterface; @@ -28,16 +30,21 @@ import android.view.Display; import android.view.View; import android.view.WindowManager; +// TODO(multi-display): Support multiple external displays public class KeyguardDisplayManager { protected static final String TAG = "KeyguardDisplayManager"; private static boolean DEBUG = KeyguardConstants.DEBUG; + + private final ViewMediatorCallback mCallback; + private final MediaRouter mMediaRouter; + private final Context mContext; + Presentation mPresentation; - private MediaRouter mMediaRouter; - private Context mContext; private boolean mShowing; - public KeyguardDisplayManager(Context context) { + public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) { mContext = context; + mCallback = callback; mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE); } @@ -90,6 +97,7 @@ public class KeyguardDisplayManager { }; protected void updateDisplays(boolean showing) { + Presentation originalPresentation = mPresentation; if (showing) { MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute( MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY); @@ -121,6 +129,13 @@ public class KeyguardDisplayManager { mPresentation = null; } } + + // mPresentation is only updated when the display changes + if (mPresentation != originalPresentation) { + final int displayId = mPresentation != null + ? mPresentation.getDisplay().getDisplayId() : INVALID_DISPLAY; + mCallback.onSecondaryDisplayShowingChanged(displayId); + } } private final static class KeyguardPresentation extends Presentation { diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java index 327d218913d2..b194de43a718 100644 --- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java @@ -88,4 +88,9 @@ public interface ViewMediatorCallback { * {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}. */ int getBouncerPromptReason(); + + /** + * Invoked when the secondary display showing a keyguard window changes. + */ + void onSecondaryDisplayShowingChanged(int displayId); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 4733008c06c3..e737cc5cbfbc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -17,6 +17,7 @@ package com.android.systemui.keyguard; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; +import static android.view.Display.INVALID_DISPLAY; import static com.android.internal.telephony.IccCardConstants.State.ABSENT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; @@ -239,6 +240,9 @@ public class KeyguardViewMediator extends SystemUI { // answer whether the input should be restricted) private boolean mShowing; + // display id of the secondary display on which we have put a keyguard window + private int mSecondaryDisplayShowing = INVALID_DISPLAY; + /** Cached value of #isInputRestricted */ private boolean mInputRestricted; @@ -646,6 +650,13 @@ public class KeyguardViewMediator extends SystemUI { } return KeyguardSecurityView.PROMPT_REASON_NONE; } + + @Override + public void onSecondaryDisplayShowingChanged(int displayId) { + synchronized (KeyguardViewMediator.this) { + setShowingLocked(mShowing, displayId, false); + } + } }; public void userActivity() { @@ -670,7 +681,7 @@ public class KeyguardViewMediator extends SystemUI { filter.addAction(Intent.ACTION_SHUTDOWN); mContext.registerReceiver(mBroadcastReceiver, filter); - mKeyguardDisplayManager = new KeyguardDisplayManager(mContext); + mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, mViewMediatorCallback); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); @@ -685,7 +696,8 @@ public class KeyguardViewMediator extends SystemUI { com.android.keyguard.R.bool.config_enableKeyguardService)) { setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled( - KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */); + KeyguardUpdateMonitor.getCurrentUser()), + mSecondaryDisplayShowing, true /* forceCallbacks */); } mStatusBarKeyguardViewManager = @@ -1688,10 +1700,10 @@ public class KeyguardViewMediator extends SystemUI { playSound(mTrustedSoundId); } - private void updateActivityLockScreenState(boolean showing) { + private void updateActivityLockScreenState(boolean showing, int secondaryDisplayShowing) { mUiOffloadThread.submit(() -> { try { - ActivityManager.getService().setLockScreenShown(showing); + ActivityManager.getService().setLockScreenShown(showing, secondaryDisplayShowing); } catch (RemoteException e) { } }); @@ -2054,30 +2066,39 @@ public class KeyguardViewMediator extends SystemUI { } private void setShowingLocked(boolean showing) { - setShowingLocked(showing, false /* forceCallbacks */); + setShowingLocked(showing, mSecondaryDisplayShowing, false /* forceCallbacks */); } - private void setShowingLocked(boolean showing, boolean forceCallbacks) { - if (showing != mShowing || forceCallbacks) { + private void setShowingLocked( + boolean showing, int secondaryDisplayShowing, boolean forceCallbacks) { + final boolean notifyDefaultDisplayCallbacks = showing != mShowing || forceCallbacks; + if (notifyDefaultDisplayCallbacks || secondaryDisplayShowing != mSecondaryDisplayShowing) { mShowing = showing; - int size = mKeyguardStateCallbacks.size(); - for (int i = size - 1; i >= 0; i--) { - IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i); - try { - callback.onShowingStateChanged(showing); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onShowingStateChanged", e); - if (e instanceof DeadObjectException) { - mKeyguardStateCallbacks.remove(callback); - } + mSecondaryDisplayShowing = secondaryDisplayShowing; + if (notifyDefaultDisplayCallbacks) { + notifyDefaultDisplayCallbacks(showing); + } + updateActivityLockScreenState(showing, secondaryDisplayShowing); + } + } + + private void notifyDefaultDisplayCallbacks(boolean showing) { + int size = mKeyguardStateCallbacks.size(); + for (int i = size - 1; i >= 0; i--) { + IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i); + try { + callback.onShowingStateChanged(showing); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call onShowingStateChanged", e); + if (e instanceof DeadObjectException) { + mKeyguardStateCallbacks.remove(callback); } } - updateInputRestrictedLocked(); - mUiOffloadThread.submit(() -> { - mTrustManager.reportKeyguardShowingChanged(); - }); - updateActivityLockScreenState(showing); } + updateInputRestrictedLocked(); + mUiOffloadThread.submit(() -> { + mTrustManager.reportKeyguardShowingChanged(); + }); } private void notifyTrustedChangedLocked(boolean trusted) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7356c93d307c..4686713ba4c5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -715,7 +715,7 @@ public class ActivityManagerService extends IActivityManager.Stub public boolean canShowErrorDialogs() { return mShowDialogs && !mSleeping && !mShuttingDown - && !mKeyguardController.isKeyguardShowing() + && !mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY) && !(UserManager.isDeviceInDemoMode(mContext) && mUserController.getCurrentUser().isDemo()); } @@ -12576,7 +12576,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void setLockScreenShown(boolean showing) { + public void setLockScreenShown(boolean showing, int secondaryDisplayShowing) { if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires permission " @@ -12586,7 +12586,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized(this) { long ident = Binder.clearCallingIdentity(); try { - mKeyguardController.setKeyguardShown(showing); + mKeyguardController.setKeyguardShown(showing, secondaryDisplayShowing); } finally { Binder.restoreCallingIdentity(ident); } @@ -24007,7 +24007,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void notifyKeyguardTrustedChanged() { synchronized (ActivityManagerService.this) { - if (mKeyguardController.isKeyguardShowing()) { + if (mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) { mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 4d525f232b2a..7413213e42bb 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1978,7 +1978,8 @@ class ActivityStack extends ConfigurationContai boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible, boolean isTop) { final boolean isInPinnedStack = r.getStack().getStackId() == PINNED_STACK_ID; - final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing(); + final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing( + mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY); final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked(); final boolean showWhenLocked = r.canShowWhenLocked() && !isInPinnedStack; final boolean dismissKeyguard = r.hasDismissKeyguardWindows(); @@ -5210,8 +5211,8 @@ class ActivityStack extends ConfigurationContai voiceInteractor, type); // add the task to stack first, mTaskPositioner might need the stack association addTask(task, toTop, "createTaskRecord"); - final boolean isLockscreenShown = - mService.mStackSupervisor.mKeyguardController.isKeyguardShowing(); + final boolean isLockscreenShown = mService.mStackSupervisor.mKeyguardController + .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY); if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable() && !isLockscreenShown) { task.updateOverrideConfiguration(mBounds); diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java index cea80c8d0e9d..85961135d84f 100644 --- a/services/core/java/com/android/server/am/KeyguardController.java +++ b/services/core/java/com/android/server/am/KeyguardController.java @@ -19,6 +19,7 @@ package com.android.server.am; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; @@ -66,6 +67,7 @@ class KeyguardController { private int mBeforeUnoccludeTransit; private int mVisibilityTransactionDepth; private SleepToken mSleepToken; + private int mSecondaryDisplayShowing = INVALID_DISPLAY; KeyguardController(ActivityManagerService service, ActivityStackSupervisor stackSupervisor) { @@ -78,10 +80,12 @@ class KeyguardController { } /** - * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise + * @return true if Keyguard is showing, not going away, and not being occluded on the given + * display, false otherwise */ - boolean isKeyguardShowing() { - return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded; + boolean isKeyguardShowing(int displayId) { + return mKeyguardShowing && !mKeyguardGoingAway && + (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing); } /** @@ -94,15 +98,19 @@ class KeyguardController { /** * Update the Keyguard showing state. */ - void setKeyguardShown(boolean showing) { - if (showing == mKeyguardShowing) { + void setKeyguardShown(boolean showing, int secondaryDisplayShowing) { + boolean showingChanged = showing != mKeyguardShowing; + if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) { return; } mKeyguardShowing = showing; - dismissDockedStackIfNeeded(); - if (showing) { - setKeyguardGoingAway(false); - mDismissalRequested = false; + mSecondaryDisplayShowing = secondaryDisplayShowing; + if (showingChanged) { + dismissDockedStackIfNeeded(); + if (showing) { + setKeyguardGoingAway(false); + mDismissalRequested = false; + } } mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); updateKeyguardSleepToken(); @@ -337,9 +345,9 @@ class KeyguardController { } private void updateKeyguardSleepToken() { - if (mSleepToken == null && isKeyguardShowing()) { + if (mSleepToken == null && isKeyguardShowing(DEFAULT_DISPLAY)) { mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY); - } else if (mSleepToken != null && !isKeyguardShowing()) { + } else if (mSleepToken != null && !isKeyguardShowing(DEFAULT_DISPLAY)) { mSleepToken.release(); mSleepToken = null; } diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index 50e5e7bd2312..5a5471b1b4f5 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -1,5 +1,7 @@ package com.android.server.policy.keyguard; +import static android.view.Display.INVALID_DISPLAY; + import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; @@ -201,7 +203,10 @@ public class KeyguardServiceDelegate { mKeyguardState.reset(); mHandler.post(() -> { try { - ActivityManager.getService().setLockScreenShown(true); + // There are no longer any keyguard windows on secondary displays, so pass + // INVALID_DISPLAY. All that means is that showWhenLocked activities on + // secondary displays now get to show. + ActivityManager.getService().setLockScreenShown(true, INVALID_DISPLAY); } catch (RemoteException e) { // Local call. } -- 2.11.0