blob: eecbee56d203dead20140b05e5e6ae8276dfaf39 [file] [log] [blame]
package com.android.systemui.keyguard
import android.app.ActivityManager
import android.app.WindowConfiguration
import android.graphics.Point
import android.graphics.Rect
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.RemoteAnimationTarget
import android.view.SurfaceControl
import android.view.SyncRtSurfaceTransactionApplier
import android.view.ViewRootImpl
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardViewController
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
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 junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
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.mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
@SmallTest
class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
@Mock
private lateinit var keyguardViewMediator: KeyguardViewMediator
@Mock
private lateinit var keyguardStateController: KeyguardStateController
@Mock
private lateinit var keyguardViewController: KeyguardViewController
@Mock
private lateinit var featureFlags: FeatureFlags
@Mock
private lateinit var biometricUnlockController: BiometricUnlockController
@Mock
private lateinit var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier
@Mock
private lateinit var statusBarStateController: SysuiStatusBarStateController
@Mock
private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@Mock
private lateinit var launcherUnlockAnimationController: ILauncherUnlockAnimationController.Stub
private lateinit var remoteAnimationTarget: RemoteAnimationTarget
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
keyguardUnlockAnimationController = KeyguardUnlockAnimationController(
context, keyguardStateController, { keyguardViewMediator }, keyguardViewController,
featureFlags, { biometricUnlockController }, statusBarStateController,
notificationShadeWindowController
)
keyguardUnlockAnimationController.setLauncherUnlockController(
launcherUnlockAnimationController)
`when`(keyguardViewController.viewRootImpl).thenReturn(mock(ViewRootImpl::class.java))
// 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.
remoteAnimationTarget = RemoteAnimationTarget(
0, 0, null, false, Rect(), Rect(), 0, Point(), Rect(), Rect(),
mock(WindowConfiguration::class.java), false, mock(SurfaceControl::class.java), Rect(),
mock(ActivityManager.RunningTaskInfo::class.java), false)
// 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 is a reasonable way to test.
keyguardUnlockAnimationController.surfaceTransactionApplier = surfaceTransactionApplier
}
/**
* 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,
* revealing the app/launcher below. In this case, we want to make sure we are not animating the
* surface, or the user will see the wallpaper briefly as the app animates in.
*/
@Test
fun noSurfaceAnimation_ifWakeAndUnlocking() {
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTarget,
0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */
)
val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java)
verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture())
val params = captor.value
// 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)
assertTrue(params.matrix.isIdentity)
// Also expect we've immediately asked the keyguard view mediator to finish the remote
// animation.
verify(keyguardViewMediator, times(1)).onKeyguardExitRemoteAnimationFinished(
false /* cancelled */)
verifyNoMoreInteractions(surfaceTransactionApplier)
}
/**
* If we are not wake and unlocking, we expect the unlock animation to play normally.
*/
@Test
fun surfaceAnimation_ifNotWakeAndUnlocking() {
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(false)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTarget,
0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */
)
// Since the animation is running, we should not have finished the remote animation.
verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished(
false /* cancelled */)
}
/**
* If we requested that the surface behind be made visible, and we're not flinging away the
* keyguard, it means that we're swiping to unlock and want the surface visible so it can follow
* the user's touch event as they swipe to unlock.
*
* In this case, we should verify that the surface was made visible via the alpha fade in
* animator, and verify that we did not start the canned animation to animate the surface in
* (since it's supposed to be following the touch events).
*/
@Test
fun fadeInSurfaceBehind_ifRequestedShowSurface_butNotFlinging() {
`when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(false)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTarget,
0 /* startTime */,
true /* requestedShowSurfaceBehindKeyguard */
)
assertTrue(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning)
assertFalse(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
}
/**
* We requested the surface behind to be made visible, but we're now flinging to dismiss the
* keyguard. This means this was a swipe to dismiss gesture but the user flung the keyguard and
* lifted their finger while we were requesting the surface be made visible.
*
* In this case, we should verify that we are playing the canned unlock animation and not
* simply fading in the surface.
*/
@Test
fun playCannedUnlockAnimation_ifRequestedShowSurface_andFlinging() {
`when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(true)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTarget,
0 /* startTime */,
true /* requestedShowSurfaceBehindKeyguard */
)
assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning)
}
/**
* We never requested the surface behind to be made visible, which means no swiping to unlock
* ever happened and we're just playing the simple canned animation (happens via UDFPS unlock,
* long press on the lock icon, etc).
*
* In this case, we should verify that we are playing the canned unlock animation and not
* simply fading in the surface.
*/
@Test
fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() {
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTarget,
0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */
)
assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning)
}
@Test
fun doNotPlayCannedUnlockAnimation_ifLaunchingApp() {
`when`(notificationShadeWindowController.isLaunchingActivity).thenReturn(true)
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTarget,
0 /* startTime */,
true /* requestedShowSurfaceBehindKeyguard */
)
assertFalse(keyguardUnlockAnimationController.canPerformInWindowLauncherAnimations())
assertFalse(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
}
@Test
fun playCannedUnlockAnimation_nullSmartspaceView_doesNotThrowExecption() {
keyguardUnlockAnimationController.lockscreenSmartspace = null
keyguardUnlockAnimationController.willUnlockWithInWindowLauncherAnimations = true
keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
remoteAnimationTarget,
0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */
)
assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
}
}