Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a545b2b7 authored by Beverly Tai's avatar Beverly Tai Committed by Android (Google) Code Review
Browse files

Merge "On UDFPS auth success, fade out the dwell ripple" into tm-dev

parents 95afc78e 08cf9432
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -652,7 +652,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
        // pre-emptively set to true to hide view
        mIsBouncerShowing = true;
        if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
            mAuthRippleController.showRipple(FINGERPRINT);
            mAuthRippleController.showUnlockRipple(FINGERPRINT);
        }
        updateVisibility();
        if (mOnGestureDetectedRunnable != null) {
+26 −9
Original line number Diff line number Diff line
@@ -52,7 +52,11 @@ import javax.inject.Inject
import javax.inject.Provider

/***
 * Controls the ripple effect that shows when authentication is successful.
 * Controls two ripple effects:
 *   1. Unlocked ripple: shows when authentication is successful
 *   2. UDFPS dwell ripple: shows when the user has their finger down on the UDFPS area and reacts
 *   to errors and successes
 *
 * The ripple uses the accent color of the current theme.
 */
@CentralSurfacesScope
@@ -115,7 +119,7 @@ class AuthRippleController @Inject constructor(
        notificationShadeWindowController.setForcePluginOpen(false, this)
    }

    fun showRipple(biometricSourceType: BiometricSourceType?) {
    fun showUnlockRipple(biometricSourceType: BiometricSourceType?) {
        if (!(keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.isDreaming) ||
            keyguardUpdateMonitor.userNeedsStrongAuth()) {
            return
@@ -252,11 +256,16 @@ class AuthRippleController @Inject constructor(
                biometricSourceType: BiometricSourceType?,
                isStrongBiometric: Boolean
            ) {
                showRipple(biometricSourceType)
                if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
                    mView.fadeDwellRipple()
                }
                showUnlockRipple(biometricSourceType)
            }

        override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) {
            mView.retractRipple()
            if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
                mView.retractDwellRipple()
            }
        }

        override fun onBiometricAcquired(
@@ -264,8 +273,16 @@ class AuthRippleController @Inject constructor(
            acquireInfo: Int
        ) {
            if (biometricSourceType == BiometricSourceType.FINGERPRINT &&
                    acquireInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_PARTIAL) {
                mView.retractRipple()
                    BiometricFingerprintConstants.shouldTurnOffHbm(acquireInfo) &&
                    acquireInfo != BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD) {
                // received an 'acquiredBad' message, so immediately retract
                mView.retractDwellRipple()
            }
        }

        override fun onKeyguardBouncerChanged(bouncerIsOrWillBeShowing: Boolean) {
            if (bouncerIsOrWillBeShowing) {
                mView.fadeDwellRipple()
            }
        }
    }
@@ -294,7 +311,7 @@ class AuthRippleController @Inject constructor(
            }

            override fun onFingerUp() {
                mView.retractRipple()
                mView.retractDwellRipple()
            }
        }

