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

Commit 2349ea23 authored by Austin Delgado's avatar Austin Delgado Committed by Automerger Merge Worker
Browse files

Merge "Remove unused UdfpsOverlay and UdfpsOverlay View" into udc-dev am: c46d48e7

parents a08775ee c46d48e7
Loading
Loading
Loading
Loading
+0 −345
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.biometrics

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.Point
import android.graphics.Rect
import android.hardware.biometrics.BiometricOverlayConstants
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
import android.hardware.fingerprint.IUdfpsOverlay
import android.os.Handler
import android.provider.Settings
import android.view.MotionEvent
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.settingslib.udfps.UdfpsOverlayParams
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.Execution
import java.util.Optional
import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Provider
import kotlin.math.cos
import kotlin.math.pow
import kotlin.math.sin

private const val TAG = "UdfpsOverlay"

const val SETTING_OVERLAY_DEBUG = "udfps_overlay_debug"

// Number of sensor points needed inside ellipse for good overlap
private const val NEEDED_POINTS = 2

@SuppressLint("ClickableViewAccessibility")
@SysUISingleton
class UdfpsOverlay
@Inject
constructor(
    private val context: Context,
    private val execution: Execution,
    private val windowManager: WindowManager,
    private val fingerprintManager: FingerprintManager?,
    private val handler: Handler,
    private val biometricExecutor: Executor,
    private val alternateTouchProvider: Optional<Provider<AlternateUdfpsTouchProvider>>,
    @Main private val fgExecutor: DelayableExecutor,
    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
    private val authController: AuthController,
    private val udfpsLogger: UdfpsLogger,
    private var featureFlags: FeatureFlags
) : CoreStartable {

    /** The view, when [isShowing], or null. */
    var overlayView: UdfpsOverlayView? = null
        private set

    private var requestId: Long = 0
    private var onFingerDown = false
    val size = windowManager.maximumWindowMetrics.bounds

    val udfpsProps: MutableList<FingerprintSensorPropertiesInternal> = mutableListOf()
    var points: Array<Point> = emptyArray()
    var processedMotionEvent = false
    var isShowing = false

    private var params: UdfpsOverlayParams = UdfpsOverlayParams()

    private val coreLayoutParams =
        WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
                0 /* flags set in computeLayoutParams() */,
                PixelFormat.TRANSLUCENT
            )
            .apply {
                title = TAG
                fitInsetsTypes = 0
                gravity = android.view.Gravity.TOP or android.view.Gravity.LEFT
                layoutInDisplayCutoutMode =
                    WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
                flags = Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS
                privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
                // Avoid announcing window title.
                accessibilityTitle = " "
                inputFeatures = INPUT_FEATURE_SPY
            }

    fun onTouch(event: MotionEvent): Boolean {
        val view = overlayView!!

        return when (event.action) {
            MotionEvent.ACTION_DOWN,
            MotionEvent.ACTION_MOVE -> {
                onFingerDown = true
                if (!view.isDisplayConfigured && alternateTouchProvider.isPresent) {
                    view.processMotionEvent(event)

                    val goodOverlap =
                        if (featureFlags.isEnabled(Flags.NEW_ELLIPSE_DETECTION)) {
                            isGoodEllipseOverlap(event)
                        } else {
                            isGoodCentroidOverlap(event)
                        }

                    if (!processedMotionEvent && goodOverlap) {
                        biometricExecutor.execute {
                            alternateTouchProvider
                                .map(Provider<AlternateUdfpsTouchProvider>::get)
                                .get()
                                .onPointerDown(
                                    requestId,
                                    event.rawX.toInt(),
                                    event.rawY.toInt(),
                                    event.touchMinor,
                                    event.touchMajor
                                )
                        }
                        fgExecutor.execute {
                            if (keyguardUpdateMonitor.isFingerprintDetectionRunning) {
                                keyguardUpdateMonitor.onUdfpsPointerDown(requestId.toInt())
                            }

                            view.configureDisplay {
                                biometricExecutor.execute {
                                    alternateTouchProvider
                                        .map(Provider<AlternateUdfpsTouchProvider>::get)
                                        .get()
                                        .onUiReady()
                                }
                            }

                            processedMotionEvent = true
                        }
                    }

                    view.invalidate()
                }
                true
            }
            MotionEvent.ACTION_UP,
            MotionEvent.ACTION_CANCEL -> {
                if (processedMotionEvent && alternateTouchProvider.isPresent) {
                    biometricExecutor.execute {
                        alternateTouchProvider
                            .map(Provider<AlternateUdfpsTouchProvider>::get)
                            .get()
                            .onPointerUp(requestId)
                    }
                    fgExecutor.execute {
                        if (keyguardUpdateMonitor.isFingerprintDetectionRunning) {
                            keyguardUpdateMonitor.onUdfpsPointerUp(requestId.toInt())
                        }
                    }

                    processedMotionEvent = false
                }

                if (view.isDisplayConfigured) {
                    view.unconfigureDisplay()
                }

                view.invalidate()
                true
            }
            else -> false
        }
    }

    fun isGoodEllipseOverlap(event: MotionEvent): Boolean {
        return points.count { checkPoint(event, it) } >= NEEDED_POINTS
    }

    fun isGoodCentroidOverlap(event: MotionEvent): Boolean {
        return params.sensorBounds.contains(event.rawX.toInt(), event.rawY.toInt())
    }

    fun checkPoint(event: MotionEvent, point: Point): Boolean {
        // Calculate if sensor point is within ellipse
        // Formula: ((cos(o)(xE - xS) + sin(o)(yE - yS))^2 / a^2) + ((sin(o)(xE - xS) + cos(o)(yE -
        // yS))^2 / b^2) <= 1
        val a: Float = cos(event.orientation) * (point.x - event.rawX)
        val b: Float = sin(event.orientation) * (point.y - event.rawY)
        val c: Float = sin(event.orientation) * (point.x - event.rawX)
        val d: Float = cos(event.orientation) * (point.y - event.rawY)
        val result =
            (a + b).pow(2) / (event.touchMinor / 2).pow(2) +
                (c - d).pow(2) / (event.touchMajor / 2).pow(2)

        return result <= 1
    }

    fun show(requestId: Long) {
        if (!featureFlags.isEnabled(Flags.NEW_UDFPS_OVERLAY)) {
            return
        }

        this.requestId = requestId
        fgExecutor.execute {
            if (overlayView == null && alternateTouchProvider.isPresent) {
                UdfpsOverlayView(context, null).let {
                    it.overlayParams = params
                    it.setUdfpsDisplayMode(
                        UdfpsDisplayMode(context, execution, authController, udfpsLogger)
                    )
                    it.setOnTouchListener { _, event -> onTouch(event) }
                    it.sensorPoints = points
                    it.debugOverlay =
                        Settings.Global.getInt(
                            context.contentResolver,
                            SETTING_OVERLAY_DEBUG,
                            0 /* def */
                        ) != 0
                    overlayView = it
                }
                windowManager.addView(overlayView, coreLayoutParams)
                isShowing = true
            }
        }
    }

    fun hide() {
        if (!featureFlags.isEnabled(Flags.NEW_UDFPS_OVERLAY)) {
            return
        }

        fgExecutor.execute {
            if (overlayView != null && isShowing && alternateTouchProvider.isPresent) {
                if (processedMotionEvent) {
                    biometricExecutor.execute {
                        alternateTouchProvider
                            .map(Provider<AlternateUdfpsTouchProvider>::get)
                            .get()
                            .onPointerUp(requestId)
                    }
                    fgExecutor.execute {
                        if (keyguardUpdateMonitor.isFingerprintDetectionRunning) {
                            keyguardUpdateMonitor.onUdfpsPointerUp(requestId.toInt())
                        }
                    }
                }

                if (overlayView!!.isDisplayConfigured) {
                    overlayView!!.unconfigureDisplay()
                }

                overlayView?.apply {
                    windowManager.removeView(this)
                    setOnTouchListener(null)
                }

                isShowing = false
                overlayView = null
                processedMotionEvent = false
            }
        }
    }

    @Override
    override fun start() {
        fingerprintManager?.addAuthenticatorsRegisteredCallback(
            object : IFingerprintAuthenticatorsRegisteredCallback.Stub() {
                override fun onAllAuthenticatorsRegistered(
                    sensors: List<FingerprintSensorPropertiesInternal>
                ) {
                    handler.post { handleAllFingerprintAuthenticatorsRegistered(sensors) }
                }
            }
        )

        fingerprintManager?.setUdfpsOverlay(
            object : IUdfpsOverlay.Stub() {
                override fun show(
                    requestId: Long,
                    sensorId: Int,
                    @BiometricOverlayConstants.ShowReason reason: Int
                ) = show(requestId)

                override fun hide(sensorId: Int) = hide()
            }
        )
    }

    private fun handleAllFingerprintAuthenticatorsRegistered(
        sensors: List<FingerprintSensorPropertiesInternal>
    ) {
        for (props in sensors) {
            if (props.isAnyUdfpsType) {
                udfpsProps.add(props)
            }
        }

        // Setup param size
        if (udfpsProps.isNotEmpty()) {
            params =
                UdfpsOverlayParams(
                    sensorBounds = udfpsProps[0].location.rect,
                    overlayBounds = Rect(0, size.height() / 2, size.width(), size.height()),
                    naturalDisplayWidth = size.width(),
                    naturalDisplayHeight = size.height(),
                    scaleFactor = 1f
                )

            val sensorX = params.sensorBounds.centerX()
            val sensorY = params.sensorBounds.centerY()
            val cornerOffset: Int = params.sensorBounds.width() / 4
            val sideOffset: Int = params.sensorBounds.width() / 3

            points =
                arrayOf(
                    Point(sensorX - cornerOffset, sensorY - cornerOffset),
                    Point(sensorX, sensorY - sideOffset),
                    Point(sensorX + cornerOffset, sensorY - cornerOffset),
                    Point(sensorX - sideOffset, sensorY),
                    Point(sensorX, sensorY),
                    Point(sensorX + sideOffset, sensorY),
                    Point(sensorX - cornerOffset, sensorY + cornerOffset),
                    Point(sensorX, sensorY + sideOffset),
                    Point(sensorX + cornerOffset, sensorY + cornerOffset)
                )
        }
    }
}
+0 −143
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.biometrics

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Point
import android.graphics.RectF
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.FrameLayout
import com.android.settingslib.udfps.UdfpsOverlayParams

