Loading core/java/android/view/WindowManager.java +8 −0 Original line number Diff line number Diff line Loading @@ -487,6 +487,13 @@ public interface WindowManager extends ViewManager { */ int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION = 0x8; /** * Transition flag: Keyguard is going away to the launcher, and it needs us to clear the task * snapshot of the launcher because it has changed something in the Launcher window. * @hide */ int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT = 0x16; /** * Transition flag: App is crashed. * @hide Loading Loading @@ -527,6 +534,7 @@ public interface WindowManager extends ViewManager { TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION, TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER, TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION, TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT, TRANSIT_FLAG_APP_CRASHED, TRANSIT_FLAG_OPEN_BEHIND, TRANSIT_FLAG_KEYGUARD_LOCKED, Loading core/java/android/view/WindowManagerPolicyConstants.java +1 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ public interface WindowManagerPolicyConstants { int KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS = 1 << 1; int KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER = 1 << 2; int KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS = 1 << 3; int KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT = 1 << 4; // Flags used for indicating whether the internal and/or external input devices // of some type are available. Loading packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +16 −7 Original line number Diff line number Diff line Loading @@ -451,12 +451,22 @@ class KeyguardUnlockAnimationController @Inject constructor( surfaceBehindRemoteAnimationTarget = target surfaceBehindRemoteAnimationStartTime = startTime // If we specifically requested that the surface behind be made visible, it means we are // swiping to unlock. In that case, the surface visibility is tied to the dismiss amount, // and we'll handle that in onKeyguardDismissAmountChanged(). If we didn't request that, the // keyguard is being dismissed for a different reason (biometric auth, etc.) and we should // play a canned animation to make the surface fully visible. if (!requestedShowSurfaceBehindKeyguard) { // If we specifically requested that the surface behind be made visible (vs. it being made // visible because we're unlocking), then we're in the middle of a swipe-to-unlock touch // gesture and the surface behind the keyguard should be made visible. if (requestedShowSurfaceBehindKeyguard) { // Fade in the surface, as long as we're not now flinging. The touch gesture ending in // a fling during the time it takes the keyguard exit animation to start is an edge // case race condition, and we'll handle it by playing a canned animation on the // now-visible surface to finish unlocking. if (!keyguardStateController.isFlingingToDismissKeyguard) { fadeInSurfaceBehind() } else { playCannedUnlockAnimation() } } else { // The surface was made visible since we're unlocking not from a swipe (fingerprint, // lock icon long-press, etc). Play the full unlock animation. playCannedUnlockAnimation() } Loading Loading @@ -612,7 +622,6 @@ class KeyguardUnlockAnimationController @Inject constructor( !keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) { keyguardViewMediator.get().showSurfaceBehindKeyguard() fadeInSurfaceBehind() } else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD && keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) { // We're no longer past the threshold but we are showing the surface. Animate it Loading packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +24 −12 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.systemui.keyguard; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN; Loading Loading @@ -119,7 +121,6 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeDepthController; Loading Loading @@ -2301,8 +2302,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, int flags = 0; if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock() || mWakeAndUnlocking && !mWallpaperSupportsAmbientMode) { flags |= WindowManagerPolicyConstants .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; flags |= KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; } if (mKeyguardViewControllerLazy.get().isGoingToNotificationShade() || mWakeAndUnlocking && mWallpaperSupportsAmbientMode) { Loading @@ -2318,6 +2318,15 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, .KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS; } // If we are unlocking to the launcher, clear the snapshot so that any changes as part // of the in-window animations are reflected. This is needed even if we're not actually // playing in-window animations for this particular unlock since a previous unlock might // have changed the Launcher state. if (mWakeAndUnlocking && KeyguardUnlockAnimationController.Companion.isNexusLauncherUnderneath()) { flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; } mUpdateMonitor.setKeyguardGoingAway(true); mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(true); Loading Loading @@ -2622,9 +2631,18 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mSurfaceBehindRemoteAnimationRequested = true; try { ActivityTaskManager.getService().keyguardGoingAway( WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS | WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER); int flags = KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS | KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; // If we are unlocking to the launcher, clear the snapshot so that any changes as part // of the in-window animations are reflected. This is needed even if we're not actually // playing in-window animations for this particular unlock since a previous unlock might // have changed the Launcher state. if (KeyguardUnlockAnimationController.Companion.isNexusLauncherUnderneath()) { flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; } ActivityTaskManager.getService().keyguardGoingAway(flags); mKeyguardStateController.notifyKeyguardGoingAway(true); } catch (RemoteException e) { mSurfaceBehindRemoteAnimationRequested = false; Loading Loading @@ -2790,12 +2808,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking"); mWakeAndUnlocking = true; // We're going to animate in the Launcher, so ask WM to clear the task snapshot so we don't // initially display an old snapshot with all of the icons visible. We're System UI, so // we're allowed to pass in null to ask WM to find the home activity for us to prevent // needing to IPC to Launcher. ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(null /* homeActivity */); keyguardDone(); Trace.endSection(); } Loading packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +66 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ import com.android.systemui.flags.FeatureFlags import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.policy.KeyguardStateController import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Test Loading Loading @@ -125,4 +126,69 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished( false /* cancelled */) } /** * If we requested that the surface behind be made visible, and we're not flinging away the * keyguard, it means that we're swiping to unlock and want the surface visible so it can follow * the user's touch event as they swipe to unlock. * * In this case, we should verify that the surface was made visible via the alpha fade in * animator, and verify that we did not start the canned animation to animate the surface in * (since it's supposed to be following the touch events). */ @Test fun fadeInSurfaceBehind_ifRequestedShowSurface_butNotFlinging() { `when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(false) keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTarget, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ ) assertTrue(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning) assertFalse(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) } /** * We requested the surface behind to be made visible, but we're now flinging to dismiss the * keyguard. This means this was a swipe to dismiss gesture but the user flung the keyguard and * lifted their finger while we were requesting the surface be made visible. * * In this case, we should verify that we are playing the canned unlock animation and not * simply fading in the surface. */ @Test fun playCannedUnlockAnimation_ifRequestedShowSurface_andFlinging() { `when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(true) keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTarget, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ ) assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning) } /** * We never requested the surface behind to be made visible, which means no swiping to unlock * ever happened and we're just playing the simple canned animation (happens via UDFPS unlock, * long press on the lock icon, etc). * * In this case, we should verify that we are playing the canned unlock animation and not * simply fading in the surface. */ @Test fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTarget, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ ) assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning) } } No newline at end of file Loading
core/java/android/view/WindowManager.java +8 −0 Original line number Diff line number Diff line Loading @@ -487,6 +487,13 @@ public interface WindowManager extends ViewManager { */ int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION = 0x8; /** * Transition flag: Keyguard is going away to the launcher, and it needs us to clear the task * snapshot of the launcher because it has changed something in the Launcher window. * @hide */ int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT = 0x16; /** * Transition flag: App is crashed. * @hide Loading Loading @@ -527,6 +534,7 @@ public interface WindowManager extends ViewManager { TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION, TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER, TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION, TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT, TRANSIT_FLAG_APP_CRASHED, TRANSIT_FLAG_OPEN_BEHIND, TRANSIT_FLAG_KEYGUARD_LOCKED, Loading
core/java/android/view/WindowManagerPolicyConstants.java +1 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ public interface WindowManagerPolicyConstants { int KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS = 1 << 1; int KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER = 1 << 2; int KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS = 1 << 3; int KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT = 1 << 4; // Flags used for indicating whether the internal and/or external input devices // of some type are available. Loading
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +16 −7 Original line number Diff line number Diff line Loading @@ -451,12 +451,22 @@ class KeyguardUnlockAnimationController @Inject constructor( surfaceBehindRemoteAnimationTarget = target surfaceBehindRemoteAnimationStartTime = startTime // If we specifically requested that the surface behind be made visible, it means we are // swiping to unlock. In that case, the surface visibility is tied to the dismiss amount, // and we'll handle that in onKeyguardDismissAmountChanged(). If we didn't request that, the // keyguard is being dismissed for a different reason (biometric auth, etc.) and we should // play a canned animation to make the surface fully visible. if (!requestedShowSurfaceBehindKeyguard) { // If we specifically requested that the surface behind be made visible (vs. it being made // visible because we're unlocking), then we're in the middle of a swipe-to-unlock touch // gesture and the surface behind the keyguard should be made visible. if (requestedShowSurfaceBehindKeyguard) { // Fade in the surface, as long as we're not now flinging. The touch gesture ending in // a fling during the time it takes the keyguard exit animation to start is an edge // case race condition, and we'll handle it by playing a canned animation on the // now-visible surface to finish unlocking. if (!keyguardStateController.isFlingingToDismissKeyguard) { fadeInSurfaceBehind() } else { playCannedUnlockAnimation() } } else { // The surface was made visible since we're unlocking not from a swipe (fingerprint, // lock icon long-press, etc). Play the full unlock animation. playCannedUnlockAnimation() } Loading Loading @@ -612,7 +622,6 @@ class KeyguardUnlockAnimationController @Inject constructor( !keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) { keyguardViewMediator.get().showSurfaceBehindKeyguard() fadeInSurfaceBehind() } else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD && keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) { // We're no longer past the threshold but we are showing the surface. Animate it Loading
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +24 −12 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.systemui.keyguard; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN; Loading Loading @@ -119,7 +121,6 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeDepthController; Loading Loading @@ -2301,8 +2302,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, int flags = 0; if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock() || mWakeAndUnlocking && !mWallpaperSupportsAmbientMode) { flags |= WindowManagerPolicyConstants .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; flags |= KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; } if (mKeyguardViewControllerLazy.get().isGoingToNotificationShade() || mWakeAndUnlocking && mWallpaperSupportsAmbientMode) { Loading @@ -2318,6 +2318,15 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, .KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS; } // If we are unlocking to the launcher, clear the snapshot so that any changes as part // of the in-window animations are reflected. This is needed even if we're not actually // playing in-window animations for this particular unlock since a previous unlock might // have changed the Launcher state. if (mWakeAndUnlocking && KeyguardUnlockAnimationController.Companion.isNexusLauncherUnderneath()) { flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; } mUpdateMonitor.setKeyguardGoingAway(true); mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(true); Loading Loading @@ -2622,9 +2631,18 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mSurfaceBehindRemoteAnimationRequested = true; try { ActivityTaskManager.getService().keyguardGoingAway( WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS | WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER); int flags = KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS | KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; // If we are unlocking to the launcher, clear the snapshot so that any changes as part // of the in-window animations are reflected. This is needed even if we're not actually // playing in-window animations for this particular unlock since a previous unlock might // have changed the Launcher state. if (KeyguardUnlockAnimationController.Companion.isNexusLauncherUnderneath()) { flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; } ActivityTaskManager.getService().keyguardGoingAway(flags); mKeyguardStateController.notifyKeyguardGoingAway(true); } catch (RemoteException e) { mSurfaceBehindRemoteAnimationRequested = false; Loading Loading @@ -2790,12 +2808,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking"); mWakeAndUnlocking = true; // We're going to animate in the Launcher, so ask WM to clear the task snapshot so we don't // initially display an old snapshot with all of the icons visible. We're System UI, so // we're allowed to pass in null to ask WM to find the home activity for us to prevent // needing to IPC to Launcher. ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(null /* homeActivity */); keyguardDone(); Trace.endSection(); } Loading
packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +66 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ import com.android.systemui.flags.FeatureFlags import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.policy.KeyguardStateController import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Test Loading Loading @@ -125,4 +126,69 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished( false /* cancelled */) } /** * If we requested that the surface behind be made visible, and we're not flinging away the * keyguard, it means that we're swiping to unlock and want the surface visible so it can follow * the user's touch event as they swipe to unlock. * * In this case, we should verify that the surface was made visible via the alpha fade in * animator, and verify that we did not start the canned animation to animate the surface in * (since it's supposed to be following the touch events). */ @Test fun fadeInSurfaceBehind_ifRequestedShowSurface_butNotFlinging() { `when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(false) keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTarget, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ ) assertTrue(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning) assertFalse(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) } /** * We requested the surface behind to be made visible, but we're now flinging to dismiss the * keyguard. This means this was a swipe to dismiss gesture but the user flung the keyguard and * lifted their finger while we were requesting the surface be made visible. * * In this case, we should verify that we are playing the canned unlock animation and not * simply fading in the surface. */ @Test fun playCannedUnlockAnimation_ifRequestedShowSurface_andFlinging() { `when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(true) keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTarget, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ ) assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning) } /** * We never requested the surface behind to be made visible, which means no swiping to unlock * ever happened and we're just playing the simple canned animation (happens via UDFPS unlock, * long press on the lock icon, etc). * * In this case, we should verify that we are playing the canned unlock animation and not * simply fading in the surface. */ @Test fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTarget, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ ) assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning) } } No newline at end of file