Merge "Ignore touches outside of Udfps Overlay bounds" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
aee24a214f
@@ -36,6 +36,9 @@ data class UdfpsOverlayParams(
|
|||||||
/** Same as [sensorBounds], but in native resolution. */
|
/** Same as [sensorBounds], but in native resolution. */
|
||||||
val nativeSensorBounds = Rect(sensorBounds).apply { scale(1f / scaleFactor) }
|
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] */
|
/** See [android.view.DisplayInfo.logicalWidth] */
|
||||||
val logicalDisplayWidth =
|
val logicalDisplayWidth =
|
||||||
if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
|
if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
|
||||||
|
|||||||
@@ -636,7 +636,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
|||||||
mOverlay.getOverlayView().getViewRootImpl().getInputToken());
|
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) {
|
private boolean oldOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ import com.android.systemui.dagger.SysUISingleton
|
|||||||
/** Returns whether the touch coordinates are within the sensor's bounding box. */
|
/** Returns whether the touch coordinates are within the sensor's bounding box. */
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
class BoundingBoxOverlapDetector : OverlapDetector {
|
class BoundingBoxOverlapDetector : OverlapDetector {
|
||||||
override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean =
|
override fun isGoodOverlap(
|
||||||
touchData.isWithinSensor(nativeSensorBounds)
|
touchData: NormalizedTouchData,
|
||||||
|
nativeSensorBounds: Rect,
|
||||||
|
nativeOverlayBounds: Rect,
|
||||||
|
): Boolean =
|
||||||
|
touchData.isWithinBounds(nativeOverlayBounds) &&
|
||||||
|
touchData.isWithinBounds(nativeSensorBounds)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ private enum class SensorPixelPosition {
|
|||||||
TARGET // Pixel within sensor center target
|
TARGET // Pixel within sensor center target
|
||||||
}
|
}
|
||||||
|
|
||||||
private val isDebug = true
|
private const val isDebug = false
|
||||||
private val TAG = "EllipseOverlapDetector"
|
private const val TAG = "EllipseOverlapDetector"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Approximates the touch as an ellipse and determines whether the ellipse has a sufficient overlap
|
* Approximates the touch as an ellipse and determines whether the ellipse has a sufficient overlap
|
||||||
@@ -39,12 +39,21 @@ private val TAG = "EllipseOverlapDetector"
|
|||||||
*/
|
*/
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
class EllipseOverlapDetector(private val params: EllipseOverlapDetectorParams) : OverlapDetector {
|
class EllipseOverlapDetector(private val params: EllipseOverlapDetectorParams) : OverlapDetector {
|
||||||
override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean {
|
override fun isGoodOverlap(
|
||||||
// First, check if touch is within bounding box,
|
touchData: NormalizedTouchData,
|
||||||
if (nativeSensorBounds.contains(touchData.x.toInt(), touchData.y.toInt())) {
|
nativeSensorBounds: Rect,
|
||||||
|
nativeOverlayBounds: Rect,
|
||||||
|
): Boolean {
|
||||||
|
// First, check if touch is within bounding box to exit early
|
||||||
|
if (touchData.isWithinBounds(nativeSensorBounds)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check touch is within overlay bounds, not worth checking if outside
|
||||||
|
if (!touchData.isWithinBounds(nativeOverlayBounds)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var isTargetTouched = false
|
var isTargetTouched = false
|
||||||
var sensorPixels = 0
|
var sensorPixels = 0
|
||||||
var coveredPixels = 0
|
var coveredPixels = 0
|
||||||
@@ -77,7 +86,7 @@ class EllipseOverlapDetector(private val params: EllipseOverlapDetectorParams) :
|
|||||||
|
|
||||||
val percentage: Float = coveredPixels.toFloat() / sensorPixels
|
val percentage: Float = coveredPixels.toFloat() / sensorPixels
|
||||||
if (isDebug) {
|
if (isDebug) {
|
||||||
Log.v(
|
Log.d(
|
||||||
TAG,
|
TAG,
|
||||||
"covered: $coveredPixels, sensor: $sensorPixels, " +
|
"covered: $coveredPixels, sensor: $sensorPixels, " +
|
||||||
"percentage: $percentage, isCenterTouched: $isTargetTouched"
|
"percentage: $percentage, isCenterTouched: $isTargetTouched"
|
||||||
|
|||||||
@@ -51,16 +51,16 @@ data class NormalizedTouchData(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [nativeSensorBounds] contains the location and dimensions of the sensor area in native
|
* [nativeBounds] contains the location and dimensions of the area in native resolution and
|
||||||
* resolution and natural orientation.
|
* 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 {
|
fun isWithinBounds(nativeBounds: Rect): Boolean {
|
||||||
return nativeSensorBounds.left <= x &&
|
return nativeBounds.left <= x &&
|
||||||
nativeSensorBounds.right >= x &&
|
nativeBounds.right >= x &&
|
||||||
nativeSensorBounds.top <= y &&
|
nativeBounds.top <= y &&
|
||||||
nativeSensorBounds.bottom >= y
|
nativeBounds.bottom >= y
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
|
|||||||
@@ -20,5 +20,9 @@ import android.graphics.Rect
|
|||||||
|
|
||||||
/** Determines whether the touch has a sufficient overlap with the sensor. */
|
/** Determines whether the touch has a sufficient overlap with the sensor. */
|
||||||
interface OverlapDetector {
|
interface OverlapDetector {
|
||||||
fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean
|
fun isGoodOverlap(
|
||||||
|
touchData: NormalizedTouchData,
|
||||||
|
nativeSensorBounds: Rect,
|
||||||
|
nativeOverlayBounds: Rect
|
||||||
|
): Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,13 @@ class SinglePointerTouchProcessor @Inject constructor(val overlapDetector: Overl
|
|||||||
val touchData = List(event.pointerCount) { event.normalize(it, overlayParams) }
|
val touchData = List(event.pointerCount) { event.normalize(it, overlayParams) }
|
||||||
val pointersOnSensor =
|
val pointersOnSensor =
|
||||||
touchData
|
touchData
|
||||||
.filter { overlapDetector.isGoodOverlap(it, overlayParams.nativeSensorBounds) }
|
.filter {
|
||||||
|
overlapDetector.isGoodOverlap(
|
||||||
|
it,
|
||||||
|
overlayParams.nativeSensorBounds,
|
||||||
|
overlayParams.nativeOverlayBounds
|
||||||
|
)
|
||||||
|
}
|
||||||
.map { it.pointerId }
|
.map { it.pointerId }
|
||||||
return PreprocessedTouch(touchData, previousPointerOnSensorId, pointersOnSensor)
|
return PreprocessedTouch(touchData, previousPointerOnSensorId, pointersOnSensor)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class BoundingBoxOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun isGoodOverlap() {
|
fun isGoodOverlap() {
|
||||||
val touchData = TOUCH_DATA.copy(x = testCase.x.toFloat(), y = testCase.y.toFloat())
|
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)
|
assertThat(actual).isEqualTo(testCase.expected)
|
||||||
}
|
}
|
||||||
@@ -50,8 +50,10 @@ class BoundingBoxOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() {
|
|||||||
validYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY())
|
validYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY())
|
||||||
),
|
),
|
||||||
genNegativeTestCases(
|
genNegativeTestCases(
|
||||||
invalidXs = listOf(SENSOR.left - 1, SENSOR.right + 1),
|
invalidXs =
|
||||||
invalidYs = listOf(SENSOR.top - 1, SENSOR.bottom + 1),
|
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()),
|
validXs = listOf(SENSOR.left, SENSOR.right, SENSOR.centerX()),
|
||||||
validYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY())
|
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 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(
|
private fun genTestCases(
|
||||||
xs: List<Int>,
|
xs: List<Int>,
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class EllipseOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() {
|
|||||||
minor = testCase.minor,
|
minor = testCase.minor,
|
||||||
major = testCase.major
|
major = testCase.major
|
||||||
)
|
)
|
||||||
val actual = underTest.isGoodOverlap(touchData, SENSOR)
|
val actual = underTest.isGoodOverlap(touchData, SENSOR, OVERLAY)
|
||||||
|
|
||||||
assertThat(actual).isEqualTo(testCase.expected)
|
assertThat(actual).isEqualTo(testCase.expected)
|
||||||
}
|
}
|
||||||
@@ -71,8 +71,10 @@ class EllipseOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() {
|
|||||||
expected = true
|
expected = true
|
||||||
),
|
),
|
||||||
genNegativeTestCase(
|
genNegativeTestCase(
|
||||||
outerXs = listOf(SENSOR.left - 1, SENSOR.right + 1),
|
outerXs =
|
||||||
outerYs = listOf(SENSOR.top - 1, SENSOR.bottom + 1),
|
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,
|
minor = 100f,
|
||||||
major = 100f,
|
major = 100f,
|
||||||
expected = false
|
expected = false
|
||||||
@@ -104,6 +106,7 @@ private val TOUCH_DATA =
|
|||||||
)
|
)
|
||||||
|
|
||||||
private val SENSOR = Rect(100 /* left */, 200 /* top */, 300 /* right */, 400 /* bottom */)
|
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(
|
private fun genPositiveTestCases(
|
||||||
innerXs: List<Int>,
|
innerXs: List<Int>,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class NormalizedTouchDataTest(val testCase: TestCase) : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun isWithinSensor() {
|
fun isWithinSensor() {
|
||||||
val touchData = TOUCH_DATA.copy(x = testCase.x.toFloat(), y = testCase.y.toFloat())
|
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)
|
assertThat(actual).isEqualTo(testCase.expected)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,11 @@ import android.graphics.Rect
|
|||||||
class FakeOverlapDetector : OverlapDetector {
|
class FakeOverlapDetector : OverlapDetector {
|
||||||
var shouldReturn: Map<Int, Boolean> = mapOf()
|
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]
|
return shouldReturn[touchData.pointerId]
|
||||||
?: error("Unexpected PointerId not declared in TestCase currentPointers")
|
?: error("Unexpected PointerId not declared in TestCase currentPointers")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user