Merge "Wallpaper animation for keyguard unlocking." into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
6f0ed61268
@@ -245,6 +245,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
@VisibleForTesting
|
||||
var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null
|
||||
private var surfaceBehindRemoteAnimationTargets: Array<RemoteAnimationTarget>? = null
|
||||
private var wallpaperTargets: Array<RemoteAnimationTarget>? = null
|
||||
private var surfaceBehindRemoteAnimationStartTime: Long = 0
|
||||
|
||||
/**
|
||||
@@ -257,9 +258,13 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
*/
|
||||
private var surfaceBehindAlpha = 1f
|
||||
|
||||
private var wallpaperAlpha = 1f
|
||||
|
||||
@VisibleForTesting
|
||||
var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
|
||||
|
||||
var wallpaperAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
|
||||
|
||||
/**
|
||||
* Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
|
||||
* 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) {
|
||||
duration = UNLOCK_ANIMATION_DURATION_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()
|
||||
}
|
||||
|
||||
fun isAnyKeyguyardAnimatorPlaying(): Boolean {
|
||||
return surfaceBehindAlphaAnimator.isStarted ||
|
||||
wallpaperAlphaAnimator.isStarted || surfaceBehindEntryAnimator.isStarted
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener to be notified of various stages of the unlock animation.
|
||||
*/
|
||||
@@ -492,6 +523,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
*/
|
||||
fun notifyStartSurfaceBehindRemoteAnimation(
|
||||
targets: Array<RemoteAnimationTarget>,
|
||||
wallpapers: Array<RemoteAnimationTarget>,
|
||||
startTime: Long,
|
||||
requestedShowSurfaceBehindKeyguard: Boolean
|
||||
) {
|
||||
@@ -501,8 +533,11 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
}
|
||||
|
||||
surfaceBehindRemoteAnimationTargets = targets
|
||||
wallpaperTargets = wallpapers
|
||||
surfaceBehindRemoteAnimationStartTime = startTime
|
||||
|
||||
fadeInWallpaper()
|
||||
|
||||
// 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 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
|
||||
* we should clean up all of our state.
|
||||
@@ -903,6 +970,12 @@ class KeyguardUnlockAnimationController @Inject constructor(
|
||||
surfaceBehindAlphaAnimator.start()
|
||||
}
|
||||
|
||||
private fun fadeInWallpaper() {
|
||||
Log.d(TAG, "fadeInWallpaper")
|
||||
wallpaperAlphaAnimator.cancel()
|
||||
wallpaperAlphaAnimator.start()
|
||||
}
|
||||
|
||||
private fun fadeOutSurfaceBehind() {
|
||||
Log.d(TAG, "fadeOutSurfaceBehind")
|
||||
surfaceBehindAlphaAnimator.cancel()
|
||||
|
||||
@@ -159,6 +159,7 @@ import dagger.Lazy;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
@@ -2710,9 +2711,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
CUJ_LOCKSCREEN_UNLOCK_ANIMATION, "DismissPanel"));
|
||||
|
||||
// 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()
|
||||
.notifyStartSurfaceBehindRemoteAnimation(
|
||||
apps, startTime, mSurfaceBehindRemoteAnimationRequested);
|
||||
apps, openingWallpapers, startTime,
|
||||
mSurfaceBehindRemoteAnimationRequested);
|
||||
} else {
|
||||
mInteractionJankMonitor.begin(
|
||||
createInteractionJankMonitorConf(
|
||||
@@ -2961,6 +2966,19 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
mSurfaceBehindRemoteAnimationRequested = false;
|
||||
mSurfaceBehindRemoteAnimationRunning = 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) {
|
||||
try {
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController
|
||||
import com.android.systemui.statusbar.SysuiStatusBarStateController
|
||||
import com.android.systemui.statusbar.phone.BiometricUnlockController
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import com.android.systemui.util.mockito.argThat
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import junit.framework.Assert.assertEquals
|
||||
import junit.framework.Assert.assertFalse
|
||||
@@ -28,13 +29,14 @@ import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor.forClass
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.atLeastOnce
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.util.function.Predicate
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper
|
||||
@@ -77,6 +79,13 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
mock(ActivityManager.RunningTaskInfo::class.java), false)
|
||||
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
|
||||
fun setUp() {
|
||||
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
|
||||
// appear amount setter doesn't short circuit.
|
||||
remoteAnimationTargets = arrayOf(remoteTarget1)
|
||||
wallpaperTargets = arrayOf(wallpaperTarget)
|
||||
|
||||
// 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
|
||||
@@ -119,18 +129,20 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
|
||||
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
|
||||
remoteAnimationTargets,
|
||||
arrayOf(),
|
||||
0 /* startTime */,
|
||||
false /* requestedShowSurfaceBehindKeyguard */
|
||||
)
|
||||
|
||||
val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java)
|
||||
verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture())
|
||||
val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
|
||||
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
|
||||
// transforms (translate, scale) on its matrix.
|
||||
assertEquals(params.alpha, 1f)
|
||||
assertEquals(1f, params.alpha)
|
||||
assertTrue(params.matrix.isIdentity)
|
||||
|
||||
// Also expect we've immediately asked the keyguard view mediator to finish the remote
|
||||
@@ -150,6 +162,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
|
||||
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
|
||||
remoteAnimationTargets,
|
||||
wallpaperTargets,
|
||||
0 /* startTime */,
|
||||
false /* requestedShowSurfaceBehindKeyguard */
|
||||
)
|
||||
@@ -174,6 +187,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
|
||||
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
|
||||
remoteAnimationTargets,
|
||||
wallpaperTargets,
|
||||
0 /* startTime */,
|
||||
true /* requestedShowSurfaceBehindKeyguard */
|
||||
)
|
||||
@@ -196,6 +210,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
|
||||
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
|
||||
remoteAnimationTargets,
|
||||
wallpaperTargets,
|
||||
0 /* startTime */,
|
||||
true /* requestedShowSurfaceBehindKeyguard */
|
||||
)
|
||||
@@ -216,6 +231,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() {
|
||||
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
|
||||
remoteAnimationTargets,
|
||||
wallpaperTargets,
|
||||
0 /* startTime */,
|
||||
false /* requestedShowSurfaceBehindKeyguard */
|
||||
)
|
||||
@@ -230,6 +246,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
|
||||
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
|
||||
remoteAnimationTargets,
|
||||
wallpaperTargets,
|
||||
0 /* startTime */,
|
||||
true /* requestedShowSurfaceBehindKeyguard */
|
||||
)
|
||||
@@ -245,6 +262,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
|
||||
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
|
||||
remoteAnimationTargets,
|
||||
wallpaperTargets,
|
||||
0 /* startTime */,
|
||||
false /* requestedShowSurfaceBehindKeyguard */
|
||||
)
|
||||
@@ -259,6 +277,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
fun surfaceAnimation_multipleTargets() {
|
||||
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
|
||||
arrayOf(remoteTarget1, remoteTarget2),
|
||||
wallpaperTargets,
|
||||
0 /* startTime */,
|
||||
false /* requestedShowSurfaceBehindKeyguard */
|
||||
)
|
||||
@@ -267,10 +286,15 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
// 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 captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
|
||||
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)
|
||||
allParams.forEach { params ->
|
||||
@@ -293,20 +317,29 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
|
||||
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
|
||||
remoteAnimationTargets,
|
||||
wallpaperTargets,
|
||||
0 /* startTime */,
|
||||
false /* requestedShowSurfaceBehindKeyguard */
|
||||
)
|
||||
|
||||
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(
|
||||
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.
|
||||
assertEquals(params.alpha, 0f)
|
||||
assertEquals(0f, params.alpha)
|
||||
assertTrue(params.matrix.isIdentity)
|
||||
assertEquals("Wallpaper surface was expected to have opacity 0",
|
||||
0f, captorWp.getLastValue().alpha)
|
||||
|
||||
verifyNoMoreInteractions(surfaceTransactionApplier)
|
||||
}
|
||||
@@ -317,19 +350,50 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
|
||||
|
||||
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
|
||||
remoteAnimationTargets,
|
||||
wallpaperTargets,
|
||||
0 /* startTime */,
|
||||
false /* requestedShowSurfaceBehindKeyguard */
|
||||
)
|
||||
|
||||
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(
|
||||
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
|
||||
assertEquals(params.alpha, 1f)
|
||||
val params = captorSb.getLastValue()
|
||||
assertEquals(1f, params.alpha)
|
||||
assertTrue(params.matrix.isIdentity)
|
||||
assertEquals("Wallpaper surface was expected to have opacity 1",
|
||||
1f, captorWp.getLastValue().alpha)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user