Loading packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +73 −0 Original line number Original line Diff line number Diff line Loading @@ -245,6 +245,7 @@ class KeyguardUnlockAnimationController @Inject constructor( @VisibleForTesting @VisibleForTesting var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null private var surfaceBehindRemoteAnimationTargets: Array<RemoteAnimationTarget>? = null private var surfaceBehindRemoteAnimationTargets: Array<RemoteAnimationTarget>? = null private var wallpaperTargets: Array<RemoteAnimationTarget>? = null private var surfaceBehindRemoteAnimationStartTime: Long = 0 private var surfaceBehindRemoteAnimationStartTime: Long = 0 /** /** Loading @@ -257,9 +258,13 @@ class KeyguardUnlockAnimationController @Inject constructor( */ */ private var surfaceBehindAlpha = 1f private var surfaceBehindAlpha = 1f private var wallpaperAlpha = 1f @VisibleForTesting @VisibleForTesting var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f) var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f) var wallpaperAlphaAnimator = ValueAnimator.ofFloat(0f, 1f) /** /** * Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the * Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the * app/launcher behind the keyguard. * app/launcher behind the keyguard. Loading Loading @@ -335,6 +340,27 @@ class KeyguardUnlockAnimationController @Inject constructor( }) }) } } with(wallpaperAlphaAnimator) { duration = LAUNCHER_ICONS_ANIMATION_DURATION_MS interpolator = Interpolators.ALPHA_OUT addUpdateListener { valueAnimator: ValueAnimator -> wallpaperAlpha = valueAnimator.animatedValue as Float setWallpaperAppearAmount(wallpaperAlpha) } addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { Log.d(TAG, "wallpaperAlphaAnimator#onAnimationEnd, animation ended ") if (wallpaperAlpha == 1f) { wallpaperTargets = null keyguardViewMediator.get().finishExitRemoteAnimation() } else { Log.d(TAG, "wallpaperAlphaAnimator#onAnimationEnd, " + "animation was cancelled: skipping finishAnimation()") } } }) } with(surfaceBehindEntryAnimator) { with(surfaceBehindEntryAnimator) { duration = UNLOCK_ANIMATION_DURATION_MS duration = UNLOCK_ANIMATION_DURATION_MS startDelay = UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS startDelay = UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS Loading @@ -361,6 +387,11 @@ class KeyguardUnlockAnimationController @Inject constructor( context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat() context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat() } } fun isAnyKeyguyardAnimatorPlaying(): Boolean { return surfaceBehindAlphaAnimator.isStarted || wallpaperAlphaAnimator.isStarted || surfaceBehindEntryAnimator.isStarted } /** /** * Add a listener to be notified of various stages of the unlock animation. * Add a listener to be notified of various stages of the unlock animation. */ */ Loading Loading @@ -492,6 +523,7 @@ class KeyguardUnlockAnimationController @Inject constructor( */ */ fun notifyStartSurfaceBehindRemoteAnimation( fun notifyStartSurfaceBehindRemoteAnimation( targets: Array<RemoteAnimationTarget>, targets: Array<RemoteAnimationTarget>, wallpapers: Array<RemoteAnimationTarget>, startTime: Long, startTime: Long, requestedShowSurfaceBehindKeyguard: Boolean requestedShowSurfaceBehindKeyguard: Boolean ) { ) { Loading @@ -501,8 +533,11 @@ class KeyguardUnlockAnimationController @Inject constructor( } } surfaceBehindRemoteAnimationTargets = targets surfaceBehindRemoteAnimationTargets = targets wallpaperTargets = wallpapers surfaceBehindRemoteAnimationStartTime = startTime surfaceBehindRemoteAnimationStartTime = startTime fadeInWallpaper() // If we specifically requested that the surface behind be made visible (vs. it being made // 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 // 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 so that we can animate // gesture and the surface behind the keyguard should be made visible so that we can animate Loading Loading @@ -838,6 +873,38 @@ class KeyguardUnlockAnimationController @Inject constructor( } } } } /** * Modify the opacity of a wallpaper window. */ fun setWallpaperAppearAmount(amount: Float) { wallpaperTargets?.forEach { wallpaper -> val animationAlpha = when { // If the screen has turned back off, the unlock animation is going to be cancelled, // so set the surface alpha to 0f so it's no longer visible. !powerManager.isInteractive -> 0f else -> amount } // SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is // unable to draw val sc: SurfaceControl? = wallpaper.leash if (keyguardViewController.viewRootImpl.view?.visibility != View.VISIBLE && sc?.isValid == true) { with(SurfaceControl.Transaction()) { setAlpha(sc, animationAlpha) apply() } } else { applyParamsToSurface( SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( wallpaper.leash) .withAlpha(animationAlpha) .build() ) } } } /** /** * Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and * Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and * we should clean up all of our state. * we should clean up all of our state. Loading Loading @@ -903,6 +970,12 @@ class KeyguardUnlockAnimationController @Inject constructor( surfaceBehindAlphaAnimator.start() surfaceBehindAlphaAnimator.start() } } private fun fadeInWallpaper() { Log.d(TAG, "fadeInWallpaper") wallpaperAlphaAnimator.cancel() wallpaperAlphaAnimator.start() } private fun fadeOutSurfaceBehind() { private fun fadeOutSurfaceBehind() { Log.d(TAG, "fadeOutSurfaceBehind") Log.d(TAG, "fadeOutSurfaceBehind") surfaceBehindAlphaAnimator.cancel() surfaceBehindAlphaAnimator.cancel() Loading packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +19 −1 Original line number Original line Diff line number Diff line Loading @@ -159,6 +159,7 @@ import dagger.Lazy; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.concurrent.Executor; import java.util.concurrent.Executor; /** /** Loading Loading @@ -2710,9 +2711,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, CUJ_LOCKSCREEN_UNLOCK_ANIMATION, "DismissPanel")); CUJ_LOCKSCREEN_UNLOCK_ANIMATION, "DismissPanel")); // Pass the surface and metadata to the unlock animation controller. // Pass the surface and metadata to the unlock animation controller. RemoteAnimationTarget[] openingWallpapers = Arrays.stream(wallpapers).filter( w -> w.mode == RemoteAnimationTarget.MODE_OPENING).toArray( RemoteAnimationTarget[]::new); mKeyguardUnlockAnimationControllerLazy.get() mKeyguardUnlockAnimationControllerLazy.get() .notifyStartSurfaceBehindRemoteAnimation( .notifyStartSurfaceBehindRemoteAnimation( apps, startTime, mSurfaceBehindRemoteAnimationRequested); apps, openingWallpapers, startTime, mSurfaceBehindRemoteAnimationRequested); } else { } else { mInteractionJankMonitor.begin( mInteractionJankMonitor.begin( createInteractionJankMonitorConf( createInteractionJankMonitorConf( Loading Loading @@ -2961,6 +2966,19 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mSurfaceBehindRemoteAnimationRequested = false; mSurfaceBehindRemoteAnimationRequested = false; mSurfaceBehindRemoteAnimationRunning = false; mSurfaceBehindRemoteAnimationRunning = false; mKeyguardStateController.notifyKeyguardGoingAway(false); mKeyguardStateController.notifyKeyguardGoingAway(false); finishExitRemoteAnimation(); } void finishExitRemoteAnimation() { if (mKeyguardUnlockAnimationControllerLazy.get().isAnyKeyguyardAnimatorPlaying() || mKeyguardStateController.isDismissingFromSwipe()) { // If the animation is ongoing, or we are not done with the swipe gesture, // it's too early to terminate the animation Log.d(TAG, "finishAnimation not executing now because " + "not all animations have finished"); return; } Log.d(TAG, "finishAnimation executing"); if (mSurfaceBehindRemoteAnimationFinishedCallback != null) { if (mSurfaceBehindRemoteAnimationFinishedCallback != null) { try { try { Loading packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +82 −18 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.argThat import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever import junit.framework.Assert.assertEquals import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import junit.framework.Assert.assertFalse Loading @@ -28,13 +29,14 @@ import org.junit.After import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test import org.junit.runner.RunWith import org.junit.runner.RunWith import org.mockito.ArgumentCaptor.forClass import org.mockito.Mock import org.mockito.Mock import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.mock import org.mockito.Mockito.mock import org.mockito.Mockito.times import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations import java.util.function.Predicate @RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class) @RunWithLooper @RunWithLooper Loading Loading @@ -77,6 +79,13 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { mock(ActivityManager.RunningTaskInfo::class.java), false) mock(ActivityManager.RunningTaskInfo::class.java), false) private lateinit var remoteAnimationTargets: Array<RemoteAnimationTarget> private lateinit var remoteAnimationTargets: Array<RemoteAnimationTarget> private var surfaceControlWp = mock(SurfaceControl::class.java) private var wallpaperTarget = RemoteAnimationTarget( 2 /* taskId */, 0, surfaceControlWp, false, Rect(), Rect(), 0, Point(), Rect(), Rect(), mock(WindowConfiguration::class.java), false, surfaceControlWp, Rect(), mock(ActivityManager.RunningTaskInfo::class.java), false) private lateinit var wallpaperTargets: Array<RemoteAnimationTarget> @Before @Before fun setUp() { fun setUp() { MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this) Loading @@ -94,6 +103,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { // All of these fields are final, so we can't mock them, but are needed so that the surface // 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. // appear amount setter doesn't short circuit. remoteAnimationTargets = arrayOf(remoteTarget1) remoteAnimationTargets = arrayOf(remoteTarget1) wallpaperTargets = arrayOf(wallpaperTarget) // Set the surface applier to our mock so that we can verify the arguments passed to it. // 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 // This applier does not have any side effects within the unlock animation controller, so Loading @@ -119,18 +129,20 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, arrayOf(), 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java) val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture()) verify(surfaceTransactionApplier, times(1)).scheduleApply( captorSb.capture { sp -> sp.surface == surfaceControl1 }) val params = captor.value val params = captorSb.getLastValue() // We expect that we've instantly set the surface behind to alpha = 1f, and have no // We expect that we've instantly set the surface behind to alpha = 1f, and have no // transforms (translate, scale) on its matrix. // transforms (translate, scale) on its matrix. assertEquals(params.alpha, 1f) assertEquals(1f, params.alpha) assertTrue(params.matrix.isIdentity) assertTrue(params.matrix.isIdentity) // Also expect we've immediately asked the keyguard view mediator to finish the remote // Also expect we've immediately asked the keyguard view mediator to finish the remote Loading @@ -150,6 +162,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -174,6 +187,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ true /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -196,6 +210,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ true /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -216,6 +231,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() { fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -230,6 +246,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ true /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -245,6 +262,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -259,6 +277,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { fun surfaceAnimation_multipleTargets() { fun surfaceAnimation_multipleTargets() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( arrayOf(remoteTarget1, remoteTarget2), arrayOf(remoteTarget1, remoteTarget2), wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -267,10 +286,15 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { // means an animation is in progress. // means an animation is in progress. keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(0.5f) keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(0.5f) val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java) val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, times(2)).scheduleApply(captor.capture()) verify(surfaceTransactionApplier, times(2)).scheduleApply(captorSb .capture { sp -> sp.surface == surfaceControl1 || sp.surface == surfaceControl2 }) val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, times(1).description( "WallpaperSurface was expected to receive scheduleApply once" )).scheduleApply(captorWp.capture { sp -> sp.surface == surfaceControlWp}) val allParams = captor.allValues val allParams = captorSb.getAllValues() val remainingTargets = mutableListOf(surfaceControl1, surfaceControl2) val remainingTargets = mutableListOf(surfaceControl1, surfaceControl2) allParams.forEach { params -> allParams.forEach { params -> Loading @@ -293,20 +317,29 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f) keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f) keyguardUnlockAnimationController.setWallpaperAppearAmount(1f) val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java) val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture()) verify(surfaceTransactionApplier, times(1)).scheduleApply( captorSb.capture { sp -> sp.surface == surfaceControl1}) val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, atLeastOnce().description("Wallpaper surface has not " + "received scheduleApply")).scheduleApply( captorWp.capture { sp -> sp.surface == surfaceControlWp }) val params = captor.value val params = captorSb.getLastValue() // We expect that we've set the surface behind to alpha = 0f since we're not interactive. // We expect that we've set the surface behind to alpha = 0f since we're not interactive. assertEquals(params.alpha, 0f) assertEquals(0f, params.alpha) assertTrue(params.matrix.isIdentity) assertTrue(params.matrix.isIdentity) assertEquals("Wallpaper surface was expected to have opacity 0", 0f, captorWp.getLastValue().alpha) verifyNoMoreInteractions(surfaceTransactionApplier) verifyNoMoreInteractions(surfaceTransactionApplier) } } Loading @@ -317,19 +350,50 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f) keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f) keyguardUnlockAnimationController.setWallpaperAppearAmount(1f) val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java) verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture()) val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, times(1)).scheduleApply( val params = captor.value captorSb.capture { sp -> sp.surface == surfaceControl1 }) assertEquals(params.alpha, 1f) val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, atLeastOnce().description("Wallpaper surface has not " + "received scheduleApply")).scheduleApply( captorWp.capture { sp -> sp.surface == surfaceControlWp }) val params = captorSb.getLastValue() assertEquals(1f, params.alpha) assertTrue(params.matrix.isIdentity) assertTrue(params.matrix.isIdentity) assertEquals("Wallpaper surface was expected to have opacity 1", 1f, captorWp.getLastValue().alpha) verifyNoMoreInteractions(surfaceTransactionApplier) verifyNoMoreInteractions(surfaceTransactionApplier) } } private class ArgThatCaptor<T> { private var allArgs: MutableList<T> = mutableListOf() fun capture(predicate: Predicate<T>): T { return argThat{x: T -> if (predicate.test(x)) { allArgs.add(x) return@argThat true } return@argThat false } } fun getLastValue(): T { return allArgs.last() } fun getAllValues(): List<T> { return allArgs } } } } Loading
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +73 −0 Original line number Original line Diff line number Diff line Loading @@ -245,6 +245,7 @@ class KeyguardUnlockAnimationController @Inject constructor( @VisibleForTesting @VisibleForTesting var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null private var surfaceBehindRemoteAnimationTargets: Array<RemoteAnimationTarget>? = null private var surfaceBehindRemoteAnimationTargets: Array<RemoteAnimationTarget>? = null private var wallpaperTargets: Array<RemoteAnimationTarget>? = null private var surfaceBehindRemoteAnimationStartTime: Long = 0 private var surfaceBehindRemoteAnimationStartTime: Long = 0 /** /** Loading @@ -257,9 +258,13 @@ class KeyguardUnlockAnimationController @Inject constructor( */ */ private var surfaceBehindAlpha = 1f private var surfaceBehindAlpha = 1f private var wallpaperAlpha = 1f @VisibleForTesting @VisibleForTesting var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f) var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f) var wallpaperAlphaAnimator = ValueAnimator.ofFloat(0f, 1f) /** /** * Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the * Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the * app/launcher behind the keyguard. * app/launcher behind the keyguard. Loading Loading @@ -335,6 +340,27 @@ class KeyguardUnlockAnimationController @Inject constructor( }) }) } } with(wallpaperAlphaAnimator) { duration = LAUNCHER_ICONS_ANIMATION_DURATION_MS interpolator = Interpolators.ALPHA_OUT addUpdateListener { valueAnimator: ValueAnimator -> wallpaperAlpha = valueAnimator.animatedValue as Float setWallpaperAppearAmount(wallpaperAlpha) } addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { Log.d(TAG, "wallpaperAlphaAnimator#onAnimationEnd, animation ended ") if (wallpaperAlpha == 1f) { wallpaperTargets = null keyguardViewMediator.get().finishExitRemoteAnimation() } else { Log.d(TAG, "wallpaperAlphaAnimator#onAnimationEnd, " + "animation was cancelled: skipping finishAnimation()") } } }) } with(surfaceBehindEntryAnimator) { with(surfaceBehindEntryAnimator) { duration = UNLOCK_ANIMATION_DURATION_MS duration = UNLOCK_ANIMATION_DURATION_MS startDelay = UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS startDelay = UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS Loading @@ -361,6 +387,11 @@ class KeyguardUnlockAnimationController @Inject constructor( context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat() context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat() } } fun isAnyKeyguyardAnimatorPlaying(): Boolean { return surfaceBehindAlphaAnimator.isStarted || wallpaperAlphaAnimator.isStarted || surfaceBehindEntryAnimator.isStarted } /** /** * Add a listener to be notified of various stages of the unlock animation. * Add a listener to be notified of various stages of the unlock animation. */ */ Loading Loading @@ -492,6 +523,7 @@ class KeyguardUnlockAnimationController @Inject constructor( */ */ fun notifyStartSurfaceBehindRemoteAnimation( fun notifyStartSurfaceBehindRemoteAnimation( targets: Array<RemoteAnimationTarget>, targets: Array<RemoteAnimationTarget>, wallpapers: Array<RemoteAnimationTarget>, startTime: Long, startTime: Long, requestedShowSurfaceBehindKeyguard: Boolean requestedShowSurfaceBehindKeyguard: Boolean ) { ) { Loading @@ -501,8 +533,11 @@ class KeyguardUnlockAnimationController @Inject constructor( } } surfaceBehindRemoteAnimationTargets = targets surfaceBehindRemoteAnimationTargets = targets wallpaperTargets = wallpapers surfaceBehindRemoteAnimationStartTime = startTime surfaceBehindRemoteAnimationStartTime = startTime fadeInWallpaper() // If we specifically requested that the surface behind be made visible (vs. it being made // 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 // 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 so that we can animate // gesture and the surface behind the keyguard should be made visible so that we can animate Loading Loading @@ -838,6 +873,38 @@ class KeyguardUnlockAnimationController @Inject constructor( } } } } /** * Modify the opacity of a wallpaper window. */ fun setWallpaperAppearAmount(amount: Float) { wallpaperTargets?.forEach { wallpaper -> val animationAlpha = when { // If the screen has turned back off, the unlock animation is going to be cancelled, // so set the surface alpha to 0f so it's no longer visible. !powerManager.isInteractive -> 0f else -> amount } // SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is // unable to draw val sc: SurfaceControl? = wallpaper.leash if (keyguardViewController.viewRootImpl.view?.visibility != View.VISIBLE && sc?.isValid == true) { with(SurfaceControl.Transaction()) { setAlpha(sc, animationAlpha) apply() } } else { applyParamsToSurface( SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( wallpaper.leash) .withAlpha(animationAlpha) .build() ) } } } /** /** * Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and * Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and * we should clean up all of our state. * we should clean up all of our state. Loading Loading @@ -903,6 +970,12 @@ class KeyguardUnlockAnimationController @Inject constructor( surfaceBehindAlphaAnimator.start() surfaceBehindAlphaAnimator.start() } } private fun fadeInWallpaper() { Log.d(TAG, "fadeInWallpaper") wallpaperAlphaAnimator.cancel() wallpaperAlphaAnimator.start() } private fun fadeOutSurfaceBehind() { private fun fadeOutSurfaceBehind() { Log.d(TAG, "fadeOutSurfaceBehind") Log.d(TAG, "fadeOutSurfaceBehind") surfaceBehindAlphaAnimator.cancel() surfaceBehindAlphaAnimator.cancel() Loading
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +19 −1 Original line number Original line Diff line number Diff line Loading @@ -159,6 +159,7 @@ import dagger.Lazy; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.concurrent.Executor; import java.util.concurrent.Executor; /** /** Loading Loading @@ -2710,9 +2711,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, CUJ_LOCKSCREEN_UNLOCK_ANIMATION, "DismissPanel")); CUJ_LOCKSCREEN_UNLOCK_ANIMATION, "DismissPanel")); // Pass the surface and metadata to the unlock animation controller. // Pass the surface and metadata to the unlock animation controller. RemoteAnimationTarget[] openingWallpapers = Arrays.stream(wallpapers).filter( w -> w.mode == RemoteAnimationTarget.MODE_OPENING).toArray( RemoteAnimationTarget[]::new); mKeyguardUnlockAnimationControllerLazy.get() mKeyguardUnlockAnimationControllerLazy.get() .notifyStartSurfaceBehindRemoteAnimation( .notifyStartSurfaceBehindRemoteAnimation( apps, startTime, mSurfaceBehindRemoteAnimationRequested); apps, openingWallpapers, startTime, mSurfaceBehindRemoteAnimationRequested); } else { } else { mInteractionJankMonitor.begin( mInteractionJankMonitor.begin( createInteractionJankMonitorConf( createInteractionJankMonitorConf( Loading Loading @@ -2961,6 +2966,19 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mSurfaceBehindRemoteAnimationRequested = false; mSurfaceBehindRemoteAnimationRequested = false; mSurfaceBehindRemoteAnimationRunning = false; mSurfaceBehindRemoteAnimationRunning = false; mKeyguardStateController.notifyKeyguardGoingAway(false); mKeyguardStateController.notifyKeyguardGoingAway(false); finishExitRemoteAnimation(); } void finishExitRemoteAnimation() { if (mKeyguardUnlockAnimationControllerLazy.get().isAnyKeyguyardAnimatorPlaying() || mKeyguardStateController.isDismissingFromSwipe()) { // If the animation is ongoing, or we are not done with the swipe gesture, // it's too early to terminate the animation Log.d(TAG, "finishAnimation not executing now because " + "not all animations have finished"); return; } Log.d(TAG, "finishAnimation executing"); if (mSurfaceBehindRemoteAnimationFinishedCallback != null) { if (mSurfaceBehindRemoteAnimationFinishedCallback != null) { try { try { Loading
packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +82 −18 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.argThat import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever import junit.framework.Assert.assertEquals import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import junit.framework.Assert.assertFalse Loading @@ -28,13 +29,14 @@ import org.junit.After import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test import org.junit.runner.RunWith import org.junit.runner.RunWith import org.mockito.ArgumentCaptor.forClass import org.mockito.Mock import org.mockito.Mock import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.mock import org.mockito.Mockito.mock import org.mockito.Mockito.times import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations import java.util.function.Predicate @RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class) @RunWithLooper @RunWithLooper Loading Loading @@ -77,6 +79,13 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { mock(ActivityManager.RunningTaskInfo::class.java), false) mock(ActivityManager.RunningTaskInfo::class.java), false) private lateinit var remoteAnimationTargets: Array<RemoteAnimationTarget> private lateinit var remoteAnimationTargets: Array<RemoteAnimationTarget> private var surfaceControlWp = mock(SurfaceControl::class.java) private var wallpaperTarget = RemoteAnimationTarget( 2 /* taskId */, 0, surfaceControlWp, false, Rect(), Rect(), 0, Point(), Rect(), Rect(), mock(WindowConfiguration::class.java), false, surfaceControlWp, Rect(), mock(ActivityManager.RunningTaskInfo::class.java), false) private lateinit var wallpaperTargets: Array<RemoteAnimationTarget> @Before @Before fun setUp() { fun setUp() { MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this) Loading @@ -94,6 +103,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { // All of these fields are final, so we can't mock them, but are needed so that the surface // 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. // appear amount setter doesn't short circuit. remoteAnimationTargets = arrayOf(remoteTarget1) remoteAnimationTargets = arrayOf(remoteTarget1) wallpaperTargets = arrayOf(wallpaperTarget) // Set the surface applier to our mock so that we can verify the arguments passed to it. // 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 // This applier does not have any side effects within the unlock animation controller, so Loading @@ -119,18 +129,20 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, arrayOf(), 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java) val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture()) verify(surfaceTransactionApplier, times(1)).scheduleApply( captorSb.capture { sp -> sp.surface == surfaceControl1 }) val params = captor.value val params = captorSb.getLastValue() // We expect that we've instantly set the surface behind to alpha = 1f, and have no // We expect that we've instantly set the surface behind to alpha = 1f, and have no // transforms (translate, scale) on its matrix. // transforms (translate, scale) on its matrix. assertEquals(params.alpha, 1f) assertEquals(1f, params.alpha) assertTrue(params.matrix.isIdentity) assertTrue(params.matrix.isIdentity) // Also expect we've immediately asked the keyguard view mediator to finish the remote // Also expect we've immediately asked the keyguard view mediator to finish the remote Loading @@ -150,6 +162,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -174,6 +187,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ true /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -196,6 +210,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ true /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -216,6 +231,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() { fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -230,6 +246,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, true /* requestedShowSurfaceBehindKeyguard */ true /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -245,6 +262,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -259,6 +277,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { fun surfaceAnimation_multipleTargets() { fun surfaceAnimation_multipleTargets() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( arrayOf(remoteTarget1, remoteTarget2), arrayOf(remoteTarget1, remoteTarget2), wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) Loading @@ -267,10 +286,15 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { // means an animation is in progress. // means an animation is in progress. keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(0.5f) keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(0.5f) val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java) val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, times(2)).scheduleApply(captor.capture()) verify(surfaceTransactionApplier, times(2)).scheduleApply(captorSb .capture { sp -> sp.surface == surfaceControl1 || sp.surface == surfaceControl2 }) val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, times(1).description( "WallpaperSurface was expected to receive scheduleApply once" )).scheduleApply(captorWp.capture { sp -> sp.surface == surfaceControlWp}) val allParams = captor.allValues val allParams = captorSb.getAllValues() val remainingTargets = mutableListOf(surfaceControl1, surfaceControl2) val remainingTargets = mutableListOf(surfaceControl1, surfaceControl2) allParams.forEach { params -> allParams.forEach { params -> Loading @@ -293,20 +317,29 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f) keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f) keyguardUnlockAnimationController.setWallpaperAppearAmount(1f) val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java) val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture()) verify(surfaceTransactionApplier, times(1)).scheduleApply( captorSb.capture { sp -> sp.surface == surfaceControl1}) val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, atLeastOnce().description("Wallpaper surface has not " + "received scheduleApply")).scheduleApply( captorWp.capture { sp -> sp.surface == surfaceControlWp }) val params = captor.value val params = captorSb.getLastValue() // We expect that we've set the surface behind to alpha = 0f since we're not interactive. // We expect that we've set the surface behind to alpha = 0f since we're not interactive. assertEquals(params.alpha, 0f) assertEquals(0f, params.alpha) assertTrue(params.matrix.isIdentity) assertTrue(params.matrix.isIdentity) assertEquals("Wallpaper surface was expected to have opacity 0", 0f, captorWp.getLastValue().alpha) verifyNoMoreInteractions(surfaceTransactionApplier) verifyNoMoreInteractions(surfaceTransactionApplier) } } Loading @@ -317,19 +350,50 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( remoteAnimationTargets, remoteAnimationTargets, wallpaperTargets, 0 /* startTime */, 0 /* startTime */, false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */ ) ) keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f) keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f) keyguardUnlockAnimationController.setWallpaperAppearAmount(1f) val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java) verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture()) val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, times(1)).scheduleApply( val params = captor.value captorSb.capture { sp -> sp.surface == surfaceControl1 }) assertEquals(params.alpha, 1f) val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>() verify(surfaceTransactionApplier, atLeastOnce().description("Wallpaper surface has not " + "received scheduleApply")).scheduleApply( captorWp.capture { sp -> sp.surface == surfaceControlWp }) val params = captorSb.getLastValue() assertEquals(1f, params.alpha) assertTrue(params.matrix.isIdentity) assertTrue(params.matrix.isIdentity) assertEquals("Wallpaper surface was expected to have opacity 1", 1f, captorWp.getLastValue().alpha) verifyNoMoreInteractions(surfaceTransactionApplier) verifyNoMoreInteractions(surfaceTransactionApplier) } } private class ArgThatCaptor<T> { private var allArgs: MutableList<T> = mutableListOf() fun capture(predicate: Predicate<T>): T { return argThat{x: T -> if (predicate.test(x)) { allArgs.add(x) return@argThat true } return@argThat false } } fun getLastValue(): T { return allArgs.last() } fun getAllValues(): List<T> { return allArgs } } } }