Override alpha to 0f if we're no longer interactive.

This is a safe way to ensure the surface is immediately
no longer visible, until the screen off lifecycle event
arrives and ends up canceling the unlock sequence and
sleeping the device. WM resets the surface alpha after
the animation ends, so this should be safe.

Since the surface alpha is usually close to 0f when this
condition is met, it's not usually perceptible that we
jump-cut to 0f.

Test: press the power button while also triggering an unlock
Test: atest KeyguardUnlockAnimationControllerTest
Bug: 260094933
Change-Id: I15a9decf1dcfac0b60b3f4e97a2e470098961743
This commit is contained in:
Josh Tsuji
2022-12-22 16:11:54 -05:00
parent f1f50ee221
commit 767467732e
2 changed files with 77 additions and 13 deletions

View File

@@ -23,6 +23,7 @@ import android.content.Context
import android.graphics.Matrix
import android.graphics.Rect
import android.os.Handler
import android.os.PowerManager
import android.os.RemoteException
import android.util.Log
import android.view.RemoteAnimationTarget
@@ -145,7 +146,8 @@ class KeyguardUnlockAnimationController @Inject constructor(
private val featureFlags: FeatureFlags,
private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>,
private val statusBarStateController: SysuiStatusBarStateController,
private val notificationShadeWindowController: NotificationShadeWindowController
private val notificationShadeWindowController: NotificationShadeWindowController,
private val powerManager: PowerManager
) : KeyguardStateController.Callback, ISysuiUnlockAnimationController.Stub() {
interface KeyguardUnlockAnimationListener {
@@ -783,10 +785,15 @@ class KeyguardUnlockAnimationController @Inject constructor(
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
val animationAlpha = when {
// If we're snapping the keyguard back, immediately begin fading it out.
keyguardStateController.isSnappingKeyguardBackAfterSwipe -> amount
// 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 -> surfaceBehindAlpha
}
// SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is
// unable to draw

View File

@@ -4,6 +4,7 @@ import android.app.ActivityManager
import android.app.WindowConfiguration
import android.graphics.Point
import android.graphics.Rect
import android.os.PowerManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.RemoteAnimationTarget
@@ -19,15 +20,16 @@ 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.whenever
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
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.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@@ -56,6 +58,8 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
private lateinit var statusBarStateController: SysuiStatusBarStateController
@Mock
private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@Mock
private lateinit var powerManager: PowerManager
@Mock
private lateinit var launcherUnlockAnimationController: ILauncherUnlockAnimationController.Stub
@@ -79,12 +83,13 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
keyguardUnlockAnimationController = KeyguardUnlockAnimationController(
context, keyguardStateController, { keyguardViewMediator }, keyguardViewController,
featureFlags, { biometricUnlockController }, statusBarStateController,
notificationShadeWindowController
notificationShadeWindowController, powerManager
)
keyguardUnlockAnimationController.setLauncherUnlockController(
launcherUnlockAnimationController)
`when`(keyguardViewController.viewRootImpl).thenReturn(mock(ViewRootImpl::class.java))
whenever(keyguardViewController.viewRootImpl).thenReturn(mock(ViewRootImpl::class.java))
whenever(powerManager.isInteractive).thenReturn(true)
// 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.
@@ -96,6 +101,12 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
keyguardUnlockAnimationController.surfaceTransactionApplier = surfaceTransactionApplier
}
@After
fun tearDown() {
keyguardUnlockAnimationController.surfaceBehindEntryAnimator.cancel()
keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.cancel()
}
/**
* If we're wake and unlocking, we are animating from the black/AOD screen to the app/launcher
* underneath. The LightRevealScrim will animate circularly from the fingerprint reader,
@@ -104,7 +115,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
*/
@Test
fun noSurfaceAnimation_ifWakeAndUnlocking() {
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
whenever(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets,
@@ -135,7 +146,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
*/
@Test
fun surfaceAnimation_ifNotWakeAndUnlocking() {
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(false)
whenever(biometricUnlockController.isWakeAndUnlock).thenReturn(false)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets,
@@ -159,7 +170,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
*/
@Test
fun fadeInSurfaceBehind_ifRequestedShowSurface_butNotFlinging() {
`when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(false)
whenever(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(false)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets,
@@ -181,7 +192,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
*/
@Test
fun playCannedUnlockAnimation_ifRequestedShowSurface_andFlinging() {
`when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(true)
whenever(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(true)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets,
@@ -215,7 +226,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
@Test
fun doNotPlayCannedUnlockAnimation_ifLaunchingApp() {
`when`(notificationShadeWindowController.isLaunchingActivity).thenReturn(true)
whenever(notificationShadeWindowController.isLaunchingActivity).thenReturn(true)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets,
@@ -275,4 +286,50 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished(
false /* cancelled */)
}
@Test
fun surfaceBehindAlphaOverriddenTo0_ifNotInteractive() {
whenever(powerManager.isInteractive).thenReturn(false)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets,
0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */
)
keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f)
val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java)
verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture())
val params = captor.value
// We expect that we've set the surface behind to alpha = 0f since we're not interactive.
assertEquals(params.alpha, 0f)
assertTrue(params.matrix.isIdentity)
verifyNoMoreInteractions(surfaceTransactionApplier)
}
@Test
fun surfaceBehindAlphaNotOverriddenTo0_ifInteractive() {
whenever(powerManager.isInteractive).thenReturn(true)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTargets,
0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */
)
keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f)
val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java)
verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture())
val params = captor.value
assertEquals(params.alpha, 1f)
assertTrue(params.matrix.isIdentity)
verifyNoMoreInteractions(surfaceTransactionApplier)
}
}