summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSelim Cinek <cinek@google.com>2021-09-01 14:46:21 +0200
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-09-20 22:31:43 +0000
commit847a407da8bf722c8feb064c5d73b4fdd10ff8b7 (patch)
tree135276c25e22e6fd609768c3cd971280722fc093
parent2f84d73e95bc6898c7e88305c9eb0a8996314a11 (diff)
downloadbase-847a407da8bf722c8feb064c5d73b4fdd10ff8b7.tar.gz
Revealing the light reveal scrim only during keyguard exit animation
When unlocking from AOD, we now wait visually before starting the reveal animation Test: atest SystemUITests Bug: 197113783 Merged-In: I5180ec48e6e100832741273277ac9d2ff4c289b0 Change-Id: I5180ec48e6e100832741273277ac9d2ff4c289b0 (cherry picked from commit 9eda54b15e8e1a63759c40e14f8060a39eb6fd97)
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt58
5 files changed, 120 insertions, 37 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index e232316b8a94..2630f119de00 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics
+import android.animation.ValueAnimator
import android.content.Context
import android.content.res.Configuration
import android.graphics.PointF
@@ -26,6 +27,8 @@ import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.settingslib.Utils
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.statusbar.CircleReveal
import com.android.systemui.statusbar.LightRevealEffect
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -36,12 +39,15 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.StatusBar
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.ViewController
import java.io.PrintWriter
import javax.inject.Inject
import javax.inject.Provider
import com.android.systemui.plugins.statusbar.StatusBarStateController
+private const val WAKE_AND_UNLOCK_FADE_DURATION = 180L
+
/***
* Controls the ripple effect that shows when authentication is successful.
* The ripple uses the accent color of the current theme.
@@ -53,6 +59,8 @@ class AuthRippleController @Inject constructor(
private val authController: AuthController,
private val configurationController: ConfigurationController,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val keyguardStateController: KeyguardStateController,
+ private val wakefulnessLifecycle: WakefulnessLifecycle,
private val commandRegistry: CommandRegistry,
private val notificationShadeWindowController: NotificationShadeWindowController,
private val bypassController: KeyguardBypassController,
@@ -60,7 +68,11 @@ class AuthRippleController @Inject constructor(
private val udfpsControllerProvider: Provider<UdfpsController>,
private val statusBarStateController: StatusBarStateController,
rippleView: AuthRippleView?
-) : ViewController<AuthRippleView>(rippleView) {
+) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback,
+ WakefulnessLifecycle.Observer {
+
+ @VisibleForTesting
+ internal var startLightRevealScrimOnKeyguardFadingAway = false
var fingerprintSensorLocation: PointF? = null
private var faceSensorLocation: PointF? = null
private var circleReveal: LightRevealEffect? = null
@@ -87,6 +99,8 @@ class AuthRippleController @Inject constructor(
udfpsController?.addCallback(udfpsControllerCallback)
configurationController.addCallback(configurationChangedListener)
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ keyguardStateController.addCallback(this)
+ wakefulnessLifecycle.addObserver(this)
commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() }
}
@@ -96,6 +110,8 @@ class AuthRippleController @Inject constructor(
authController.removeCallback(authControllerCallback)
keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
configurationController.removeCallback(configurationChangedListener)
+ keyguardStateController.removeCallback(this)
+ wakefulnessLifecycle.removeObserver(this)
commandRegistry.unregisterCommand("auth-ripple")
notificationShadeWindowController.setForcePluginOpen(false, this)
@@ -123,30 +139,48 @@ class AuthRippleController @Inject constructor(
private fun showUnlockedRipple() {
notificationShadeWindowController.setForcePluginOpen(true, this)
- val biometricUnlockMode = biometricUnlockController.mode
- val useCircleReveal = circleReveal != null &&
- (biometricUnlockMode == BiometricUnlockController.MODE_WAKE_AND_UNLOCK ||
- biometricUnlockMode == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING ||
- biometricUnlockMode == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM)
+ val useCircleReveal = circleReveal != null && biometricUnlockController.isWakeAndUnlock
val lightRevealScrim = statusBar.lightRevealScrim
if (useCircleReveal) {
lightRevealScrim?.revealEffect = circleReveal!!
+ startLightRevealScrimOnKeyguardFadingAway = true
}
mView.startUnlockedRipple(
/* end runnable */
Runnable {
notificationShadeWindowController.setForcePluginOpen(false, this)
- },
- /* circleReveal */
- if (useCircleReveal) {
- lightRevealScrim
- } else {
- null
}
)
}
+ override fun onKeyguardFadingAwayChanged() {
+ if (keyguardStateController.isKeyguardFadingAway) {
+ val lightRevealScrim = statusBar.lightRevealScrim
+ if (startLightRevealScrimOnKeyguardFadingAway && lightRevealScrim != null) {
+ val revealAnimator = ValueAnimator.ofFloat(.1f, 1f).apply {
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ duration = RIPPLE_ANIMATION_DURATION
+ startDelay = keyguardStateController.keyguardFadingAwayDelay
+ addUpdateListener { animator ->
+ if (lightRevealScrim.revealEffect != circleReveal) {
+ // if the something else took over the reveal, let's do nothing.
+ return@addUpdateListener
+ }
+ lightRevealScrim.revealAmount = animator.animatedValue as Float
+ }
+ }
+ revealAnimator.start()
+ startLightRevealScrimOnKeyguardFadingAway = false
+ }
+ }
+ }
+
+ override fun onStartedGoingToSleep() {
+ // reset the light reveal start in case we were pending an unlock
+ startLightRevealScrimOnKeyguardFadingAway = false
+ }
+
fun updateSensorLocation() {
fingerprintSensorLocation = authController.fingerprintSensorLocation
faceSensorLocation = authController.faceAuthSensorLocation
@@ -318,4 +352,8 @@ class AuthRippleController @Inject constructor(
help(pw)
}
}
+
+ companion object {
+ const val RIPPLE_ANIMATION_DURATION: Long = 1533
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 1113579e417c..c6d26ffb9957 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -26,13 +26,10 @@ import android.graphics.PointF
import android.util.AttributeSet
import android.view.View
import android.view.animation.PathInterpolator
-import com.android.internal.R.attr.interpolator
import com.android.internal.graphics.ColorUtils
import com.android.systemui.animation.Interpolators
-import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.charging.RippleShader
-private const val RIPPLE_ANIMATION_DURATION: Long = 1533
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
/**
@@ -250,7 +247,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
/**
* Ripple that bursts outwards from the position of the sensor to the edges of the screen
*/
- fun startUnlockedRipple(onAnimationEnd: Runnable?, lightReveal: LightRevealScrim?) {
+ fun startUnlockedRipple(onAnimationEnd: Runnable?) {
if (unlockedRippleInProgress) {
return // Ignore if ripple effect is already playing
}
@@ -266,7 +263,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
val rippleAnimator = ValueAnimator.ofFloat(rippleStart, 1f).apply {
interpolator = Interpolators.LINEAR_OUT_SLOW_IN
- duration = RIPPLE_ANIMATION_DURATION
+ duration = AuthRippleController.RIPPLE_ANIMATION_DURATION
addUpdateListener { animator ->
val now = animator.currentPlayTime
rippleShader.progress = animator.animatedValue as Float
@@ -276,14 +273,6 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
}
}
- val revealAnimator = ValueAnimator.ofFloat(.1f, 1f).apply {
- interpolator = rippleAnimator.interpolator
- duration = rippleAnimator.duration
- addUpdateListener { animator ->
- lightReveal?.revealAmount = animator.animatedValue as Float
- }
- }
-
val alphaInAnimator = ValueAnimator.ofInt(0, 255).apply {
duration = alphaDuration
addUpdateListener { animator ->
@@ -298,7 +287,6 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
val animatorSet = AnimatorSet().apply {
playTogether(
rippleAnimator,
- revealAnimator,
alphaInAnimator
)
addListener(object : AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index ee3d40edc2eb..1a8af3bb650b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -818,6 +818,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
private final KeyguardStateController mKeyguardStateController;
private final Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
+ private boolean mWallpaperSupportsAmbientMode;
/**
* Injected constructor. See {@link KeyguardModule}.
@@ -2089,13 +2090,14 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
int flags = 0;
if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock()
- || (mWakeAndUnlocking && !mPulsing)
- || isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
+ || mWakeAndUnlocking && !mWallpaperSupportsAmbientMode) {
flags |= WindowManagerPolicyConstants
.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
}
if (mKeyguardViewControllerLazy.get().isGoingToNotificationShade()
- || (mWakeAndUnlocking && mPulsing)) {
+ || mWakeAndUnlocking && mWallpaperSupportsAmbientMode) {
+ // When the wallpaper supports ambient mode, the scrim isn't fully opaque during
+ // wake and unlock and we should fade in the app on top of the wallpaper
flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
}
if (mKeyguardViewControllerLazy.get().isUnlockWithWallpaper()) {
@@ -2784,6 +2786,15 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
mPulsing = pulsing;
}
+ /**
+ * Set if the wallpaper supports ambient mode. This is used to trigger the right animation.
+ * In case it does support it, we have to fade in the incoming app, otherwise we'll reveal it
+ * with the light reveal scrim.
+ */
+ public void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) {
+ mWallpaperSupportsAmbientMode = supportsAmbientMode;
+ }
+
private static class StartKeyguardExitAnimParams {
@WindowManager.TransitionOldType int mTransit;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 4705a362b669..90fc779c32cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -592,6 +592,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
+ mKeyguardViewMediator.setWallpaperSupportsAmbientMode(supportsAmbientMode);
}
};
@@ -3913,7 +3914,8 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onDozeAmountChanged(float linear, float eased) {
if (mFeatureFlags.useNewLockscreenAnimations()
- && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
+ && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)
+ && !mBiometricUnlockController.isWakeAndUnlock()) {
mLightRevealScrim.setRevealAmount(1f - linear);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 5c73077c0e69..f2f0029708ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -19,17 +19,23 @@ package com.android.systemui.biometrics
import android.graphics.PointF
import android.hardware.biometrics.BiometricSourceType
import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.StatusBar
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -55,12 +61,15 @@ class AuthRippleControllerTest : SysuiTestCase() {
@Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var authController: AuthController
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@Mock private lateinit var bypassController: KeyguardBypassController
@Mock private lateinit var biometricUnlockController: BiometricUnlockController
@Mock private lateinit var udfpsControllerProvider: Provider<UdfpsController>
@Mock private lateinit var udfpsController: UdfpsController
@Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var lightRevealScrim: LightRevealScrim
@Before
fun setUp() {
@@ -73,6 +82,8 @@ class AuthRippleControllerTest : SysuiTestCase() {
authController,
configurationController,
keyguardUpdateMonitor,
+ keyguardStateController,
+ wakefulnessLifecycle,
commandRegistry,
notificationShadeWindowController,
bypassController,
@@ -82,6 +93,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
rippleView
)
controller.init()
+ `when`(statusBar.lightRevealScrim).thenReturn(lightRevealScrim)
}
@Test
@@ -103,7 +115,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
// THEN update sensor location and show ripple
verify(rippleView).setSensorLocation(fpsLocation)
- verify(rippleView).startUnlockedRipple(any(), any())
+ verify(rippleView).startUnlockedRipple(any())
}
@Test
@@ -124,7 +136,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
false /* isStrongBiometric */)
// THEN no ripple
- verify(rippleView, never()).startUnlockedRipple(any(), any())
+ verify(rippleView, never()).startUnlockedRipple(any())
}
@Test
@@ -145,7 +157,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
false /* isStrongBiometric */)
// THEN no ripple
- verify(rippleView, never()).startUnlockedRipple(any(), any())
+ verify(rippleView, never()).startUnlockedRipple(any())
}
@Test
@@ -169,7 +181,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
// THEN show ripple
verify(rippleView).setSensorLocation(faceLocation)
- verify(rippleView).startUnlockedRipple(any(), any())
+ verify(rippleView).startUnlockedRipple(any())
}
@Test
@@ -189,7 +201,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
false /* isStrongBiometric */)
// THEN no ripple
- verify(rippleView, never()).startUnlockedRipple(any(), any())
+ verify(rippleView, never()).startUnlockedRipple(any())
}
@Test
@@ -204,7 +216,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
0 /* userId */,
BiometricSourceType.FACE /* type */,
false /* isStrongBiometric */)
- verify(rippleView, never()).startUnlockedRipple(any(), any())
+ verify(rippleView, never()).startUnlockedRipple(any())
}
@Test
@@ -219,7 +231,39 @@ class AuthRippleControllerTest : SysuiTestCase() {
0 /* userId */,
BiometricSourceType.FINGERPRINT /* type */,
false /* isStrongBiometric */)
- verify(rippleView, never()).startUnlockedRipple(any(), any())
+ verify(rippleView, never()).startUnlockedRipple(any())
+ }
+
+ @Test
+ fun registersAndDeregisters() {
+ controller.onViewAttached()
+ val captor = ArgumentCaptor
+ .forClass(KeyguardStateController.Callback::class.java)
+ verify(keyguardStateController).addCallback(captor.capture())
+ val captor2 = ArgumentCaptor
+ .forClass(WakefulnessLifecycle.Observer::class.java)
+ verify(wakefulnessLifecycle).addObserver(captor2.capture())
+ controller.onViewDetached()
+ verify(keyguardStateController).removeCallback(any())
+ verify(wakefulnessLifecycle).removeObserver(any())
+ }
+
+ @Test
+ @RunWithLooper(setAsMainLooper = true)
+ fun testAnimatorRunWhenWakeAndUnlock() {
+ val fpsLocation = PointF(5f, 5f)
+ `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
+ controller.onViewAttached()
+ `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+ `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
+
+ controller.showRipple(BiometricSourceType.FINGERPRINT)
+ assertTrue("reveal didn't start on keyguardFadingAway",
+ controller.startLightRevealScrimOnKeyguardFadingAway)
+ `when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true)
+ controller.onKeyguardFadingAwayChanged()
+ assertFalse("reveal triggers multiple times",
+ controller.startLightRevealScrimOnKeyguardFadingAway)
}
@Test