Merge "On UDFPS auth success, fade out the dwell ripple" into tm-dev
This commit is contained in:
commit
a545b2b7b4
@ -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) {
|
||||
|
@ -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 ||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user