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

Commit c9307675 authored by Chandru S's avatar Chandru S
Browse files

Reduce the trigger points for showing/hiding the scanning animation

 - Previously we were showing/hiding the scanning animation based on biometric auth events.
 - With this change, we only rely onShowCameraProtection and onHideCameraProtection to show/hide the scanning animation and to show the success pulse.

Fixes: 311715007
Flag: NONE
Test: everything builds
Test: manually
 1. Trigger face auth, let it timeout, see that the animation is all okay
 2. Trigger face auth, let it succeed, see that the animation is all okay
 3. Trigger face auth, let it fail, it should be the same as the timeout scenario
 4. Unlock the device, launch camera, see that the face scanning animation is not shown
 5. Trigger biometric prompt, tested the same three scenarios with biometric prompt.
Change-Id: I73ede8abe1f3c9bd78de40ca459dc67fdf8cd05a
parent e80499c3
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -209,11 +209,11 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
        return result
    }

    open fun enableShowProtection(show: Boolean) {
        if (showProtection == show) {
    open fun enableShowProtection(isCameraActive: Boolean) {
        if (showProtection == isCameraActive) {
            return
        }
        showProtection = show
        showProtection = isCameraActive
        updateProtectionBoundingPath()
        // Delay the relayout until the end of the animation when hiding the cutout,
        // otherwise we'd clip it.
+12 −79
Original line number Diff line number Diff line
@@ -28,12 +28,10 @@ import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import android.hardware.biometrics.BiometricSourceType
import android.view.View
import androidx.core.graphics.ColorUtils
import com.android.app.animation.Interpolators
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.settingslib.Utils
import com.android.systemui.biometrics.AuthController
import com.android.systemui.log.ScreenDecorationsLogger
@@ -66,26 +64,11 @@ class FaceScanningOverlay(
        com.android.internal.R.attr.materialColorPrimaryFixed)
    private var cameraProtectionAnimator: ValueAnimator? = null
    var hideOverlayRunnable: Runnable? = null
    var faceAuthSucceeded = false

    init {
        visibility = View.INVISIBLE // only show this view when face scanning is happening
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        mainExecutor.execute {
            keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        mainExecutor.execute {
            keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
        }
    }

    override fun setColor(color: Int) {
        cameraProtectionColor = color
        invalidate()
@@ -103,18 +86,22 @@ class FaceScanningOverlay(
        }
    }

    override fun enableShowProtection(show: Boolean) {
        val animationRequired =
    override fun enableShowProtection(isCameraActive: Boolean) {
        val scanningAnimationRequiredWhenCameraActive =
                keyguardUpdateMonitor.isFaceDetectionRunning || authController.isShowing
        val showScanningAnimNow = animationRequired && show
        if (showScanningAnimNow == showScanningAnim) {
        val faceAuthSucceeded = keyguardUpdateMonitor.isFaceAuthenticated
        val showScanningAnimationNow = scanningAnimationRequiredWhenCameraActive && isCameraActive
        if (showScanningAnimationNow == showScanningAnim) {
            return
        }
        logger.cameraProtectionShownOrHidden(keyguardUpdateMonitor.isFaceDetectionRunning,
        logger.cameraProtectionShownOrHidden(
                showScanningAnimationNow,
                keyguardUpdateMonitor.isFaceDetectionRunning,
                authController.isShowing,
                show,
                faceAuthSucceeded,
                isCameraActive,
                showScanningAnim)
        showScanningAnim = showScanningAnimNow
        showScanningAnim = showScanningAnimationNow
        updateProtectionBoundingPath()
        // Delay the relayout until the end of the animation when hiding,
        // otherwise we'd clip it.
@@ -125,7 +112,7 @@ class FaceScanningOverlay(

        cameraProtectionAnimator?.cancel()
        cameraProtectionAnimator = ValueAnimator.ofFloat(cameraProtectionProgress,
                if (showScanningAnimNow) SHOW_CAMERA_PROTECTION_SCALE
                if (showScanningAnimationNow) SHOW_CAMERA_PROTECTION_SCALE
                else HIDDEN_CAMERA_PROTECTION_SCALE).apply {
            startDelay =
                    if (showScanningAnim) 0
@@ -335,70 +322,16 @@ class FaceScanningOverlay(
        invalidate()
    }

    private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
        override fun onBiometricAuthenticated(
            userId: Int,
            biometricSourceType: BiometricSourceType?,
            isStrongBiometric: Boolean
        ) {
            if (biometricSourceType == BiometricSourceType.FACE) {
                post {
                    faceAuthSucceeded = true
                    logger.biometricEvent("biometricAuthenticated")
                    enableShowProtection(false)
                }
            }
        }

        override fun onBiometricAcquired(
            biometricSourceType: BiometricSourceType?,
            acquireInfo: Int
        ) {
            if (biometricSourceType == BiometricSourceType.FACE) {
                post {
                    faceAuthSucceeded = false // reset
                }
            }
        }

        override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) {
            if (biometricSourceType == BiometricSourceType.FACE) {
                post {
                    faceAuthSucceeded = false
                    logger.biometricEvent("biometricFailed")
                    enableShowProtection(false)
                }
            }
        }

        override fun onBiometricError(
            msgId: Int,
            errString: String?,
            biometricSourceType: BiometricSourceType?
        ) {
            if (biometricSourceType == BiometricSourceType.FACE) {
                post {
                    faceAuthSucceeded = false
                    logger.biometricEvent("biometricError")
                    enableShowProtection(false)
                }
            }
        }
    }

    companion object {
        private const val HIDDEN_RIM_SCALE = HIDDEN_CAMERA_PROTECTION_SCALE
        private const val SHOW_CAMERA_PROTECTION_SCALE = 1f

        private const val PULSE_RADIUS_IN = 1.1f
        private const val PULSE_RADIUS_OUT = 1.125f
        private const val PULSE_RADIUS_SUCCESS = 1.25f

        private const val CAMERA_PROTECTION_APPEAR_DURATION = 250L
        private const val PULSE_APPEAR_DURATION = 250L // without start delay

        private const val HALF_PULSE_DURATION = 500L

        private const val PULSE_SUCCESS_DISAPPEAR_DURATION = 400L
        private const val CAMERA_PROTECTION_SUCCESS_DISAPPEAR_DURATION = 500L // without start delay

+11 −9
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ private const val TAG = "ScreenDecorationsLog"
 *
 * To enable logcat echoing for an entire buffer:
 * ```
 *   adb shell settings put global systemui/buffer/ScreenDecorationsLog <logLevel>
 *   adb shell cmd statusbar echo -b ScreenDecorationsLog:<logLevel>
 *
 * ```
 */
@@ -134,33 +134,35 @@ constructor(
    }

    fun cameraProtectionShownOrHidden(
        showAnimationNow: Boolean,
        faceDetectionRunning: Boolean,
        biometricPromptShown: Boolean,
        requestedState: Boolean,
        faceAuthenticated: Boolean,
        isCameraActive: Boolean,
        currentlyShowing: Boolean
    ) {
        logBuffer.log(
            TAG,
            DEBUG,
            {
                str1 = "$showAnimationNow"
                bool1 = faceDetectionRunning
                bool2 = biometricPromptShown
                bool3 = requestedState
                str2 = "$faceAuthenticated"
                bool3 = isCameraActive
                bool4 = currentlyShowing
            },
            {
                "cameraProtectionShownOrHidden showAnimationNow: $str1, " +
                    "isFaceDetectionRunning: $bool1, " +
                    "isBiometricPromptShowing: $bool2, " +
                    "requestedState: $bool3, " +
                    "faceAuthenticated: $str2, " +
                    "isCameraActive: $bool3, " +
                    "currentState: $bool4"
            }
        )
    }

    fun biometricEvent(@CompileTimeConstant info: String) {
        logBuffer.log(TAG, DEBUG, info)
    }

    fun cameraProtectionEvent(@CompileTimeConstant cameraProtectionEvent: String) {
        logBuffer.log(TAG, DEBUG, cameraProtectionEvent)
    }