@@ -337,12 +354,12 @@ class AuthRippleController @Inject constructor(
                    "fingerprint" -> {
                        updateSensorLocation()
                        pw.println("fingerprint ripple sensorLocation=$fingerprintSensorLocation")
                        showRipple(BiometricSourceType.FINGERPRINT)
                        showUnlockRipple(BiometricSourceType.FINGERPRINT)
                    }
                    "face" -> {
                        updateSensorLocation()
                        pw.println("face ripple sensorLocation=$faceSensorLocation")
                        showRipple(BiometricSourceType.FACE)
                        showUnlockRipple(BiometricSourceType.FACE)
                    }
                    "custom" -> {
                        if (args.size != 3 ||
+54 −14
Original line number Diff line number Diff line
@@ -35,12 +35,13 @@ import com.android.systemui.statusbar.charging.RippleShader
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f

/**
 * Expanding ripple effect
 * - startUnlockedRipple for the transition from biometric authentication success to showing
 * launcher.
 * - startDwellRipple for the ripple expansion out when the user has their finger down on the UDFPS
 * sensor area
 * - retractRipple for the ripple animation inwards to signal a failure
 * Handles two ripple effects: dwell ripple and unlocked ripple
 * Dwell Ripple:
 *     - startDwellRipple: dwell ripple expands outwards around the biometric area
 *     - retractDwellRipple: retracts the dwell ripple to radius 0 to signal a failure
 *     - fadeDwellRipple: fades the dwell ripple away to alpha 0
 * Unlocked ripple:
 *     - startUnlockedRipple: ripple expands from biometric auth location to the edges of the screen
 */
class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
    private val retractInterpolator = PathInterpolator(.05f, .93f, .1f, 1f)
@@ -52,6 +53,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
    private var drawRipple: Boolean = false

    private var lockScreenColorVal = Color.WHITE
    private val fadeDuration = 83L
    private val retractDuration = 400L
    private var alphaInDuration: Long = 0
    private var unlockedRippleInProgress: Boolean = false
@@ -59,7 +61,8 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
    private val dwellPaint = Paint()
    private val rippleShader = RippleShader()
    private val ripplePaint = Paint()
    private var retractAnimator: Animator? = null
    private var fadeDwellAnimator: Animator? = null
    private var retractDwellAnimator: Animator? = null
    private var dwellPulseOutAnimator: Animator? = null
    private var dwellRadius: Float = 0f
        set(value) {
@@ -112,15 +115,15 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
    }

    /**
     * Animate ripple inwards back to radius 0
     * Animate dwell ripple inwards back to radius 0
     */
    fun retractRipple() {
        if (retractAnimator?.isRunning == true) {
    fun retractDwellRipple() {
        if (retractDwellAnimator?.isRunning == true || fadeDwellAnimator?.isRunning == true) {
            return // let the animation finish
        }

        if (dwellPulseOutAnimator?.isRunning == true) {
            val retractRippleAnimator = ValueAnimator.ofFloat(dwellShader.progress, 0f)
            val retractDwellRippleAnimator = ValueAnimator.ofFloat(dwellShader.progress, 0f)
                    .apply {
                interpolator = retractInterpolator
                duration = retractDuration
@@ -145,8 +148,8 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
                }
            }

            retractAnimator = AnimatorSet().apply {
                playTogether(retractRippleAnimator, retractAlphaAnimator)
            retractDwellAnimator = AnimatorSet().apply {
                playTogether(retractDwellRippleAnimator, retractAlphaAnimator)
                addListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationStart(animation: Animator?) {
                        dwellPulseOutAnimator?.cancel()
@@ -163,6 +166,42 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
        }
    }

    /**
     * Animate ripple fade to alpha=0
     */
    fun fadeDwellRipple() {
        if (fadeDwellAnimator?.isRunning == true) {
            return // let the animation finish
        }

        if (dwellPulseOutAnimator?.isRunning == true || retractDwellAnimator?.isRunning == true) {
            fadeDwellAnimator = ValueAnimator.ofInt(Color.alpha(dwellShader.color), 0).apply {
                interpolator = Interpolators.LINEAR
                duration = fadeDuration
                addUpdateListener { animator ->
                    dwellShader.color = ColorUtils.setAlphaComponent(
                            dwellShader.color,
                            animator.animatedValue as Int
                    )
                    invalidate()
                }
                addListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationStart(animation: Animator?) {
                        retractDwellAnimator?.cancel()
                        dwellPulseOutAnimator?.cancel()
                        drawDwell = true
                    }

                    override fun onAnimationEnd(animation: Animator?) {
                        drawDwell = false
                        resetDwellAlpha()
                    }
                })
                start()
            }
        }
    }

    /**
     * Plays a ripple animation that grows to the dwellRadius with distortion.
     */
@@ -205,7 +244,8 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
            )
            addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationStart(animation: Animator?) {
                    retractAnimator?.cancel()
                    retractDwellAnimator?.cancel()
                    fadeDwellAnimator?.cancel()
                    visibility = VISIBLE
                    drawDwell = true
                }
+1 −1
Original line number Diff line number Diff line
@@ -299,7 +299,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
        `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
        `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)

        controller.showRipple(BiometricSourceType.FINGERPRINT)
        controller.showUnlockRipple(BiometricSourceType.FINGERPRINT)
        assertTrue("reveal didn't start on keyguardFadingAway",
            controller.startLightRevealScrimOnKeyguardFadingAway)
        `when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true)