private const val TAG = "UdfpsOverlayView"
private const val POINT_SIZE = 10f

class UdfpsOverlayView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
    var overlayParams = UdfpsOverlayParams()
    private var mUdfpsDisplayMode: UdfpsDisplayMode? = null

    var debugOverlay = false

    var overlayPaint = Paint()
    var sensorPaint = Paint()
    var touchPaint = Paint()
    var pointPaint = Paint()
    val centerPaint = Paint()

    var oval = RectF()

    /** True after the call to [configureDisplay] and before the call to [unconfigureDisplay]. */
    var isDisplayConfigured: Boolean = false
        private set

    var touchX: Float = 0f
    var touchY: Float = 0f
    var touchMinor: Float = 0f
    var touchMajor: Float = 0f
    var touchOrientation: Double = 0.0

    var sensorPoints: Array<Point>? = null

    init {
        this.setWillNotDraw(false)
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()

        overlayPaint.color = Color.argb(100, 255, 0, 0)
        overlayPaint.style = Paint.Style.FILL

        touchPaint.color = Color.argb(200, 255, 255, 255)
        touchPaint.style = Paint.Style.FILL

        sensorPaint.color = Color.argb(150, 134, 204, 255)
        sensorPaint.style = Paint.Style.FILL

        pointPaint.color = Color.WHITE
        pointPaint.style = Paint.Style.FILL
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        if (debugOverlay) {
            // Draw overlay and sensor bounds
            canvas.drawRect(overlayParams.overlayBounds, overlayPaint)
            canvas.drawRect(overlayParams.sensorBounds, sensorPaint)
        }

        // Draw sensor circle
        canvas.drawCircle(
            overlayParams.sensorBounds.exactCenterX(),
            overlayParams.sensorBounds.exactCenterY(),
            overlayParams.sensorBounds.width().toFloat() / 2,
            centerPaint
        )

        if (debugOverlay) {
            // Draw Points
            sensorPoints?.forEach {
                canvas.drawCircle(it.x.toFloat(), it.y.toFloat(), POINT_SIZE, pointPaint)
            }

            // Draw touch oval
            canvas.save()
            canvas.rotate(Math.toDegrees(touchOrientation).toFloat(), touchX, touchY)

            oval.setEmpty()
            oval.set(
                touchX - touchMinor / 2,
                touchY + touchMajor / 2,
                touchX + touchMinor / 2,
                touchY - touchMajor / 2
            )

            canvas.drawOval(oval, touchPaint)

            // Draw center point
            canvas.drawCircle(touchX, touchY, POINT_SIZE, centerPaint)
            canvas.restore()
        }
    }

    fun setUdfpsDisplayMode(udfpsDisplayMode: UdfpsDisplayMode?) {
        mUdfpsDisplayMode = udfpsDisplayMode
    }

    fun configureDisplay(onDisplayConfigured: Runnable) {
        isDisplayConfigured = true
        mUdfpsDisplayMode?.enable(onDisplayConfigured)
    }

    fun unconfigureDisplay() {
        isDisplayConfigured = false
        mUdfpsDisplayMode?.disable(null /* onDisabled */)
    }

    fun processMotionEvent(event: MotionEvent) {
        touchX = event.rawX
        touchY = event.rawY
        touchMinor = event.touchMinor
        touchMajor = event.touchMajor
        touchOrientation = event.orientation.toDouble()
    }
}
+1 −16
Original line number Original line Diff line number Diff line
@@ -50,8 +50,7 @@ private const val MAJOR = 10F
 */
 */
