Merge "Fix issue where surface was animated while wake and unlocking." into sc-v2-dev am: b024f66885

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16466631

Change-Id: I324e663b42e6412c2a450105eff2638850602d5a
This commit is contained in:
TreeHugger Robot
2021-12-16 19:39:38 +00:00
committed by Automerger Merge Worker
2 changed files with 155 additions and 5 deletions

View File

@@ -24,6 +24,7 @@ import android.graphics.Matrix
import android.view.RemoteAnimationTarget import android.view.RemoteAnimationTarget
import android.view.SyncRtSurfaceTransactionApplier import android.view.SyncRtSurfaceTransactionApplier
import android.view.View import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.core.math.MathUtils import androidx.core.math.MathUtils
import com.android.internal.R import com.android.internal.R
import com.android.keyguard.KeyguardClockSwitchController import com.android.keyguard.KeyguardClockSwitchController
@@ -32,6 +33,7 @@ import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy import dagger.Lazy
import javax.inject.Inject import javax.inject.Inject
@@ -91,7 +93,8 @@ class KeyguardUnlockAnimationController @Inject constructor(
private val keyguardViewMediator: Lazy<KeyguardViewMediator>, private val keyguardViewMediator: Lazy<KeyguardViewMediator>,
private val keyguardViewController: KeyguardViewController, private val keyguardViewController: KeyguardViewController,
private val smartspaceTransitionController: SmartspaceTransitionController, private val smartspaceTransitionController: SmartspaceTransitionController,
private val featureFlags: FeatureFlags private val featureFlags: FeatureFlags,
private val biometricUnlockController: BiometricUnlockController
) : KeyguardStateController.Callback { ) : KeyguardStateController.Callback {
/** /**
@@ -105,7 +108,8 @@ class KeyguardUnlockAnimationController @Inject constructor(
* If we're unlocking via biometrics, PIN entry, or from clicking a notification, a canned * If we're unlocking via biometrics, PIN entry, or from clicking a notification, a canned
* animation is started in [notifyStartKeyguardExitAnimation]. * animation is started in [notifyStartKeyguardExitAnimation].
*/ */
private var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null @VisibleForTesting
var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null
private var surfaceBehindRemoteAnimationTarget: RemoteAnimationTarget? = null private var surfaceBehindRemoteAnimationTarget: RemoteAnimationTarget? = null
private var surfaceBehindRemoteAnimationStartTime: Long = 0 private var surfaceBehindRemoteAnimationStartTime: Long = 0
@@ -132,7 +136,8 @@ class KeyguardUnlockAnimationController @Inject constructor(
* Animator that animates in the surface behind the keyguard. This is used to play a canned * Animator that animates in the surface behind the keyguard. This is used to play a canned
* animation on the surface, if we're not doing a swipe gesture. * animation on the surface, if we're not doing a swipe gesture.
*/ */
private val surfaceBehindEntryAnimator = ValueAnimator.ofFloat(0f, 1f) @VisibleForTesting
val surfaceBehindEntryAnimator = ValueAnimator.ofFloat(0f, 1f)
/** Rounded corner radius to apply to the surface behind the keyguard. */ /** Rounded corner radius to apply to the surface behind the keyguard. */
private var roundedCornerRadius = 0f private var roundedCornerRadius = 0f
@@ -220,8 +225,19 @@ class KeyguardUnlockAnimationController @Inject constructor(
// to animate it in. Otherwise, the swipe touch events will continue animating it. // to animate it in. Otherwise, the swipe touch events will continue animating it.
if (!requestedShowSurfaceBehindKeyguard) { if (!requestedShowSurfaceBehindKeyguard) {
keyguardViewController.hide(startTime, 350) keyguardViewController.hide(startTime, 350)
// If we're wake and unlocking, we don't want to animate the surface since we're going
// to do the light reveal scrim from the black AOD screen. Make it visible and end the
// remote aimation.
if (biometricUnlockController.isWakeAndUnlock) {
setSurfaceBehindAppearAmount(1f)
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
false /* cancelled */)
} else {
// Otherwise, animate it in normally.
surfaceBehindEntryAnimator.start() surfaceBehindEntryAnimator.start()
} }
}
// Finish the keyguard remote animation if the dismiss amount has crossed the threshold. // Finish the keyguard remote animation if the dismiss amount has crossed the threshold.
// Check it here in case there is no more change to the dismiss amount after the last change // Check it here in case there is no more change to the dismiss amount after the last change
@@ -264,7 +280,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
* animations and swipe gestures to animate the surface's entry (and exit, if the swipe is * animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
* cancelled). * cancelled).
*/ */
private fun setSurfaceBehindAppearAmount(amount: Float) { fun setSurfaceBehindAppearAmount(amount: Float) {
if (surfaceBehindRemoteAnimationTarget == null) { if (surfaceBehindRemoteAnimationTarget == null) {
return return
} }

View File

@@ -0,0 +1,134 @@
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.SmartspaceTransitionController
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController
import junit.framework.Assert.assertEquals
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.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
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 smartspaceTransitionController: SmartspaceTransitionController
@Mock
private lateinit var featureFlags: FeatureFlags
@Mock
private lateinit var biometricUnlockController: BiometricUnlockController
@Mock
private lateinit var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier
private lateinit var remoteAnimationTarget: RemoteAnimationTarget
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
keyguardUnlockAnimationController = KeyguardUnlockAnimationController(
context, keyguardStateController, { keyguardViewMediator }, keyguardViewController,
smartspaceTransitionController, featureFlags, biometricUnlockController
)
`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.notifyStartKeyguardExitAnimation(
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.notifyStartKeyguardExitAnimation(
remoteAnimationTarget,
0 /* startTime */,
false /* requestedShowSurfaceBehindKeyguard */
)
// Make sure the animator was started.
assertTrue(keyguardUnlockAnimationController.surfaceBehindEntryAnimator.isRunning)
// Since the animation is running, we should not have finished the remote animation.
verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished(
false /* cancelled */)
}
}