diff options
4 files changed, 108 insertions, 148 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index 90a1e5e64daf..f82ea790bb64 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -80,11 +80,6 @@ class AuthRippleController @Inject constructor( private var circleReveal: LightRevealEffect? = null private var udfpsController: UdfpsController? = null - - private var dwellScale = 2f - private var expandedDwellScale = 2.5f - private var aodDwellScale = 1.9f - private var aodExpandedDwellScale = 2.3f private var udfpsRadius: Float = -1f override fun onInit() { @@ -128,7 +123,7 @@ class AuthRippleController @Inject constructor( updateSensorLocation() if (biometricSourceType == BiometricSourceType.FINGERPRINT && fingerprintSensorLocation != null) { - mView.setSensorLocation(fingerprintSensorLocation!!) + mView.setFingerprintSensorLocation(fingerprintSensorLocation!!, udfpsRadius) showUnlockedRipple() } else if (biometricSourceType == BiometricSourceType.FACE && faceSensorLocation != null) { @@ -241,24 +236,12 @@ class AuthRippleController @Inject constructor( } private fun updateRippleColor() { - mView.setColor( - Utils.getColorAttr(sysuiContext, android.R.attr.colorAccent).defaultColor) + mView.setLockScreenColor(Utils.getColorAttrDefaultColor(sysuiContext, + R.attr.wallpaperTextColorAccent)) } private fun showDwellRipple() { - if (statusBarStateController.isDozing) { - mView.startDwellRipple( - /* startRadius */ udfpsRadius, - /* endRadius */ udfpsRadius * aodDwellScale, - /* expandedRadius */ udfpsRadius * aodExpandedDwellScale, - /* isDozing */ true) - } else { - mView.startDwellRipple( - /* startRadius */ udfpsRadius, - /* endRadius */ udfpsRadius * dwellScale, - /* expandedRadius */ udfpsRadius * expandedDwellScale, - /* isDozing */ false) - } + mView.startDwellRipple(statusBarStateController.isDozing) } private val keyguardUpdateMonitorCallback = @@ -295,7 +278,7 @@ class AuthRippleController @Inject constructor( return } - mView.setSensorLocation(fingerprintSensorLocation!!) + mView.setFingerprintSensorLocation(fingerprintSensorLocation!!, udfpsRadius) showDwellRipple() } @@ -307,8 +290,8 @@ class AuthRippleController @Inject constructor( private val authControllerCallback = object : AuthController.Callback { override fun onAllAuthenticatorsRegistered() { - updateSensorLocation() updateUdfpsDependentParams() + updateSensorLocation() } override fun onEnrollmentsChanged() { @@ -329,20 +312,6 @@ class AuthRippleController @Inject constructor( } inner class AuthRippleCommand : Command { - fun printLockScreenDwellInfo(pw: PrintWriter) { - pw.println("lock screen dwell ripple: " + - "\n\tsensorLocation=$fingerprintSensorLocation" + - "\n\tdwellScale=$dwellScale" + - "\n\tdwellExpand=$expandedDwellScale") - } - - fun printAodDwellInfo(pw: PrintWriter) { - pw.println("aod dwell ripple: " + - "\n\tsensorLocation=$fingerprintSensorLocation" + - "\n\tdwellScale=$aodDwellScale" + - "\n\tdwellExpand=$aodExpandedDwellScale") - } - override fun execute(pw: PrintWriter, args: List<String>) { if (args.isEmpty()) { invalidCommand(pw) @@ -350,11 +319,9 @@ class AuthRippleController @Inject constructor( when (args[0]) { "dwell" -> { showDwellRipple() - if (statusBarStateController.isDozing) { - printAodDwellInfo(pw) - } else { - printLockScreenDwellInfo(pw) - } + pw.println("lock screen dwell ripple: " + + "\n\tsensorLocation=$fingerprintSensorLocation" + + "\n\tudfpsRadius=$udfpsRadius") } "fingerprint" -> { updateSensorLocation() diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt index c6d26ffb9957..d67363079e17 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt @@ -21,6 +21,7 @@ import android.animation.AnimatorSet import android.animation.ValueAnimator import android.content.Context import android.graphics.Canvas +import android.graphics.Color import android.graphics.Paint import android.graphics.PointF import android.util.AttributeSet @@ -28,6 +29,7 @@ import android.view.View import android.view.animation.PathInterpolator import com.android.internal.graphics.ColorUtils import com.android.systemui.animation.Interpolators +import com.android.systemui.statusbar.charging.DwellRippleShader import com.android.systemui.statusbar.charging.RippleShader private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f @@ -43,23 +45,32 @@ private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) { private val retractInterpolator = PathInterpolator(.05f, .93f, .1f, 1f) - private val dwellPulseDuration = 50L - private val dwellAlphaDuration = dwellPulseDuration - private val dwellAlpha: Float = 1f - private val dwellExpandDuration = 1200L - dwellPulseDuration + private val dwellPulseDuration = 100L + private val dwellExpandDuration = 2000L - dwellPulseDuration - private val aodDwellPulseDuration = 50L - private var aodDwellAlphaDuration = aodDwellPulseDuration - private var aodDwellAlpha: Float = .8f - private var aodDwellExpandDuration = 1200L - aodDwellPulseDuration + private var drawDwell: Boolean = false + private var drawRipple: Boolean = false + private var lockScreenColorVal = Color.WHITE private val retractDuration = 400L private var alphaInDuration: Long = 0 private var unlockedRippleInProgress: Boolean = false + private val dwellShader = DwellRippleShader() + private val dwellPaint = Paint() private val rippleShader = RippleShader() private val ripplePaint = Paint() private var retractAnimator: Animator? = null private var dwellPulseOutAnimator: Animator? = null + private var dwellRadius: Float = 0f + set(value) { + dwellShader.maxRadius = value + field = value + } + private var dwellOrigin: PointF = PointF() + set(value) { + dwellShader.origin = value + field = value + } private var radius: Float = 0f set(value) { rippleShader.radius = value @@ -76,6 +87,11 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at rippleShader.progress = 0f rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH ripplePaint.shader = rippleShader + + dwellShader.color = 0xffffffff.toInt() // default color + dwellShader.progress = 0f + dwellShader.distortionStrength = .4f + dwellPaint.shader = dwellShader visibility = GONE } @@ -84,6 +100,13 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at radius = maxOf(location.x, location.y, width - location.x, height - location.y).toFloat() } + fun setFingerprintSensorLocation(location: PointF, sensorRadius: Float) { + origin = location + radius = maxOf(location.x, location.y, width - location.x, height - location.y).toFloat() + dwellOrigin = location + dwellRadius = sensorRadius * 1.5f + } + fun setAlphaInDuration(duration: Long) { alphaInDuration = duration } @@ -97,14 +120,14 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at } if (dwellPulseOutAnimator?.isRunning == true) { - val retractRippleAnimator = ValueAnimator.ofFloat(rippleShader.progress, 0f) + val retractRippleAnimator = ValueAnimator.ofFloat(dwellShader.progress, 0f) .apply { interpolator = retractInterpolator duration = retractDuration addUpdateListener { animator -> val now = animator.currentPlayTime - rippleShader.progress = animator.animatedValue as Float - rippleShader.time = now.toFloat() + dwellShader.progress = animator.animatedValue as Float + dwellShader.time = now.toFloat() invalidate() } @@ -114,8 +137,8 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at interpolator = Interpolators.LINEAR duration = retractDuration addUpdateListener { animator -> - rippleShader.color = ColorUtils.setAlphaComponent( - rippleShader.color, + dwellShader.color = ColorUtils.setAlphaComponent( + dwellShader.color, animator.animatedValue as Int ) invalidate() @@ -127,13 +150,12 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at addListener(object : AnimatorListenerAdapter() { override fun onAnimationStart(animation: Animator?) { dwellPulseOutAnimator?.cancel() - rippleShader.shouldFadeOutRipple = false - visibility = VISIBLE + drawDwell = true } override fun onAnimationEnd(animation: Animator?) { - visibility = GONE - resetRippleAlpha() + drawDwell = false + resetDwellAlpha() } }) start() @@ -142,101 +164,54 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at } /** - * Ripple that moves animates from an outer ripple ring of - * startRadius => endRadius => expandedRadius + * Plays a ripple animation that grows to the dwellRadius with distortion. */ - fun startDwellRipple( - startRadius: Float, - endRadius: Float, - expandedRadius: Float, - isDozing: Boolean - ) { + fun startDwellRipple(isDozing: Boolean) { if (unlockedRippleInProgress || dwellPulseOutAnimator?.isRunning == true) { return } - // we divide by 4 because the desired startRadius and endRadius is for the ripple's outer - // ring see RippleShader - val startDwellProgress = startRadius / radius / 4f - val endInitialDwellProgress = endRadius / radius / 4f - val endExpandDwellProgress = expandedRadius / radius / 4f - - val alpha = if (isDozing) aodDwellAlpha else dwellAlpha - val pulseOutEndAlpha = (255 * alpha).toInt() - val expandDwellEndAlpha = kotlin.math.min((255 * (alpha + .25f)).toInt(), 255) - val dwellPulseOutRippleAnimator = ValueAnimator.ofFloat(startDwellProgress, - endInitialDwellProgress).apply { - interpolator = Interpolators.LINEAR_OUT_SLOW_IN - duration = if (isDozing) aodDwellPulseDuration else dwellPulseDuration - addUpdateListener { animator -> - val now = animator.currentPlayTime - rippleShader.progress = animator.animatedValue as Float - rippleShader.time = now.toFloat() - - invalidate() - } - } + updateDwellRippleColor(isDozing) - val dwellPulseOutAlphaAnimator = ValueAnimator.ofInt(0, pulseOutEndAlpha).apply { + val dwellPulseOutRippleAnimator = ValueAnimator.ofFloat(0f, .8f).apply { interpolator = Interpolators.LINEAR - duration = if (isDozing) aodDwellAlphaDuration else dwellAlphaDuration + duration = dwellPulseDuration addUpdateListener { animator -> - rippleShader.color = ColorUtils.setAlphaComponent( - rippleShader.color, - animator.animatedValue as Int - ) + val now = animator.currentPlayTime + dwellShader.progress = animator.animatedValue as Float + dwellShader.time = now.toFloat() + invalidate() } } // slowly animate outwards until we receive a call to retractRipple or startUnlockedRipple - val expandDwellRippleAnimator = ValueAnimator.ofFloat(endInitialDwellProgress, - endExpandDwellProgress).apply { + val expandDwellRippleAnimator = ValueAnimator.ofFloat(.8f, 1f).apply { interpolator = Interpolators.LINEAR_OUT_SLOW_IN - duration = if (isDozing) aodDwellExpandDuration else dwellExpandDuration + duration = dwellExpandDuration addUpdateListener { animator -> val now = animator.currentPlayTime - rippleShader.progress = animator.animatedValue as Float - rippleShader.time = now.toFloat() + dwellShader.progress = animator.animatedValue as Float + dwellShader.time = now.toFloat() invalidate() } } - val expandDwellAlphaAnimator = ValueAnimator.ofInt(pulseOutEndAlpha, expandDwellEndAlpha) - .apply { - interpolator = Interpolators.LINEAR - duration = if (isDozing) aodDwellExpandDuration else dwellExpandDuration - addUpdateListener { animator -> - rippleShader.color = ColorUtils.setAlphaComponent( - rippleShader.color, - animator.animatedValue as Int - ) - invalidate() - } - } - - val initialDwellPulseOutAnimator = AnimatorSet().apply { - playTogether(dwellPulseOutRippleAnimator, dwellPulseOutAlphaAnimator) - } - val expandDwellAnimator = AnimatorSet().apply { - playTogether(expandDwellRippleAnimator, expandDwellAlphaAnimator) - } - dwellPulseOutAnimator = AnimatorSet().apply { playSequentially( - initialDwellPulseOutAnimator, - expandDwellAnimator + dwellPulseOutRippleAnimator, + expandDwellRippleAnimator ) addListener(object : AnimatorListenerAdapter() { override fun onAnimationStart(animation: Animator?) { retractAnimator?.cancel() - rippleShader.shouldFadeOutRipple = false visibility = VISIBLE + drawDwell = true } override fun onAnimationEnd(animation: Animator?) { - visibility = GONE + drawDwell = false resetRippleAlpha() } }) @@ -252,16 +227,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at return // Ignore if ripple effect is already playing } - var rippleStart = 0f - var alphaDuration = alphaInDuration - if (dwellPulseOutAnimator?.isRunning == true || retractAnimator?.isRunning == true) { - rippleStart = rippleShader.progress - alphaDuration = 0 - dwellPulseOutAnimator?.cancel() - retractAnimator?.cancel() - } - - val rippleAnimator = ValueAnimator.ofFloat(rippleStart, 1f).apply { + val rippleAnimator = ValueAnimator.ofFloat(0f, 1f).apply { interpolator = Interpolators.LINEAR_OUT_SLOW_IN duration = AuthRippleController.RIPPLE_ANIMATION_DURATION addUpdateListener { animator -> @@ -274,7 +240,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at } val alphaInAnimator = ValueAnimator.ofInt(0, 255).apply { - duration = alphaDuration + duration = alphaInDuration addUpdateListener { animator -> rippleShader.color = ColorUtils.setAlphaComponent( rippleShader.color, @@ -293,12 +259,14 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at override fun onAnimationStart(animation: Animator?) { unlockedRippleInProgress = true rippleShader.shouldFadeOutRipple = true + drawRipple = true visibility = VISIBLE } override fun onAnimationEnd(animation: Animator?) { onAnimationEnd?.run() unlockedRippleInProgress = false + drawRipple = false visibility = GONE } }) @@ -313,17 +281,42 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at ) } - fun setColor(color: Int) { - rippleShader.color = color + fun setLockScreenColor(color: Int) { + lockScreenColorVal = color + rippleShader.color = lockScreenColorVal resetRippleAlpha() } + fun updateDwellRippleColor(isDozing: Boolean) { + if (isDozing) { + dwellShader.color = Color.WHITE + } else { + dwellShader.color = lockScreenColorVal + } + resetDwellAlpha() + } + + fun resetDwellAlpha() { + dwellShader.color = ColorUtils.setAlphaComponent( + dwellShader.color, + 255 + ) + } + override fun onDraw(canvas: Canvas?) { // To reduce overdraw, we mask the effect to a circle whose radius is big enough to cover // the active effect area. Values here should be kept in sync with the // animation implementation in the ripple shader. - val maskRadius = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) * - (1 - rippleShader.progress)) * radius * 2f - canvas?.drawCircle(origin.x, origin.y, maskRadius, ripplePaint) + if (drawDwell) { + val maskRadius = (1 - (1 - dwellShader.progress) * (1 - dwellShader.progress) * + (1 - dwellShader.progress)) * dwellRadius * 2f + canvas?.drawCircle(dwellOrigin.x, dwellOrigin.y, maskRadius, dwellPaint) + } + + if (drawRipple) { + val mask = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) * + (1 - rippleShader.progress)) * radius * 2f + canvas?.drawCircle(origin.x, origin.y, mask, ripplePaint) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt index a1d086b5d768..73d3e2afac7c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt @@ -59,8 +59,8 @@ class DwellRippleShader internal constructor() : RuntimeShader(SHADER, false) { } vec2 distort(vec2 p, float time, float distort_amount_xy, float frequency) { - return p + vec2(sin(p.x * frequency + in_phase1), - cos(p.y * frequency * 1.23 + in_phase2)) * distort_amount_xy; + return p + vec2(sin(p.y * frequency + in_phase1), + cos(p.x * frequency * -1.23 + in_phase2)) * distort_amount_xy; } vec4 ripple(vec2 p, float distort_xy, float frequency) { @@ -73,11 +73,11 @@ class DwellRippleShader internal constructor() : RuntimeShader(SHADER, false) { """ private const val SHADER_MAIN = """vec4 main(vec2 p) { vec4 color1 = ripple(p, - 12 * in_distortion_strength, // distort_xy + 34 * in_distortion_strength, // distort_xy 0.012 // frequency ); vec4 color2 = ripple(p, - 17.5 * in_distortion_strength, // distort_xy + 49 * in_distortion_strength, // distort_xy 0.018 // frequency ); // Alpha blend between two layers. @@ -128,8 +128,8 @@ class DwellRippleShader internal constructor() : RuntimeShader(SHADER, false) { set(value) { field = value * 0.001f setUniform("in_time", field) - setUniform("in_phase1", field * 2f + 0.367f) - setUniform("in_phase2", field * 5.2f * 1.531f) + setUniform("in_phase1", field * 3f + 0.367f) + setUniform("in_phase2", field * 7.2f * 1.531f) } /** 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 2c4808a4b84f..5128ccc15d9d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt @@ -131,7 +131,7 @@ class AuthRippleControllerTest : SysuiTestCase() { false /* isStrongBiometric */) // THEN update sensor location and show ripple - verify(rippleView).setSensorLocation(fpsLocation) + verify(rippleView).setFingerprintSensorLocation(fpsLocation, -1f) verify(rippleView).startUnlockedRipple(any()) } @@ -292,10 +292,10 @@ class AuthRippleControllerTest : SysuiTestCase() { reset(rippleView) captor.value.onThemeChanged() - verify(rippleView).setColor(ArgumentMatchers.anyInt()) + verify(rippleView).setLockScreenColor(ArgumentMatchers.anyInt()) reset(rippleView) captor.value.onUiModeChanged() - verify(rippleView).setColor(ArgumentMatchers.anyInt()) + verify(rippleView).setLockScreenColor(ArgumentMatchers.anyInt()) } } |