Merge "Wallpaper animation for keyguard unlocking." into udc-dev

This commit is contained in:
Marzia Favaro
2023-05-10 15:09:12 +00:00
committed by Android (Google) Code Review
3 changed files with 172 additions and 17 deletions

View File

@@ -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
/** /**
@@ -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.
@@ -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
@@ -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.
*/ */
@@ -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
) { ) {
@@ -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
@@ -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.
@@ -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()

View File

@@ -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;
/** /**
@@ -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(
@@ -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 {

View File

@@ -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
@@ -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
@@ -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)
@@ -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
@@ -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
@@ -150,6 +162,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets, remoteAnimationTargets,
wallpaperTargets,
0 /* startTime */, 0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */
) )
@@ -174,6 +187,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets, remoteAnimationTargets,
wallpaperTargets,
0 /* startTime */, 0 /* startTime */,
true /* requestedShowSurfaceBehindKeyguard */ true /* requestedShowSurfaceBehindKeyguard */
) )
@@ -196,6 +210,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets, remoteAnimationTargets,
wallpaperTargets,
0 /* startTime */, 0 /* startTime */,
true /* requestedShowSurfaceBehindKeyguard */ true /* requestedShowSurfaceBehindKeyguard */
) )
@@ -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 */
) )
@@ -230,6 +246,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets, remoteAnimationTargets,
wallpaperTargets,
0 /* startTime */, 0 /* startTime */,
true /* requestedShowSurfaceBehindKeyguard */ true /* requestedShowSurfaceBehindKeyguard */
) )
@@ -245,6 +262,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation( keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets, remoteAnimationTargets,
wallpaperTargets,
0 /* startTime */, 0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */ false /* requestedShowSurfaceBehindKeyguard */
) )
@@ -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 */
) )
@@ -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 ->
@@ -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)
} }
@@ -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) 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()
assertEquals(params.alpha, 1f) 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
}
}
} }