From 9546f607f68814f5269374b5c5e714c9d8d8b0b8 Mon Sep 17 00:00:00 2001 From: Issei Suzuki Date: Wed, 26 Jan 2022 18:15:08 +0000 Subject: [PATCH] Add ActivityOption to remove insecure keyguard when activity is launched. Add a new ActivityOption#setDismissKeyguardIfInsecure remove keyguard when an activity is launched while an insecure keyguard is shown. If this option is set, WMS waits until the launched activity finishes drawing its surface, then starts KEYGUARD_GOING_AWAY app transition. Bug: 203044476 Test: atest KeyguardLockedTests KeyguardTransitionTests Change-Id: I0f6a501baa2a60ae044bf1ef888e5e6f57a5f13e --- core/java/android/app/ActivityOptions.java | 30 +++++++++++++ .../am/ActivityManagerShellCommand.java | 9 ++++ .../com/android/server/wm/ActivityRecord.java | 2 + .../android/server/wm/KeyguardController.java | 44 +++++++++++++++---- 4 files changed, 76 insertions(+), 9 deletions(-) diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 0178fa1434452..e3900f629c766 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -361,6 +361,10 @@ public class ActivityOptions extends ComponentOptions { private static final String KEY_LAUNCH_INTO_PIP_PARAMS = "android.activity.launchIntoPipParams"; + /** See {@link #setDismissKeyguardIfInsecure()}. */ + private static final String KEY_DISMISS_KEYGUARD_IF_INSECURE = + "android.activity.dismissKeyguardIfInsecure"; + /** * @see #setLaunchCookie * @hide @@ -457,6 +461,7 @@ public class ActivityOptions extends ComponentOptions { private boolean mLaunchedFromBubble; private boolean mTransientLaunch; private PictureInPictureParams mLaunchIntoPipParams; + private boolean mDismissKeyguardIfInsecure; /** * Create an ActivityOptions specifying a custom animation to run when @@ -1253,6 +1258,7 @@ public class ActivityOptions extends ComponentOptions { mLaunchIntoPipParams = opts.getParcelable(KEY_LAUNCH_INTO_PIP_PARAMS); mIsEligibleForLegacyPermissionPrompt = opts.getBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE); + mDismissKeyguardIfInsecure = opts.getBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE); } /** @@ -1848,6 +1854,27 @@ public class ActivityOptions extends ComponentOptions { return mTransientLaunch; } + /** + * Sets whether the insecure keyguard should go away when this activity launches. In case the + * keyguard is secure, this option will be ignored. + * + * @see Activity#setShowWhenLocked(boolean) + * @see android.R.attr#showWhenLocked + * @hide + */ + public void setDismissKeyguardIfInsecure() { + mDismissKeyguardIfInsecure = true; + } + + /** + * @see #setDismissKeyguardIfInsecure() + * @return whether the insecure keyguard should go away when the activity launches. + * @hide + */ + public boolean getDismissKeyguardIfInsecure() { + return mDismissKeyguardIfInsecure; + } + /** * Update the current values in this ActivityOptions from those supplied * in otherOptions. Any values @@ -2109,6 +2136,9 @@ public class ActivityOptions extends ComponentOptions { b.putBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE, mIsEligibleForLegacyPermissionPrompt); } + if (mDismissKeyguardIfInsecure) { + b.putBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE, mDismissKeyguardIfInsecure); + } return b; } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 28b807c5d30bb..bbb91a85f363b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -183,6 +183,7 @@ final class ActivityManagerShellCommand extends ShellCommand { private boolean mAsync; private BroadcastOptions mBroadcastOptions; private boolean mShowSplashScreen; + private boolean mDismissKeyguardIfInsecure; final boolean mDumping; @@ -437,6 +438,8 @@ final class ActivityManagerShellCommand extends ShellCommand { mAsync = true; } else if (opt.equals("--splashscreen-show-icon")) { mShowSplashScreen = true; + } else if (opt.equals("--dismiss-keyguard-if-insecure")) { + mDismissKeyguardIfInsecure = true; } else { return false; } @@ -581,6 +584,12 @@ final class ActivityManagerShellCommand extends ShellCommand { } options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); } + if (mDismissKeyguardIfInsecure) { + if (options == null) { + options = ActivityOptions.makeBasic(); + } + options.setDismissKeyguardIfInsecure(); + } if (mWaitOption) { result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, null, intent, mimeType, null, null, 0, mStartFlags, profilerInfo, diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 647ca9456393a..86139706822ad 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -848,6 +848,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean mEnteringAnimation; boolean mOverrideTaskTransition; + boolean mDismissKeyguardIfInsecure; boolean mAppStopped; // A hint to override the window specified rotation animation, or -1 to use the window specified @@ -1880,6 +1881,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } mOverrideTaskTransition = options.getOverrideTaskTransition(); + mDismissKeyguardIfInsecure = options.getDismissKeyguardIfInsecure(); } ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService( diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index c55af9b6286ea..48de6ed78119d 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -28,6 +28,7 @@ import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_W import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE; import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; +import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS; @@ -407,6 +408,25 @@ class KeyguardController { ? topActivity.getRootTask() : null); } + /** + * Called when keyguard going away state changed. + */ + private void handleKeyguardGoingAwayChanged(DisplayContent dc) { + mService.deferWindowLayout(); + try { + dc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, 0 /* transitFlags */); + // We are deprecating TRANSIT_KEYGUARD_GOING_AWAY for Shell transition and use + // TRANSIT_FLAG_KEYGUARD_GOING_AWAY to indicate that it should animate keyguard going + // away. + dc.mAtmService.getTransitionController().requestTransitionIfNeeded( + TRANSIT_OPEN, TRANSIT_FLAG_KEYGUARD_GOING_AWAY, null /* trigger */, dc); + updateKeyguardSleepToken(); + mWindowManager.executeAppTransition(); + } finally { + mService.continueWindowLayout(); + } + } + /** * Called when somebody wants to dismiss the Keyguard via the flag. */ @@ -525,11 +545,13 @@ class KeyguardController { } /** - * Updates {@link #mOccluded}, {@link #mTopTurnScreenOnActivity} and - * {@link #mDismissingKeyguardActivity} if the top task could be visible. + * Updates keyguard status if the top task could be visible. The top task may occlude + * keyguard, request to dismiss keyguard or make insecure keyguard go away based on its + * properties. */ void updateVisibility(KeyguardController controller, DisplayContent display) { final boolean lastOccluded = mOccluded; + final boolean lastKeyguardGoingAway = mKeyguardGoingAway; final ActivityRecord lastDismissKeyguardActivity = mDismissingKeyguardActivity; final ActivityRecord lastTurnScreenOnActivity = mTopTurnScreenOnActivity; @@ -552,14 +574,18 @@ class KeyguardController { mTopTurnScreenOnActivity = top; } - final boolean showWhenLocked = top.canShowWhenLocked(); - if (showWhenLocked) { + final boolean isKeyguardSecure = controller.mWindowManager.isKeyguardSecure( + controller.mService.getCurrentUserId()); + if (top.mDismissKeyguardIfInsecure && mKeyguardShowing && !isKeyguardSecure) { + mKeyguardGoingAway = true; + } else if (top.canShowWhenLocked()) { mTopOccludesActivity = top; } // Only the top activity may control occluded, as we can't occlude the Keyguard // if the top app doesn't want to occlude it. - occludedByActivity = showWhenLocked || (mDismissingKeyguardActivity != null + occludedByActivity = mTopOccludesActivity != null + || (mDismissingKeyguardActivity != null && task.topRunningActivity() == mDismissingKeyguardActivity && controller.canShowWhileOccluded( true /* dismissKeyguard */, false /* showWhenLocked */)); @@ -574,10 +600,8 @@ class KeyguardController { && top.getActivityType() == ACTIVITY_TYPE_DREAM); mOccluded = dreaming || occludedByActivity; mRequestDismissKeyguard = lastDismissKeyguardActivity != mDismissingKeyguardActivity - && !mOccluded - && mDismissingKeyguardActivity != null - && controller.mWindowManager.isKeyguardSecure( - controller.mService.getCurrentUserId()); + && !mOccluded && !mKeyguardGoingAway + && mDismissingKeyguardActivity != null; if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity && mTopTurnScreenOnActivity != null @@ -589,6 +613,8 @@ class KeyguardController { if (lastOccluded != mOccluded) { controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity); + } else if (!lastKeyguardGoingAway && mKeyguardGoingAway) { + controller.handleKeyguardGoingAwayChanged(display); } }