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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user