summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt110
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt57
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt6
3 files changed, 149 insertions, 24 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt
index 6e78f3d3d6aa..57652dc44aa6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt
@@ -19,6 +19,7 @@ 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.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
@@ -31,14 +32,22 @@ import android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
+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.*
import java.util.concurrent.Executor
import javax.inject.Inject
+import kotlin.math.cos
+import kotlin.math.pow
+import kotlin.math.sin
private const val TAG = "UdfpsOverlay"
+// Number of sensor points needed inside ellipse for good overlap
+private const val NEEDED_POINTS = 3
+
@SuppressLint("ClickableViewAccessibility")
@SysUISingleton
class UdfpsOverlay
@@ -54,7 +63,8 @@ constructor(
private val fgExecutor: DelayableExecutor,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val authController: AuthController,
- private val udfpsLogger: UdfpsLogger
+ private val udfpsLogger: UdfpsLogger,
+ private var featureFlags: FeatureFlags
) : CoreStartable {
/** The view, when [isShowing], or null. */
@@ -65,6 +75,8 @@ constructor(
private var onFingerDown = false
val size = windowManager.maximumWindowMetrics.bounds
val udfpsProps: MutableList<FingerprintSensorPropertiesInternal> = mutableListOf()
+ var points: Array<Point> = emptyArray()
+ var processedMotionEvent = false
private var params: UdfpsOverlayParams = UdfpsOverlayParams()
@@ -95,33 +107,47 @@ constructor(
MotionEvent.ACTION_MOVE -> {
onFingerDown = true
if (!view.isDisplayConfigured && alternateTouchProvider.isPresent) {
- biometricExecutor.execute {
- alternateTouchProvider
- .get()
- .onPointerDown(
- requestId,
- event.x.toInt(),
- event.y.toInt(),
- event.touchMinor,
- event.touchMajor
- )
- }
- fgExecutor.execute {
- if (keyguardUpdateMonitor.isFingerprintDetectionRunning) {
- keyguardUpdateMonitor.onUdfpsPointerDown(requestId.toInt())
+ view.processMotionEvent(event)
+
+ val goodOverlap =
+ if (featureFlags.isEnabled(Flags.NEW_ELLIPSE_DETECTION)) {
+ isGoodEllipseOverlap(event)
+ } else {
+ isGoodCentroidOverlap(event)
+ }
+
+ if (!processedMotionEvent && goodOverlap) {
+ biometricExecutor.execute {
+ alternateTouchProvider
+ .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.get().onUiReady() }
}
- }
- view.configureDisplay {
- biometricExecutor.execute { alternateTouchProvider.get().onUiReady() }
+ processedMotionEvent = true
}
}
+ view.invalidate()
true
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL -> {
- if (onFingerDown && alternateTouchProvider.isPresent) {
+ if (processedMotionEvent && alternateTouchProvider.isPresent) {
biometricExecutor.execute {
alternateTouchProvider.get().onPointerUp(requestId)
}
@@ -130,18 +156,44 @@ constructor(
keyguardUpdateMonitor.onUdfpsPointerUp(requestId.toInt())
}
}
+
+ processedMotionEvent = false
}
- onFingerDown = 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(0)(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): Boolean {
this.requestId = requestId
if (overlayView == null && alternateTouchProvider.isPresent) {
@@ -151,6 +203,7 @@ constructor(
UdfpsDisplayMode(context, execution, authController, udfpsLogger)
)
it.setOnTouchListener { v, event -> onTouch(v, event) }
+ it.sensorPoints = points
overlayView = it
}
windowManager.addView(overlayView, coreLayoutParams)
@@ -201,6 +254,23 @@ constructor(
naturalDisplayHeight = size.height(),
scaleFactor = 1f
)
+
+ val sensorX = params.sensorBounds.centerX()
+ val sensorY = params.sensorBounds.centerY()
+ val gridOffset: Int = params.sensorBounds.width() / 3
+
+ points =
+ arrayOf(
+ Point(sensorX - gridOffset, sensorY - gridOffset),
+ Point(sensorX, sensorY - gridOffset),
+ Point(sensorX + gridOffset, sensorY - gridOffset),
+ Point(sensorX - gridOffset, sensorY),
+ Point(sensorX, sensorY),
+ Point(sensorX + gridOffset, sensorY),
+ Point(sensorX - gridOffset, sensorY + gridOffset),
+ Point(sensorX, sensorY + gridOffset),
+ Point(sensorX + gridOffset, sensorY + gridOffset)
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt
index d37133239531..25e08d705736 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt
@@ -20,26 +20,39 @@ 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
private const val TAG = "UdfpsOverlayView"
+private const val POINT_SIZE = 10f
class UdfpsOverlayView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
-
- private val sensorRect = RectF()
var overlayParams = UdfpsOverlayParams()
private var mUdfpsDisplayMode: UdfpsDisplayMode? = null
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)
}
@@ -47,16 +60,23 @@ class UdfpsOverlayView(context: Context, attrs: AttributeSet?) : FrameLayout(con
override fun onAttachedToWindow() {
super.onAttachedToWindow()
- overlayPaint.color = Color.argb(120, 255, 0, 0)
+ 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)
+ // Draw overlay and sensor
canvas.drawRect(overlayParams.overlayBounds, overlayPaint)
canvas.drawRect(overlayParams.sensorBounds, sensorPaint)
canvas.drawCircle(
@@ -65,6 +85,29 @@ class UdfpsOverlayView(context: Context, attrs: AttributeSet?) : FrameLayout(con
overlayParams.sensorBounds.width().toFloat() / 2,
centerPaint
)
+
+ // 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?) {
@@ -80,4 +123,12 @@ class UdfpsOverlayView(context: Context, attrs: AttributeSet?) : FrameLayout(con
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()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 4818bccb1f64..80d84446f73b 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -124,6 +124,10 @@ object Flags {
*/
@JvmField val DOZING_MIGRATION_1 = UnreleasedFlag(213, teamfood = true)
+ @JvmField val NEW_ELLIPSE_DETECTION = UnreleasedFlag(214)
+
+ @JvmField val NEW_UDFPS_OVERLAY = UnreleasedFlag(215)
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = ReleasedFlag(300)