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:
@@ -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,7 +225,18 @@ 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)
|
||||||
surfaceBehindEntryAnimator.start()
|
|
||||||
|
// 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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 */)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user