@SysUISingleton
@SysUISingleton
class UdfpsShell @Inject constructor(
class UdfpsShell @Inject constructor(
    commandRegistry: CommandRegistry,
    commandRegistry: CommandRegistry
    private val udfpsOverlay: UdfpsOverlay
) : Command {
) : Command {


    /**
    /**
@@ -69,10 +68,6 @@ class UdfpsShell @Inject constructor(
    override fun execute(pw: PrintWriter, args: List<String>) {
    override fun execute(pw: PrintWriter, args: List<String>) {
        if (args.size == 1 && args[0] == "hide") {
        if (args.size == 1 && args[0] == "hide") {
            hideOverlay()
            hideOverlay()
        } else if (args.size == 2 && args[0] == "udfpsOverlay" && args[1] == "show") {
            showUdfpsOverlay()
        } else if (args.size == 2 && args[0] == "udfpsOverlay" && args[1] == "hide") {
            hideUdfpsOverlay()
        } else if (args.size == 2 && args[0] == "show") {
        } else if (args.size == 2 && args[0] == "show") {
            showOverlay(getEnrollmentReason(args[1]))
            showOverlay(getEnrollmentReason(args[1]))
        } else if (args.size == 1 && args[0] == "onUiReady") {
        } else if (args.size == 1 && args[0] == "onUiReady") {
@@ -131,16 +126,6 @@ class UdfpsShell @Inject constructor(
        )
        )
    }
    }


    private fun showUdfpsOverlay() {
        Log.v(TAG, "showUdfpsOverlay")
        udfpsOverlay.show(REQUEST_ID)
    }

    private fun hideUdfpsOverlay() {
        Log.v(TAG, "hideUdfpsOverlay")
        udfpsOverlay.hide()
    }

    private fun hideOverlay() {
    private fun hideOverlay() {
        udfpsOverlayController?.hideUdfpsOverlay(SENSOR_ID)
        udfpsOverlayController?.hideUdfpsOverlay(SENSOR_ID)
    }
    }
+0 −7
Original line number Original line Diff line number Diff line
@@ -25,7 +25,6 @@ import com.android.systemui.SliceBroadcastRelayHandler
import com.android.systemui.accessibility.SystemActions
import com.android.systemui.accessibility.SystemActions
import com.android.systemui.accessibility.WindowMagnification
import com.android.systemui.accessibility.WindowMagnification
import com.android.systemui.biometrics.AuthController
import com.android.systemui.biometrics.AuthController
import com.android.systemui.biometrics.UdfpsOverlay
import com.android.systemui.clipboardoverlay.ClipboardListener
import com.android.systemui.clipboardoverlay.ClipboardListener
import com.android.systemui.controls.dagger.StartControlsStartableModule
import com.android.systemui.controls.dagger.StartControlsStartableModule
import com.android.systemui.dagger.qualifiers.PerUser
import com.android.systemui.dagger.qualifiers.PerUser
@@ -229,12 +228,6 @@ abstract class SystemUICoreStartableModule {
    @ClassKey(KeyguardLiftController::class)
    @ClassKey(KeyguardLiftController::class)
    abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable
    abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable


    /** Inject into UdfpsOverlay.  */
    @Binds
    @IntoMap
    @ClassKey(UdfpsOverlay::class)
    abstract fun bindUdfpsOverlay(sysui: UdfpsOverlay): CoreStartable

    /** Inject into MediaTttSenderCoordinator. */
    /** Inject into MediaTttSenderCoordinator. */
    @Binds
    @Binds
    @IntoMap
    @IntoMap
+1 −2
Original line number Original line Diff line number Diff line
@@ -49,7 +49,6 @@ class UdfpsShellTest : SysuiTestCase() {
    private lateinit var udfpsShell: UdfpsShell
    private lateinit var udfpsShell: UdfpsShell


    @Mock lateinit var commandRegistry: CommandRegistry
    @Mock lateinit var commandRegistry: CommandRegistry
    @Mock lateinit var udfpsOverlay: UdfpsOverlay
    @Mock lateinit var udfpsOverlayController: UdfpsOverlayController
    @Mock lateinit var udfpsOverlayController: UdfpsOverlayController


    @Captor private lateinit var motionEvent: ArgumentCaptor<MotionEvent>
    @Captor private lateinit var motionEvent: ArgumentCaptor<MotionEvent>
@@ -60,7 +59,7 @@ class UdfpsShellTest : SysuiTestCase() {
    fun setup() {
    fun setup() {
        whenEver(udfpsOverlayController.sensorBounds).thenReturn(sensorBounds)
        whenEver(udfpsOverlayController.sensorBounds).thenReturn(sensorBounds)


        udfpsShell = UdfpsShell(commandRegistry, udfpsOverlay)
        udfpsShell = UdfpsShell(commandRegistry)
        udfpsShell.udfpsOverlayController = udfpsOverlayController
        udfpsShell.udfpsOverlayController = udfpsOverlayController
    }
    }