Loading packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +50 −12 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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. Loading @@ -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, Loading @@ -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 Loading @@ -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() } } Loading @@ -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) Loading Loading @@ -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 Loading Loading @@ -318,4 +352,8 @@ class AuthRippleController @Inject constructor( help(pw) } } companion object { const val RIPPLE_ANIMATION_DURATION: Long = 1533 } } packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt +2 −14 Original line number Diff line number Diff line Loading @@ -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 /** Loading Loading @@ -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 } Loading @@ -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 Loading @@ -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 -> Loading @@ -298,7 +287,6 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at val animatorSet = AnimatorSet().apply { playTogether( rippleAnimator, revealAnimator, alphaInAnimator ) addListener(object : AnimatorListenerAdapter() { Loading packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +14 −3 Original line number Diff line number Diff line Loading @@ -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}. Loading Loading @@ -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()) { Loading Loading @@ -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; Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +3 −1 Original line number Diff line number Diff line Loading @@ -592,6 +592,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mKeyguardViewMediator.setWallpaperSupportsAmbientMode(supportsAmbientMode); } }; Loading Loading @@ -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); } } Loading packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +51 −7 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() { Loading @@ -73,6 +82,8 @@ class AuthRippleControllerTest : SysuiTestCase() { authController, configurationController, keyguardUpdateMonitor, keyguardStateController, wakefulnessLifecycle, commandRegistry, notificationShadeWindowController, bypassController, Loading @@ -82,6 +93,7 @@ class AuthRippleControllerTest : SysuiTestCase() { rippleView ) controller.init() `when`(statusBar.lightRevealScrim).thenReturn(lightRevealScrim) } @Test Loading @@ -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 Loading @@ -124,7 +136,7 @@ class AuthRippleControllerTest : SysuiTestCase() { false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startUnlockedRipple(any(), any()) verify(rippleView, never()).startUnlockedRipple(any()) } @Test Loading @@ -145,7 +157,7 @@ class AuthRippleControllerTest : SysuiTestCase() { false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startUnlockedRipple(any(), any()) verify(rippleView, never()).startUnlockedRipple(any()) } @Test Loading @@ -169,7 +181,7 @@ class AuthRippleControllerTest : SysuiTestCase() { // THEN show ripple verify(rippleView).setSensorLocation(faceLocation) verify(rippleView).startUnlockedRipple(any(), any()) verify(rippleView).startUnlockedRipple(any()) } @Test Loading @@ -189,7 +201,7 @@ class AuthRippleControllerTest : SysuiTestCase() { false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startUnlockedRipple(any(), any()) verify(rippleView, never()).startUnlockedRipple(any()) } @Test Loading @@ -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 Loading @@ -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 Loading Loading
packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +50 −12 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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. Loading @@ -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, Loading @@ -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 Loading @@ -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() } } Loading @@ -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) Loading Loading @@ -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 Loading Loading @@ -318,4 +352,8 @@ class AuthRippleController @Inject constructor( help(pw) } } companion object { const val RIPPLE_ANIMATION_DURATION: Long = 1533 } }
packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt +2 −14 Original line number Diff line number Diff line Loading @@ -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 /** Loading Loading @@ -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 } Loading @@ -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 Loading @@ -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 -> Loading @@ -298,7 +287,6 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at val animatorSet = AnimatorSet().apply { playTogether( rippleAnimator, revealAnimator, alphaInAnimator ) addListener(object : AnimatorListenerAdapter() { Loading
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +14 −3 Original line number Diff line number Diff line Loading @@ -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}. Loading Loading @@ -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()) { Loading Loading @@ -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; Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +3 −1 Original line number Diff line number Diff line Loading @@ -592,6 +592,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mKeyguardViewMediator.setWallpaperSupportsAmbientMode(supportsAmbientMode); } }; Loading Loading @@ -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); } } Loading
packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +51 −7 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() { Loading @@ -73,6 +82,8 @@ class AuthRippleControllerTest : SysuiTestCase() { authController, configurationController, keyguardUpdateMonitor, keyguardStateController, wakefulnessLifecycle, commandRegistry, notificationShadeWindowController, bypassController, Loading @@ -82,6 +93,7 @@ class AuthRippleControllerTest : SysuiTestCase() { rippleView ) controller.init() `when`(statusBar.lightRevealScrim).thenReturn(lightRevealScrim) } @Test Loading @@ -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 Loading @@ -124,7 +136,7 @@ class AuthRippleControllerTest : SysuiTestCase() { false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startUnlockedRipple(any(), any()) verify(rippleView, never()).startUnlockedRipple(any()) } @Test Loading @@ -145,7 +157,7 @@ class AuthRippleControllerTest : SysuiTestCase() { false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startUnlockedRipple(any(), any()) verify(rippleView, never()).startUnlockedRipple(any()) } @Test Loading @@ -169,7 +181,7 @@ class AuthRippleControllerTest : SysuiTestCase() { // THEN show ripple verify(rippleView).setSensorLocation(faceLocation) verify(rippleView).startUnlockedRipple(any(), any()) verify(rippleView).startUnlockedRipple(any()) } @Test Loading @@ -189,7 +201,7 @@ class AuthRippleControllerTest : SysuiTestCase() { false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startUnlockedRipple(any(), any()) verify(rippleView, never()).startUnlockedRipple(any()) } @Test Loading @@ -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 Loading @@ -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 Loading