diff --git a/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsOverlayParams.kt b/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsOverlayParams.kt index d55a027c2374b..b386e5e12504a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsOverlayParams.kt +++ b/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsOverlayParams.kt @@ -36,6 +36,9 @@ data class UdfpsOverlayParams( /** Same as [sensorBounds], but in native resolution. */ val nativeSensorBounds = Rect(sensorBounds).apply { scale(1f / scaleFactor) } + /** Same as [overlayBounds], but in native resolution. */ + val nativeOverlayBounds = Rect(overlayBounds).apply { scale(1f / scaleFactor) } + /** See [android.view.DisplayInfo.logicalWidth] */ val logicalDisplayWidth = if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index bc44df488d906..493762275ee06 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -636,7 +636,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { mOverlay.getOverlayView().getViewRootImpl().getInputToken()); } - return processedTouch.getTouchData().isWithinSensor(mOverlayParams.getNativeSensorBounds()); + return processedTouch.getTouchData().isWithinBounds(mOverlayParams.getNativeSensorBounds()); } private boolean oldOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt index 79a0acb8bbc19..cf6044f146b02 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt @@ -22,6 +22,11 @@ import com.android.systemui.dagger.SysUISingleton /** Returns whether the touch coordinates are within the sensor's bounding box. */ @SysUISingleton class BoundingBoxOverlapDetector : OverlapDetector { - override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean = - touchData.isWithinSensor(nativeSensorBounds) + override fun isGoodOverlap( + touchData: NormalizedTouchData, + nativeSensorBounds: Rect, + nativeOverlayBounds: Rect, + ): Boolean = + touchData.isWithinBounds(nativeOverlayBounds) && + touchData.isWithinBounds(nativeSensorBounds) } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt index baf8d743938d7..f70e01dc9050d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt @@ -30,8 +30,8 @@ private enum class SensorPixelPosition { TARGET // Pixel within sensor center target } -private val isDebug = true -private val TAG = "EllipseOverlapDetector" +private const val isDebug = false +private const val TAG = "EllipseOverlapDetector" /** * Approximates the touch as an ellipse and determines whether the ellipse has a sufficient overlap @@ -39,12 +39,21 @@ private val TAG = "EllipseOverlapDetector" */ @SysUISingleton class EllipseOverlapDetector(private val params: EllipseOverlapDetectorParams) : OverlapDetector { - override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean { - // First, check if touch is within bounding box, - if (nativeSensorBounds.contains(touchData.x.toInt(), touchData.y.toInt())) { + override fun isGoodOverlap( + touchData: NormalizedTouchData, + nativeSensorBounds: Rect, + nativeOverlayBounds: Rect, + ): Boolean { + // First, check if touch is within bounding box to exit early + if (touchData.isWithinBounds(nativeSensorBounds)) { return true } + // Check touch is within overlay bounds, not worth checking if outside + if (!touchData.isWithinBounds(nativeOverlayBounds)) { + return false + } + var isTargetTouched = false var sensorPixels = 0 var coveredPixels = 0 @@ -77,7 +86,7 @@ class EllipseOverlapDetector(private val params: EllipseOverlapDetectorParams) : val percentage: Float = coveredPixels.toFloat() / sensorPixels if (isDebug) { - Log.v( + Log.d( TAG, "covered: $coveredPixels, sensor: $sensorPixels, " + "percentage: $percentage, isCenterTouched: $isTargetTouched" diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/NormalizedTouchData.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/NormalizedTouchData.kt index 6854b50370ba0..1b4062a4e9bc3 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/NormalizedTouchData.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/NormalizedTouchData.kt @@ -51,16 +51,16 @@ data class NormalizedTouchData( ) { /** - * [nativeSensorBounds] contains the location and dimensions of the sensor area in native - * resolution and natural orientation. + * [nativeBounds] contains the location and dimensions of the area in native resolution and + * natural orientation. * - * Returns whether the coordinates of the given pointer are within the sensor's bounding box. + * Returns whether the coordinates of the given pointer are within the bounding box. */ - fun isWithinSensor(nativeSensorBounds: Rect): Boolean { - return nativeSensorBounds.left <= x && - nativeSensorBounds.right >= x && - nativeSensorBounds.top <= y && - nativeSensorBounds.bottom >= y + fun isWithinBounds(nativeBounds: Rect): Boolean { + return nativeBounds.left <= x && + nativeBounds.right >= x && + nativeBounds.top <= y && + nativeBounds.bottom >= y } @JvmOverloads diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/OverlapDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/OverlapDetector.kt index 0fec8ffbaa0aa..f16347159010b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/OverlapDetector.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/OverlapDetector.kt @@ -20,5 +20,9 @@ import android.graphics.Rect /** Determines whether the touch has a sufficient overlap with the sensor. */ interface OverlapDetector { - fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean + fun isGoodOverlap( + touchData: NormalizedTouchData, + nativeSensorBounds: Rect, + nativeOverlayBounds: Rect + ): Boolean } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt index 6c9390ddad7d8..eeb0f4c7bb134 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt @@ -46,7 +46,13 @@ class SinglePointerTouchProcessor @Inject constructor(val overlapDetector: Overl val touchData = List(event.pointerCount) { event.normalize(it, overlayParams) } val pointersOnSensor = touchData - .filter { overlapDetector.isGoodOverlap(it, overlayParams.nativeSensorBounds) } + .filter { + overlapDetector.isGoodOverlap( + it, + overlayParams.nativeSensorBounds, + overlayParams.nativeOverlayBounds + ) + } .map { it.pointerId } return PreprocessedTouch(touchData, previousPointerOnSensorId, pointersOnSensor) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt index 4f89b69108f43..da55d5a099b74 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt @@ -33,7 +33,7 @@ class BoundingBoxOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() { @Test fun isGoodOverlap() { val touchData = TOUCH_DATA.copy(x = testCase.x.toFloat(), y = testCase.y.toFloat()) - val actual = underTest.isGoodOverlap(touchData, SENSOR) + val actual = underTest.isGoodOverlap(touchData, SENSOR, OVERLAY) assertThat(actual).isEqualTo(testCase.expected) } @@ -50,8 +50,10 @@ class BoundingBoxOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() { validYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY()) ), genNegativeTestCases( - invalidXs = listOf(SENSOR.left - 1, SENSOR.right + 1), - invalidYs = listOf(SENSOR.top - 1, SENSOR.bottom + 1), + invalidXs = + listOf(SENSOR.left - 1, SENSOR.right + 1, OVERLAY.left, OVERLAY.right), + invalidYs = + listOf(SENSOR.top - 1, SENSOR.bottom + 1, OVERLAY.top, OVERLAY.bottom), validXs = listOf(SENSOR.left, SENSOR.right, SENSOR.centerX()), validYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY()) ) @@ -82,6 +84,7 @@ private val TOUCH_DATA = ) private val SENSOR = Rect(100 /* left */, 200 /* top */, 300 /* right */, 500 /* bottom */) +private val OVERLAY = Rect(0 /* left */, 100 /* top */, 400 /* right */, 600 /* bottom */) private fun genTestCases( xs: List, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt index fb3c1854e9966..317141ba42ddd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt @@ -43,7 +43,7 @@ class EllipseOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() { minor = testCase.minor, major = testCase.major ) - val actual = underTest.isGoodOverlap(touchData, SENSOR) + val actual = underTest.isGoodOverlap(touchData, SENSOR, OVERLAY) assertThat(actual).isEqualTo(testCase.expected) } @@ -71,8 +71,10 @@ class EllipseOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() { expected = true ), genNegativeTestCase( - outerXs = listOf(SENSOR.left - 1, SENSOR.right + 1), - outerYs = listOf(SENSOR.top - 1, SENSOR.bottom + 1), + outerXs = + listOf(SENSOR.left - 1, SENSOR.right + 1, OVERLAY.left, OVERLAY.right), + outerYs = + listOf(SENSOR.top - 1, SENSOR.bottom + 1, OVERLAY.top, OVERLAY.bottom), minor = 100f, major = 100f, expected = false @@ -104,6 +106,7 @@ private val TOUCH_DATA = ) private val SENSOR = Rect(100 /* left */, 200 /* top */, 300 /* right */, 400 /* bottom */) +private val OVERLAY = Rect(0 /* left */, 100 /* top */, 400 /* right */, 600 /* bottom */) private fun genPositiveTestCases( innerXs: List, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt index 834d0a69e427e..3e5c43a334742 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt @@ -16,7 +16,7 @@ class NormalizedTouchDataTest(val testCase: TestCase) : SysuiTestCase() { @Test fun isWithinSensor() { val touchData = TOUCH_DATA.copy(x = testCase.x.toFloat(), y = testCase.y.toFloat()) - val actual = touchData.isWithinSensor(SENSOR) + val actual = touchData.isWithinBounds(SENSOR) assertThat(actual).isEqualTo(testCase.expected) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/udfps/FakeOverlapDetector.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/udfps/FakeOverlapDetector.kt index 1bdee3667d04e..e3e7933405a4f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/udfps/FakeOverlapDetector.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/udfps/FakeOverlapDetector.kt @@ -21,7 +21,11 @@ import android.graphics.Rect class FakeOverlapDetector : OverlapDetector { var shouldReturn: Map = mapOf() - override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean { + override fun isGoodOverlap( + touchData: NormalizedTouchData, + nativeSensorBounds: Rect, + nativeOverlayBounds: Rect + ): Boolean { return shouldReturn[touchData.pointerId] ?: error("Unexpected PointerId not declared in TestCase currentPointers") }