Merge "Ignore touches outside of Udfps Overlay bounds" into udc-dev

This commit is contained in:
Austin Delgado
2023-05-11 16:29:04 +00:00
committed by Android (Google) Code Review
11 changed files with 64 additions and 27 deletions

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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)
}

View File

@@ -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"

View File

@@ -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

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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<Int>,

View File

@@ -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<Int>,

View File

@@ -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)
}

View File

@@ -21,7 +21,11 @@ import android.graphics.Rect
class FakeOverlapDetector : OverlapDetector {
var shouldReturn: Map<Int, Boolean> = 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")
}