Loading core/java/android/app/KeyguardManager.java +9 −0 Original line number Diff line number Diff line Loading @@ -147,6 +147,15 @@ public class KeyguardManager { */ public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm"; /** * When switching to a secure user, system server will expect a callback when the UI has * completed the switch. * * @hide */ public static final String LOCK_ON_USER_SWITCH_CALLBACK = "onSwitchCallback"; /** * * Password lock type, see {@link #setLock} Loading packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +49 −18 Original line number Diff line number Diff line Loading @@ -138,8 +138,7 @@ const val UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS = 75L class KeyguardUnlockAnimationController @Inject constructor( private val context: Context, private val keyguardStateController: KeyguardStateController, private val keyguardViewMediator: Lazy<KeyguardViewMediator>, private val keyguardViewMediator: Lazy<KeyguardViewMediator>, private val keyguardViewController: KeyguardViewController, private val featureFlags: FeatureFlags, private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>, Loading Loading @@ -198,6 +197,12 @@ class KeyguardUnlockAnimationController @Inject constructor( */ var playingCannedUnlockAnimation = false /** * Whether we reached the swipe gesture threshold to dismiss keyguard, or restore it, once and * should ignore any future changes to the dismiss amount before the animation finishes. */ var dismissAmountThresholdsReached = false /** * Remote callback provided by Launcher that allows us to control the Launcher's unlock * animation and smartspace. Loading Loading @@ -326,7 +331,7 @@ class KeyguardUnlockAnimationController @Inject constructor( addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { playingCannedUnlockAnimation = false keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */ ) } Loading Loading @@ -516,7 +521,7 @@ class KeyguardUnlockAnimationController @Inject constructor( // around behind that. biometricUnlockControllerLazy.get().isWakeAndUnlock -> { setSurfaceBehindAppearAmount(1f) keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) } Loading Loading @@ -553,7 +558,7 @@ class KeyguardUnlockAnimationController @Inject constructor( return@postDelayed } keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) }, CANNED_UNLOCK_START_DELAY) } Loading Loading @@ -625,6 +630,10 @@ class KeyguardUnlockAnimationController @Inject constructor( return } if (dismissAmountThresholdsReached) { return } if (!keyguardStateController.isShowing) { return } Loading Loading @@ -657,6 +666,11 @@ class KeyguardUnlockAnimationController @Inject constructor( return } // no-op if we alreaddy reached a threshold. if (dismissAmountThresholdsReached) { return } // no-op if animation is not requested yet. if (!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() || !keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) { Loading @@ -671,7 +685,9 @@ class KeyguardUnlockAnimationController @Inject constructor( !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture && dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)) { setSurfaceBehindAppearAmount(1f) keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(false /* cancelled */) dismissAmountThresholdsReached = true keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) } } Loading Loading @@ -726,28 +742,43 @@ class KeyguardUnlockAnimationController @Inject constructor( * This is generally triggered by us, calling * [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation]. */ fun notifyFinishedKeyguardExitAnimation(cancelled: Boolean) { fun notifyFinishedKeyguardExitAnimation(showKeyguard: Boolean) { // Cancel any pending actions. handler.removeCallbacksAndMessages(null) // Make sure we made the surface behind fully visible, just in case. It should already be // fully visible. If the launcher is doing its own animation, let it continue without // forcing it to 1f. // The lockscreen surface is gone, so it is now safe to re-show the smartspace. if (lockscreenSmartspace?.visibility == View.INVISIBLE) { lockscreenSmartspace?.visibility = View.VISIBLE } if (!showKeyguard) { // Make sure we made the surface behind fully visible, just in case. It should already // be fully visible. The exit animation is finished, and we should not hold the leash // anymore, so forcing it to 1f. surfaceBehindAlpha = 1f setSurfaceBehindAppearAmount(1f) try { launcherUnlockController?.setUnlockAmount(1f, false /* forceIfAnimating */) } catch (e: RemoteException) { Log.e(TAG, "Remote exception in notifyFinishedKeyguardExitAnimation", e) } } listeners.forEach { it.onUnlockAnimationFinished() } // Reset all state surfaceBehindAlphaAnimator.cancel() surfaceBehindEntryAnimator.cancel() // That target is no longer valid since the animation finished, null it out. surfaceBehindRemoteAnimationTarget = null surfaceBehindParams = null playingCannedUnlockAnimation = false dismissAmountThresholdsReached = false willUnlockWithInWindowLauncherAnimations = false willUnlockWithSmartspaceTransition = false // The lockscreen surface is gone, so it is now safe to re-show the smartspace. lockscreenSmartspace?.visibility = View.VISIBLE listeners.forEach { it.onUnlockAnimationFinished() } } /** Loading packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +279 −79 File changed.Preview size limit exceeded, changes collapsed. Show changes packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +3 −3 Original line number Diff line number Diff line Loading @@ -116,7 +116,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { // Also expect we've immediately asked the keyguard view mediator to finish the remote // animation. verify(keyguardViewMediator, times(1)).onKeyguardExitRemoteAnimationFinished( verify(keyguardViewMediator, times(1)).exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) verifyNoMoreInteractions(surfaceTransactionApplier) Loading @@ -136,7 +136,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { ) // Since the animation is running, we should not have finished the remote animation. verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished( verify(keyguardViewMediator, times(0)).exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) } Loading services/core/java/com/android/server/am/UserController.java +25 −30 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE; import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL; import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK; import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED; import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED; import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; Loading Loading @@ -103,7 +104,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.LockPatternUtils; Loading @@ -127,6 +127,8 @@ import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** Loading Loading @@ -1580,7 +1582,8 @@ class UserController implements Handler.Callback { mInjector.getWindowManager().setSwitchingUser(true); // Only lock if the user has a secure keyguard PIN/Pattern/Pwd if (mInjector.getKeyguardManager().isDeviceSecure(userId)) { mInjector.getWindowManager().lockNow(null); // Make sure the device is locked before moving on with the user switch mInjector.lockDeviceNowAndWaitForKeyguardShown(); } } } else { Loading Loading @@ -2039,22 +2042,9 @@ class UserController implements Handler.Callback { @VisibleForTesting void completeUserSwitch(int newUserId) { if (isUserSwitchUiEnabled()) { // If there is no challenge set, dismiss the keyguard right away if (!mInjector.getKeyguardManager().isDeviceSecure(newUserId)) { // Wait until the keyguard is dismissed to unfreeze mInjector.dismissKeyguard( new Runnable() { public void run() { unfreezeScreen(); } }, "User Switch"); return; } else { unfreezeScreen(); } } } /** * Tell WindowManager we're ready to unfreeze the screen, at its leisure. Note that there is Loading Loading @@ -3381,23 +3371,28 @@ class UserController implements Handler.Callback { return IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); } protected void dismissKeyguard(Runnable runnable, String reason) { getWindowManager().dismissKeyguard(new IKeyguardDismissCallback.Stub() { @Override public void onDismissError() throws RemoteException { mHandler.post(runnable); } void lockDeviceNowAndWaitForKeyguardShown() { final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); t.traceBegin("lockDeviceNowAndWaitForKeyguardShown"); @Override public void onDismissSucceeded() throws RemoteException { mHandler.post(runnable); final CountDownLatch latch = new CountDownLatch(1); Bundle bundle = new Bundle(); bundle.putBinder(LOCK_ON_USER_SWITCH_CALLBACK, new IRemoteCallback.Stub() { public void sendResult(Bundle data) { latch.countDown(); } @Override public void onDismissCancelled() throws RemoteException { mHandler.post(runnable); }); getWindowManager().lockNow(bundle); try { if (!latch.await(20, TimeUnit.SECONDS)) { throw new RuntimeException("User controller expected a callback while waiting " + "to show the keyguard. Timed out after 20 seconds."); } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { t.traceEnd(); } }, reason); } } } Loading
core/java/android/app/KeyguardManager.java +9 −0 Original line number Diff line number Diff line Loading @@ -147,6 +147,15 @@ public class KeyguardManager { */ public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm"; /** * When switching to a secure user, system server will expect a callback when the UI has * completed the switch. * * @hide */ public static final String LOCK_ON_USER_SWITCH_CALLBACK = "onSwitchCallback"; /** * * Password lock type, see {@link #setLock} Loading
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +49 −18 Original line number Diff line number Diff line Loading @@ -138,8 +138,7 @@ const val UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS = 75L class KeyguardUnlockAnimationController @Inject constructor( private val context: Context, private val keyguardStateController: KeyguardStateController, private val keyguardViewMediator: Lazy<KeyguardViewMediator>, private val keyguardViewMediator: Lazy<KeyguardViewMediator>, private val keyguardViewController: KeyguardViewController, private val featureFlags: FeatureFlags, private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>, Loading Loading @@ -198,6 +197,12 @@ class KeyguardUnlockAnimationController @Inject constructor( */ var playingCannedUnlockAnimation = false /** * Whether we reached the swipe gesture threshold to dismiss keyguard, or restore it, once and * should ignore any future changes to the dismiss amount before the animation finishes. */ var dismissAmountThresholdsReached = false /** * Remote callback provided by Launcher that allows us to control the Launcher's unlock * animation and smartspace. Loading Loading @@ -326,7 +331,7 @@ class KeyguardUnlockAnimationController @Inject constructor( addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { playingCannedUnlockAnimation = false keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */ ) } Loading Loading @@ -516,7 +521,7 @@ class KeyguardUnlockAnimationController @Inject constructor( // around behind that. biometricUnlockControllerLazy.get().isWakeAndUnlock -> { setSurfaceBehindAppearAmount(1f) keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) } Loading Loading @@ -553,7 +558,7 @@ class KeyguardUnlockAnimationController @Inject constructor( return@postDelayed } keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished( keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) }, CANNED_UNLOCK_START_DELAY) } Loading Loading @@ -625,6 +630,10 @@ class KeyguardUnlockAnimationController @Inject constructor( return } if (dismissAmountThresholdsReached) { return } if (!keyguardStateController.isShowing) { return } Loading Loading @@ -657,6 +666,11 @@ class KeyguardUnlockAnimationController @Inject constructor( return } // no-op if we alreaddy reached a threshold. if (dismissAmountThresholdsReached) { return } // no-op if animation is not requested yet. if (!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() || !keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) { Loading @@ -671,7 +685,9 @@ class KeyguardUnlockAnimationController @Inject constructor( !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture && dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)) { setSurfaceBehindAppearAmount(1f) keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(false /* cancelled */) dismissAmountThresholdsReached = true keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) } } Loading Loading @@ -726,28 +742,43 @@ class KeyguardUnlockAnimationController @Inject constructor( * This is generally triggered by us, calling * [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation]. */ fun notifyFinishedKeyguardExitAnimation(cancelled: Boolean) { fun notifyFinishedKeyguardExitAnimation(showKeyguard: Boolean) { // Cancel any pending actions. handler.removeCallbacksAndMessages(null) // Make sure we made the surface behind fully visible, just in case. It should already be // fully visible. If the launcher is doing its own animation, let it continue without // forcing it to 1f. // The lockscreen surface is gone, so it is now safe to re-show the smartspace. if (lockscreenSmartspace?.visibility == View.INVISIBLE) { lockscreenSmartspace?.visibility = View.VISIBLE } if (!showKeyguard) { // Make sure we made the surface behind fully visible, just in case. It should already // be fully visible. The exit animation is finished, and we should not hold the leash // anymore, so forcing it to 1f. surfaceBehindAlpha = 1f setSurfaceBehindAppearAmount(1f) try { launcherUnlockController?.setUnlockAmount(1f, false /* forceIfAnimating */) } catch (e: RemoteException) { Log.e(TAG, "Remote exception in notifyFinishedKeyguardExitAnimation", e) } } listeners.forEach { it.onUnlockAnimationFinished() } // Reset all state surfaceBehindAlphaAnimator.cancel() surfaceBehindEntryAnimator.cancel() // That target is no longer valid since the animation finished, null it out. surfaceBehindRemoteAnimationTarget = null surfaceBehindParams = null playingCannedUnlockAnimation = false dismissAmountThresholdsReached = false willUnlockWithInWindowLauncherAnimations = false willUnlockWithSmartspaceTransition = false // The lockscreen surface is gone, so it is now safe to re-show the smartspace. lockscreenSmartspace?.visibility = View.VISIBLE listeners.forEach { it.onUnlockAnimationFinished() } } /** Loading
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +279 −79 File changed.Preview size limit exceeded, changes collapsed. Show changes
packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +3 −3 Original line number Diff line number Diff line Loading @@ -116,7 +116,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { // Also expect we've immediately asked the keyguard view mediator to finish the remote // animation. verify(keyguardViewMediator, times(1)).onKeyguardExitRemoteAnimationFinished( verify(keyguardViewMediator, times(1)).exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) verifyNoMoreInteractions(surfaceTransactionApplier) Loading @@ -136,7 +136,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { ) // Since the animation is running, we should not have finished the remote animation. verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished( verify(keyguardViewMediator, times(0)).exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) } Loading
services/core/java/com/android/server/am/UserController.java +25 −30 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE; import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL; import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK; import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED; import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED; import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; Loading Loading @@ -103,7 +104,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.LockPatternUtils; Loading @@ -127,6 +127,8 @@ import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** Loading Loading @@ -1580,7 +1582,8 @@ class UserController implements Handler.Callback { mInjector.getWindowManager().setSwitchingUser(true); // Only lock if the user has a secure keyguard PIN/Pattern/Pwd if (mInjector.getKeyguardManager().isDeviceSecure(userId)) { mInjector.getWindowManager().lockNow(null); // Make sure the device is locked before moving on with the user switch mInjector.lockDeviceNowAndWaitForKeyguardShown(); } } } else { Loading Loading @@ -2039,22 +2042,9 @@ class UserController implements Handler.Callback { @VisibleForTesting void completeUserSwitch(int newUserId) { if (isUserSwitchUiEnabled()) { // If there is no challenge set, dismiss the keyguard right away if (!mInjector.getKeyguardManager().isDeviceSecure(newUserId)) { // Wait until the keyguard is dismissed to unfreeze mInjector.dismissKeyguard( new Runnable() { public void run() { unfreezeScreen(); } }, "User Switch"); return; } else { unfreezeScreen(); } } } /** * Tell WindowManager we're ready to unfreeze the screen, at its leisure. Note that there is Loading Loading @@ -3381,23 +3371,28 @@ class UserController implements Handler.Callback { return IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); } protected void dismissKeyguard(Runnable runnable, String reason) { getWindowManager().dismissKeyguard(new IKeyguardDismissCallback.Stub() { @Override public void onDismissError() throws RemoteException { mHandler.post(runnable); } void lockDeviceNowAndWaitForKeyguardShown() { final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); t.traceBegin("lockDeviceNowAndWaitForKeyguardShown"); @Override public void onDismissSucceeded() throws RemoteException { mHandler.post(runnable); final CountDownLatch latch = new CountDownLatch(1); Bundle bundle = new Bundle(); bundle.putBinder(LOCK_ON_USER_SWITCH_CALLBACK, new IRemoteCallback.Stub() { public void sendResult(Bundle data) { latch.countDown(); } @Override public void onDismissCancelled() throws RemoteException { mHandler.post(runnable); }); getWindowManager().lockNow(bundle); try { if (!latch.await(20, TimeUnit.SECONDS)) { throw new RuntimeException("User controller expected a callback while waiting " + "to show the keyguard. Timed out after 20 seconds."); } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { t.traceEnd(); } }, reason); } } }