diff options
3 files changed, 113 insertions, 87 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt index bd75ab2adb54..6f38f4f53b7c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt @@ -241,9 +241,8 @@ class KeyguardUnlockAnimationController @Inject constructor( */ @VisibleForTesting var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null - private var surfaceBehindRemoteAnimationTarget: RemoteAnimationTarget? = null + private var surfaceBehindRemoteAnimationTargets: Array<RemoteAnimationTarget>? = null private var surfaceBehindRemoteAnimationStartTime: Long = 0 - private var surfaceBehindParams: SyncRtSurfaceTransactionApplier.SurfaceParams? = null /** * Alpha value applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the @@ -458,7 +457,7 @@ class KeyguardUnlockAnimationController @Inject constructor( * (fingerprint, tap, etc.) and the keyguard is going away. */ fun notifyStartSurfaceBehindRemoteAnimation( - target: RemoteAnimationTarget, + targets: Array<RemoteAnimationTarget>, startTime: Long, requestedShowSurfaceBehindKeyguard: Boolean ) { @@ -467,10 +466,7 @@ class KeyguardUnlockAnimationController @Inject constructor( keyguardViewController.viewRootImpl.view) } - // New animation, new params. - surfaceBehindParams = null - - surfaceBehindRemoteAnimationTarget = target + surfaceBehindRemoteAnimationTargets = targets surfaceBehindRemoteAnimationStartTime = startTime // If we specifically requested that the surface behind be made visible (vs. it being made @@ -597,7 +593,7 @@ class KeyguardUnlockAnimationController @Inject constructor( * keyguard dismiss amount and the method of dismissal. */ private fun updateSurfaceBehindAppearAmount() { - if (surfaceBehindRemoteAnimationTarget == null) { + if (surfaceBehindRemoteAnimationTargets == null) { return } @@ -715,63 +711,60 @@ class KeyguardUnlockAnimationController @Inject constructor( * cancelled). */ fun setSurfaceBehindAppearAmount(amount: Float) { - if (surfaceBehindRemoteAnimationTarget == null) { - return - } + surfaceBehindRemoteAnimationTargets?.forEach { surfaceBehindRemoteAnimationTarget -> + val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget.screenSpaceBounds.height() + + var scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR + + (1f - SURFACE_BEHIND_START_SCALE_FACTOR) * + MathUtils.clamp(amount, 0f, 1f)) - // Otherwise, animate in the surface's scale/transltion. - val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.height() - - var scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR + - (1f - SURFACE_BEHIND_START_SCALE_FACTOR) * - MathUtils.clamp(amount, 0f, 1f)) - - // If we're dismissing via swipe to the Launcher, we'll play in-window scale animations, so - // don't also scale the window. - if (keyguardStateController.isDismissingFromSwipe && - willUnlockWithInWindowLauncherAnimations) { - scaleFactor = 1f - } - - // Scale up from a point at the center-bottom of the surface. - surfaceBehindMatrix.setScale( - scaleFactor, - scaleFactor, - surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.width() / 2f, - surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y - ) - - // Translate up from the bottom. - surfaceBehindMatrix.postTranslate( - 0f, - surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount) - ) - - // If we're snapping the keyguard back, immediately begin fading it out. - val animationAlpha = - if (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount - else surfaceBehindAlpha - - // SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is unable - // to draw - val sc: SurfaceControl? = surfaceBehindRemoteAnimationTarget?.leash - if (keyguardViewController.viewRootImpl.view?.visibility != View.VISIBLE && - sc?.isValid == true) { - with(SurfaceControl.Transaction()) { - setMatrix(sc, surfaceBehindMatrix, tmpFloat) - setCornerRadius(sc, roundedCornerRadius) - setAlpha(sc, animationAlpha) - apply() + // If we're dismissing via swipe to the Launcher, we'll play in-window scale animations, + // so don't also scale the window. + if (keyguardStateController.isDismissingFromSwipe && + willUnlockWithInWindowLauncherAnimations) { + scaleFactor = 1f } - } else { - applyParamsToSurface( - SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( - surfaceBehindRemoteAnimationTarget!!.leash) - .withMatrix(surfaceBehindMatrix) - .withCornerRadius(roundedCornerRadius) - .withAlpha(animationAlpha) - .build() + + // Translate up from the bottom. + surfaceBehindMatrix.setTranslate( + surfaceBehindRemoteAnimationTarget.screenSpaceBounds.left.toFloat(), + surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount) ) + + // Scale up from a point at the center-bottom of the surface. + surfaceBehindMatrix.postScale( + scaleFactor, + scaleFactor, + keyguardViewController.viewRootImpl.width / 2f, + surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y + ) + + // If we're snapping the keyguard back, immediately begin fading it out. + val animationAlpha = + if (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount + else surfaceBehindAlpha + + // SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is + // unable to draw + val sc: SurfaceControl? = surfaceBehindRemoteAnimationTarget.leash + if (keyguardViewController.viewRootImpl.view?.visibility != View.VISIBLE && + sc?.isValid == true) { + with(SurfaceControl.Transaction()) { + setMatrix(sc, surfaceBehindMatrix, tmpFloat) + setCornerRadius(sc, roundedCornerRadius) + setAlpha(sc, animationAlpha) + apply() + } + } else { + applyParamsToSurface( + SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( + surfaceBehindRemoteAnimationTarget.leash) + .withMatrix(surfaceBehindMatrix) + .withCornerRadius(roundedCornerRadius) + .withAlpha(animationAlpha) + .build() + ) + } } } @@ -796,8 +789,7 @@ class KeyguardUnlockAnimationController @Inject constructor( launcherUnlockController?.setUnlockAmount(1f, false /* forceIfAnimating */) // That target is no longer valid since the animation finished, null it out. - surfaceBehindRemoteAnimationTarget = null - surfaceBehindParams = null + surfaceBehindRemoteAnimationTargets = null playingCannedUnlockAnimation = false willUnlockWithInWindowLauncherAnimations = false @@ -829,7 +821,6 @@ class KeyguardUnlockAnimationController @Inject constructor( private fun applyParamsToSurface(params: SyncRtSurfaceTransactionApplier.SurfaceParams) { surfaceTransactionApplier!!.scheduleApply(params) - surfaceBehindParams = params } private fun fadeInSurfaceBehind() { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index d4e0f061ba06..5dcdb109aae8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -2587,18 +2587,10 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mInteractionJankMonitor.begin( createInteractionJankMonitorConf("DismissPanel")); - // Apply the opening animation on root task if exists - RemoteAnimationTarget aniTarget = apps[0]; - for (RemoteAnimationTarget tmpTarget : apps) { - if (tmpTarget.taskId != -1 && !tmpTarget.hasAnimatingParent) { - aniTarget = tmpTarget; - break; - } - } // Pass the surface and metadata to the unlock animation controller. mKeyguardUnlockAnimationControllerLazy.get() .notifyStartSurfaceBehindRemoteAnimation( - aniTarget, startTime, mSurfaceBehindRemoteAnimationRequested); + apps, startTime, mSurfaceBehindRemoteAnimationRequested); } else { mInteractionJankMonitor.begin( createInteractionJankMonitorConf("RemoteAnimationDisabled")); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt index eecbee56d203..a78c902a1f30 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt @@ -27,11 +27,11 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor.forClass import org.mockito.Mock +import org.mockito.Mockito.`when` import org.mockito.Mockito.mock import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions -import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @@ -60,7 +60,18 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var launcherUnlockAnimationController: ILauncherUnlockAnimationController.Stub - private lateinit var remoteAnimationTarget: RemoteAnimationTarget + private var surfaceControl1 = mock(SurfaceControl::class.java) + private var remoteTarget1 = RemoteAnimationTarget( + 0 /* taskId */, 0, surfaceControl1, false, Rect(), Rect(), 0, Point(), Rect(), Rect(), + mock(WindowConfiguration::class.java), false, surfaceControl1, Rect(), + mock(ActivityManager.RunningTaskInfo::class.java), false) + + private var surfaceControl2 = mock(SurfaceControl::class.java) + private var remoteTarget2 = RemoteAnimationTarget( + 1 /* taskId */, 0, surfaceControl2, false, Rect(), Rect(), 0, Point(), Rect(), Rect(), + mock(WindowConfiguration::class.java), false, surfaceControl2, Rect(), + mock(ActivityManager.RunningTaskInfo::class.java), false) + private lateinit var remoteAnimationTargets: Array<RemoteAnimationTarget> @Before fun setUp() { @@ -77,10 +88,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { // All of these fields are final, so we can't mock them, but are needed so that the surface // appear amount setter doesn't short circuit. - remoteAnimationTarget = RemoteAnimationTarget( - 0, 0, null, false, Rect(), Rect(), 0, Point(), Rect(), Rect(), - mock(WindowConfiguration::class.java), false, mock(SurfaceControl::class.java), Rect(), - mock(ActivityManager.RunningTaskInfo::class.java), false) + remoteAnimationTargets = arrayOf(remoteTarget1) // Set the surface applier to our mock so that we can verify the arguments passed to it. // This applier does not have any side effects within the unlock animation controller, so @@ -99,7 +107,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true) keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( - remoteAnimationTarget, + remoteAnimationTargets, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ ) @@ -130,7 +138,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(false) keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( - remoteAnimationTarget, + remoteAnimationTargets, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ ) @@ -154,7 +162,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { `when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(false) keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( - remoteAnimationTarget, + remoteAnimationTargets, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ ) @@ -176,7 +184,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { `when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(true) keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( - remoteAnimationTarget, + remoteAnimationTargets, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ ) @@ -196,7 +204,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { @Test fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( - remoteAnimationTarget, + remoteAnimationTargets, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ ) @@ -210,7 +218,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { `when`(notificationShadeWindowController.isLaunchingActivity).thenReturn(true) keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( - remoteAnimationTarget, + remoteAnimationTargets, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ ) @@ -225,11 +233,46 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.willUnlockWithInWindowLauncherAnimations = true keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( - remoteAnimationTarget, + remoteAnimationTargets, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ ) assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) } + + /** + * If we are not wake and unlocking, we expect the unlock animation to play normally. + */ + @Test + fun surfaceAnimation_multipleTargets() { + keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( + arrayOf(remoteTarget1, remoteTarget2), + 0 /* startTime */, + false /* requestedShowSurfaceBehindKeyguard */ + ) + + // Set appear to 50%, we'll just verify that we're not applying the identity matrix which + // means an animation is in progress. + keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(0.5f) + + val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java) + verify(surfaceTransactionApplier, times(2)).scheduleApply(captor.capture()) + + val allParams = captor.allValues + + val remainingTargets = mutableListOf(surfaceControl1, surfaceControl2) + allParams.forEach { params -> + assertTrue(!params.matrix.isIdentity) + remainingTargets.remove(params.surface) + } + + // Make sure we called applyParams with each of the surface controls once. The order does + // not matter, so don't explicitly check for that. + assertTrue(remainingTargets.isEmpty()) + + // Since the animation is running, we should not have finished the remote animation. + verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished( + false /* cancelled */) + } } |