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

Commit d6998f74 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Add haptic feedback to auth ripple animation" into sc-dev am: 8c8765d3

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14666655

Change-Id: If12f6166f70101229e8ced3d2e1e25bc60f71248
parents 941f0bb1 8c8765d3
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -23,7 +23,11 @@ import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.PointF
import android.media.AudioAttributes
import android.os.VibrationEffect
import android.os.Vibrator
import android.util.AttributeSet
import android.util.MathUtils
import android.view.View
import android.view.animation.PathInterpolator
import com.android.internal.graphics.ColorUtils
@@ -31,15 +35,26 @@ import com.android.systemui.statusbar.charging.RippleShader

private const val RIPPLE_ANIMATION_DURATION: Long = 1533
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
private const val RIPPLE_VIBRATION_PRIMITIVE: Int = VibrationEffect.Composition.PRIMITIVE_LOW_TICK
private const val RIPPLE_VIBRATION_SIZE: Int = 60
private const val RIPPLE_VIBRATION_SCALE_START: Float = 0.6f
private const val RIPPLE_VIBRATION_SCALE_DECAY: Float = -0.1f

/**
 * Expanding ripple effect on the transition from biometric authentication success to showing
 * launcher.
 */
class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
    private val vibrator: Vibrator? = context?.getSystemService(Vibrator::class.java)
    private var rippleInProgress: Boolean = false
    private val rippleShader = RippleShader()
    private val ripplePaint = Paint()
    private val rippleVibrationEffect = createVibrationEffect(vibrator)
    private val rippleVibrationAttrs =
            AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
                    .build()

    init {
        rippleShader.color = 0xffffffff.toInt() // default color
@@ -95,6 +110,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
                visibility = GONE
            }
        })
        vibrate()
        animatorSet.start()
        visibility = VISIBLE
        rippleInProgress = true
@@ -108,4 +124,23 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
        // draw over the entire screen
        canvas?.drawRect(0f, 0f, width.toFloat(), height.toFloat(), ripplePaint)
    }

    private fun vibrate() {
        if (rippleVibrationEffect != null) {
            vibrator?.vibrate(rippleVibrationEffect, rippleVibrationAttrs)
        }
    }

    private fun createVibrationEffect(vibrator: Vibrator?): VibrationEffect? {
        if (vibrator?.areAllPrimitivesSupported(RIPPLE_VIBRATION_PRIMITIVE) == false) {
            return null
        }
        val composition = VibrationEffect.startComposition()
        for (i in 0 until RIPPLE_VIBRATION_SIZE) {
            val scale =
                    RIPPLE_VIBRATION_SCALE_START * MathUtils.exp(RIPPLE_VIBRATION_SCALE_DECAY * i)
            composition.addPrimitive(RIPPLE_VIBRATION_PRIMITIVE, scale, 0 /* delay */)
        }
        return composition.compose()
    }
}