Merge "Add multitouch to new touch architecture" into tm-qpr-dev am: fa87b00c96 am: f6a293ad6c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20624533

Change-Id: I4a80e4ccd22d3ef31c42a3ec136e0be34ff5157f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Austin Delgado
2023-01-13 22:46:03 +00:00
committed by Automerger Merge Worker
4 changed files with 283 additions and 123 deletions

View File

@@ -26,28 +26,28 @@ data class NormalizedTouchData(
* Value obtained from [MotionEvent.getPointerId], or [MotionEvent.INVALID_POINTER_ID] if the ID
* is not available.
*/
val pointerId: Int,
val pointerId: Int = MotionEvent.INVALID_POINTER_ID,
/** [MotionEvent.getRawX] mapped to natural orientation and native resolution. */
val x: Float,
val x: Float = 0f,
/** [MotionEvent.getRawY] mapped to natural orientation and native resolution. */
val y: Float,
val y: Float = 0f,
/** [MotionEvent.getTouchMinor] mapped to natural orientation and native resolution. */
val minor: Float,
val minor: Float = 0f,
/** [MotionEvent.getTouchMajor] mapped to natural orientation and native resolution. */
val major: Float,
val major: Float = 0f,
/** [MotionEvent.getOrientation] mapped to natural orientation. */
val orientation: Float,
val orientation: Float = 0f,
/** [MotionEvent.getEventTime]. */
val time: Long,
val time: Long = 0,
/** [MotionEvent.getDownTime]. */
val gestureStart: Long,
val gestureStart: Long = 0,
) {
/**

View File

@@ -43,74 +43,72 @@ class SinglePointerTouchProcessor @Inject constructor(val overlapDetector: Overl
): TouchProcessorResult {
fun preprocess(): PreprocessedTouch {
// TODO(b/253085297): Add multitouch support. pointerIndex can be > 0 for ACTION_MOVE.
val pointerIndex = 0
val touchData = event.normalize(pointerIndex, overlayParams)
val isGoodOverlap =
overlapDetector.isGoodOverlap(touchData, overlayParams.nativeSensorBounds)
return PreprocessedTouch(touchData, previousPointerOnSensorId, isGoodOverlap)
val touchData = List(event.pointerCount) { event.normalize(it, overlayParams) }
val pointersOnSensor =
touchData
.filter { overlapDetector.isGoodOverlap(it, overlayParams.nativeSensorBounds) }
.map { it.pointerId }
return PreprocessedTouch(touchData, previousPointerOnSensorId, pointersOnSensor)
}
return when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> processActionDown(preprocess())
MotionEvent.ACTION_DOWN,
MotionEvent.ACTION_POINTER_DOWN,
MotionEvent.ACTION_MOVE -> processActionMove(preprocess())
MotionEvent.ACTION_UP -> processActionUp(preprocess())
MotionEvent.ACTION_CANCEL ->
processActionCancel(event.normalize(pointerIndex = 0, overlayParams))
MotionEvent.ACTION_UP,
MotionEvent.ACTION_POINTER_UP ->
processActionUp(preprocess(), event.getPointerId(event.actionIndex))
MotionEvent.ACTION_CANCEL -> processActionCancel(NormalizedTouchData())
else ->
Failure("Unsupported MotionEvent." + MotionEvent.actionToString(event.actionMasked))
}
}
}
/**
* [data] contains a list of NormalizedTouchData for pointers in the motionEvent ordered by
* pointerIndex
*
* [previousPointerOnSensorId] the pointerId of the previous pointer on the sensor,
* [MotionEvent.INVALID_POINTER_ID] if none
*
* [pointersOnSensor] contains a list of ids of pointers on the sensor
*/
private data class PreprocessedTouch(
val data: NormalizedTouchData,
val data: List<NormalizedTouchData>,
val previousPointerOnSensorId: Int,
val isGoodOverlap: Boolean,
val pointersOnSensor: List<Int>,
)
private fun processActionDown(touch: PreprocessedTouch): TouchProcessorResult {
return if (touch.isGoodOverlap) {
ProcessedTouch(InteractionEvent.DOWN, pointerOnSensorId = touch.data.pointerId, touch.data)
} else {
val event =
if (touch.data.pointerId == touch.previousPointerOnSensorId) {
InteractionEvent.UP
} else {
InteractionEvent.UNCHANGED
}
ProcessedTouch(event, pointerOnSensorId = INVALID_POINTER_ID, touch.data)
}
}
private fun processActionMove(touch: PreprocessedTouch): TouchProcessorResult {
val hadPointerOnSensor = touch.previousPointerOnSensorId != INVALID_POINTER_ID
val interactionEvent =
when {
touch.isGoodOverlap && !hadPointerOnSensor -> InteractionEvent.DOWN
!touch.isGoodOverlap && hadPointerOnSensor -> InteractionEvent.UP
else -> InteractionEvent.UNCHANGED
}
val pointerOnSensorId =
when (interactionEvent) {
InteractionEvent.UNCHANGED -> touch.previousPointerOnSensorId
InteractionEvent.DOWN -> touch.data.pointerId
else -> INVALID_POINTER_ID
}
return ProcessedTouch(interactionEvent, pointerOnSensorId, touch.data)
val hasPointerOnSensor = touch.pointersOnSensor.isNotEmpty()
val pointerOnSensorId = touch.pointersOnSensor.firstOrNull() ?: INVALID_POINTER_ID
return if (!hadPointerOnSensor && hasPointerOnSensor) {
val data = touch.data.find { it.pointerId == pointerOnSensorId } ?: NormalizedTouchData()
ProcessedTouch(InteractionEvent.DOWN, data.pointerId, data)
} else if (hadPointerOnSensor && !hasPointerOnSensor) {
ProcessedTouch(InteractionEvent.UP, INVALID_POINTER_ID, NormalizedTouchData())
} else {
val data = touch.data.find { it.pointerId == pointerOnSensorId } ?: NormalizedTouchData()
ProcessedTouch(InteractionEvent.UNCHANGED, pointerOnSensorId, data)
}
}
private fun processActionUp(touch: PreprocessedTouch): TouchProcessorResult {
return if (touch.isGoodOverlap) {
ProcessedTouch(InteractionEvent.UP, pointerOnSensorId = INVALID_POINTER_ID, touch.data)
private fun processActionUp(touch: PreprocessedTouch, actionId: Int): TouchProcessorResult {
// Finger lifted and it was the only finger on the sensor
return if (touch.pointersOnSensor.size == 1 && touch.pointersOnSensor.contains(actionId)) {
ProcessedTouch(
InteractionEvent.UP,
pointerOnSensorId = INVALID_POINTER_ID,
NormalizedTouchData()
)
} else {
val event =
if (touch.previousPointerOnSensorId != INVALID_POINTER_ID) {
InteractionEvent.UP
} else {
InteractionEvent.UNCHANGED
}
ProcessedTouch(event, pointerOnSensorId = INVALID_POINTER_ID, touch.data)
// Pick new pointerOnSensor that's not the finger that was lifted
val pointerOnSensorId = touch.pointersOnSensor.find { it != actionId } ?: INVALID_POINTER_ID
val data = touch.data.find { it.pointerId == pointerOnSensorId } ?: NormalizedTouchData()
ProcessedTouch(InteractionEvent.UNCHANGED, data.pointerId, data)
}
}

View File

@@ -39,7 +39,8 @@ class SinglePointerTouchProcessorTest(val testCase: TestCase) : SysuiTestCase()
@Test
fun processTouch() {
overlapDetector.shouldReturn = testCase.isGoodOverlap
overlapDetector.shouldReturn =
testCase.currentPointers.associate { pointer -> pointer.id to pointer.onSensor }
val actual =
underTest.processTouch(
@@ -56,7 +57,7 @@ class SinglePointerTouchProcessorTest(val testCase: TestCase) : SysuiTestCase()
data class TestCase(
val event: MotionEvent,
val isGoodOverlap: Boolean,
val currentPointers: List<TestPointer>,
val previousPointerOnSensorId: Int,
val overlayParams: UdfpsOverlayParams,
val expected: TouchProcessorResult,
@@ -91,28 +92,21 @@ class SinglePointerTouchProcessorTest(val testCase: TestCase) : SysuiTestCase()
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_DOWN,
previousPointerOnSensorId = INVALID_POINTER_ID,
isGoodOverlap = true,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
expectedInteractionEvent = InteractionEvent.DOWN,
expectedPointerOnSensorId = POINTER_ID,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_DOWN,
previousPointerOnSensorId = POINTER_ID,
isGoodOverlap = true,
expectedInteractionEvent = InteractionEvent.DOWN,
expectedPointerOnSensorId = POINTER_ID,
expectedPointerOnSensorId = POINTER_ID_1,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_DOWN,
previousPointerOnSensorId = INVALID_POINTER_ID,
isGoodOverlap = false,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_DOWN,
previousPointerOnSensorId = POINTER_ID,
isGoodOverlap = false,
previousPointerOnSensorId = POINTER_ID_1,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
expectedInteractionEvent = InteractionEvent.UP,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
@@ -120,109 +114,226 @@ class SinglePointerTouchProcessorTest(val testCase: TestCase) : SysuiTestCase()
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_MOVE,
previousPointerOnSensorId = INVALID_POINTER_ID,
isGoodOverlap = true,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
expectedInteractionEvent = InteractionEvent.DOWN,
expectedPointerOnSensorId = POINTER_ID,
expectedPointerOnSensorId = POINTER_ID_1,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_MOVE,
previousPointerOnSensorId = POINTER_ID,
isGoodOverlap = true,
previousPointerOnSensorId = POINTER_ID_1,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = POINTER_ID,
expectedPointerOnSensorId = POINTER_ID_1,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_MOVE,
previousPointerOnSensorId = INVALID_POINTER_ID,
isGoodOverlap = false,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_MOVE,
previousPointerOnSensorId = POINTER_ID,
isGoodOverlap = false,
previousPointerOnSensorId = POINTER_ID_1,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
expectedInteractionEvent = InteractionEvent.UP,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_MOVE,
previousPointerOnSensorId = INVALID_POINTER_ID,
currentPointers =
listOf(
TestPointer(id = POINTER_ID_1, onSensor = false),
TestPointer(id = POINTER_ID_2, onSensor = true)
),
expectedInteractionEvent = InteractionEvent.DOWN,
expectedPointerOnSensorId = POINTER_ID_2,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_MOVE,
previousPointerOnSensorId = POINTER_ID_1,
currentPointers =
listOf(
TestPointer(id = POINTER_ID_1, onSensor = false),
TestPointer(id = POINTER_ID_2, onSensor = true)
),
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = POINTER_ID_2,
),
// MotionEvent.ACTION_UP
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_UP,
previousPointerOnSensorId = INVALID_POINTER_ID,
isGoodOverlap = true,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
expectedInteractionEvent = InteractionEvent.UP,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_UP,
previousPointerOnSensorId = POINTER_ID,
isGoodOverlap = true,
previousPointerOnSensorId = POINTER_ID_1,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
expectedInteractionEvent = InteractionEvent.UP,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_UP,
previousPointerOnSensorId = INVALID_POINTER_ID,
isGoodOverlap = false,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_UP,
previousPointerOnSensorId = POINTER_ID,
isGoodOverlap = false,
expectedInteractionEvent = InteractionEvent.UP,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
// MotionEvent.ACTION_CANCEL
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_CANCEL,
previousPointerOnSensorId = INVALID_POINTER_ID,
isGoodOverlap = true,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
expectedInteractionEvent = InteractionEvent.CANCEL,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_CANCEL,
previousPointerOnSensorId = POINTER_ID,
isGoodOverlap = true,
previousPointerOnSensorId = POINTER_ID_1,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
expectedInteractionEvent = InteractionEvent.CANCEL,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_CANCEL,
previousPointerOnSensorId = INVALID_POINTER_ID,
isGoodOverlap = false,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
expectedInteractionEvent = InteractionEvent.CANCEL,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_CANCEL,
previousPointerOnSensorId = POINTER_ID,
isGoodOverlap = false,
previousPointerOnSensorId = POINTER_ID_1,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
expectedInteractionEvent = InteractionEvent.CANCEL,
expectedPointerOnSensorId = INVALID_POINTER_ID,
),
// MotionEvent.ACTION_POINTER_DOWN
genPositiveTestCases(
motionEventAction =
MotionEvent.ACTION_POINTER_DOWN +
(1 shl MotionEvent.ACTION_POINTER_INDEX_SHIFT),
previousPointerOnSensorId = INVALID_POINTER_ID,
currentPointers =
listOf(
TestPointer(id = POINTER_ID_1, onSensor = true),
TestPointer(id = POINTER_ID_2, onSensor = false)
),
expectedInteractionEvent = InteractionEvent.DOWN,
expectedPointerOnSensorId = POINTER_ID_1,
),
genPositiveTestCases(
motionEventAction =
MotionEvent.ACTION_POINTER_DOWN +
(1 shl MotionEvent.ACTION_POINTER_INDEX_SHIFT),
previousPointerOnSensorId = INVALID_POINTER_ID,
currentPointers =
listOf(
TestPointer(id = POINTER_ID_1, onSensor = false),
TestPointer(id = POINTER_ID_2, onSensor = true)
),
expectedInteractionEvent = InteractionEvent.DOWN,
expectedPointerOnSensorId = POINTER_ID_2
),
genPositiveTestCases(
motionEventAction =
MotionEvent.ACTION_POINTER_DOWN +
(1 shl MotionEvent.ACTION_POINTER_INDEX_SHIFT),
previousPointerOnSensorId = POINTER_ID_1,
currentPointers =
listOf(
TestPointer(id = POINTER_ID_1, onSensor = true),
TestPointer(id = POINTER_ID_2, onSensor = false)
),
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = POINTER_ID_1,
),
// MotionEvent.ACTION_POINTER_UP
genPositiveTestCases(
motionEventAction =
MotionEvent.ACTION_POINTER_UP +
(1 shl MotionEvent.ACTION_POINTER_INDEX_SHIFT),
previousPointerOnSensorId = INVALID_POINTER_ID,
currentPointers =
listOf(
TestPointer(id = POINTER_ID_1, onSensor = false),
TestPointer(id = POINTER_ID_2, onSensor = false)
),
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = INVALID_POINTER_ID
),
genPositiveTestCases(
motionEventAction =
MotionEvent.ACTION_POINTER_UP +
(1 shl MotionEvent.ACTION_POINTER_INDEX_SHIFT),
previousPointerOnSensorId = POINTER_ID_2,
currentPointers =
listOf(
TestPointer(id = POINTER_ID_1, onSensor = false),
TestPointer(id = POINTER_ID_2, onSensor = true)
),
expectedInteractionEvent = InteractionEvent.UP,
expectedPointerOnSensorId = INVALID_POINTER_ID
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_POINTER_UP,
previousPointerOnSensorId = POINTER_ID_1,
currentPointers =
listOf(
TestPointer(id = POINTER_ID_1, onSensor = true),
TestPointer(id = POINTER_ID_2, onSensor = false)
),
expectedInteractionEvent = InteractionEvent.UP,
expectedPointerOnSensorId = INVALID_POINTER_ID
),
genPositiveTestCases(
motionEventAction =
MotionEvent.ACTION_POINTER_UP +
(1 shl MotionEvent.ACTION_POINTER_INDEX_SHIFT),
previousPointerOnSensorId = POINTER_ID_1,
currentPointers =
listOf(
TestPointer(id = POINTER_ID_1, onSensor = true),
TestPointer(id = POINTER_ID_2, onSensor = false)
),
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = POINTER_ID_1
),
genPositiveTestCases(
motionEventAction = MotionEvent.ACTION_POINTER_UP,
previousPointerOnSensorId = POINTER_ID_2,
currentPointers =
listOf(
TestPointer(id = POINTER_ID_1, onSensor = false),
TestPointer(id = POINTER_ID_2, onSensor = true)
),
expectedInteractionEvent = InteractionEvent.UNCHANGED,
expectedPointerOnSensorId = POINTER_ID_2
)
)
.flatten() +
listOf(
// Unsupported MotionEvent actions.
genTestCasesForUnsupportedAction(MotionEvent.ACTION_POINTER_DOWN),
genTestCasesForUnsupportedAction(MotionEvent.ACTION_POINTER_UP),
genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_ENTER),
genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_MOVE),
genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_EXIT),
genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_EXIT)
)
.flatten()
}
}
data class TestPointer(val id: Int, val onSensor: Boolean)
/* Display dimensions in native resolution and natural orientation. */
private const val ROTATION_0_NATIVE_DISPLAY_WIDTH = 400
private const val ROTATION_0_NATIVE_DISPLAY_HEIGHT = 600
/* Placeholder touch parameters. */
private const val POINTER_ID = 42
private const val POINTER_ID_1 = 42
private const val POINTER_ID_2 = 43
private const val NATIVE_MINOR = 2.71828f
private const val NATIVE_MAJOR = 3.14f
private const val ORIENTATION = 1.2345f
@@ -325,7 +436,7 @@ private val ROTATION_270_INPUTS =
private val MOTION_EVENT =
obtainMotionEvent(
action = 0,
pointerId = POINTER_ID,
pointerId = POINTER_ID_1,
x = 0f,
y = 0f,
minor = 0f,
@@ -338,7 +449,7 @@ private val MOTION_EVENT =
/* Template [NormalizedTouchData]. */
private val NORMALIZED_TOUCH_DATA =
NormalizedTouchData(
POINTER_ID,
POINTER_ID_1,
x = 0f,
y = 0f,
NATIVE_MINOR,
@@ -384,7 +495,7 @@ private data class OrientationBasedInputs(
private fun genPositiveTestCases(
motionEventAction: Int,
previousPointerOnSensorId: Int,
isGoodOverlap: Boolean,
currentPointers: List<TestPointer>,
expectedInteractionEvent: InteractionEvent,
expectedPointerOnSensorId: Int
): List<SinglePointerTouchProcessorTest.TestCase> {
@@ -399,22 +510,47 @@ private fun genPositiveTestCases(
return scaleFactors.flatMap { scaleFactor ->
orientations.map { orientation ->
val overlayParams = orientation.toOverlayParams(scaleFactor)
val nativeX = orientation.getNativeX(isGoodOverlap)
val nativeY = orientation.getNativeY(isGoodOverlap)
val pointerProperties =
currentPointers
.map { pointer ->
val pp = MotionEvent.PointerProperties()
pp.id = pointer.id
pp
}
.toList()
val pointerCoords =
currentPointers
.map { pointer ->
val pc = MotionEvent.PointerCoords()
pc.x = orientation.getNativeX(pointer.onSensor) * scaleFactor
pc.y = orientation.getNativeY(pointer.onSensor) * scaleFactor
pc.touchMinor = NATIVE_MINOR * scaleFactor
pc.touchMajor = NATIVE_MAJOR * scaleFactor
pc.orientation = orientation.nativeOrientation
pc
}
.toList()
val event =
MOTION_EVENT.copy(
action = motionEventAction,
x = nativeX * scaleFactor,
y = nativeY * scaleFactor,
minor = NATIVE_MINOR * scaleFactor,
major = NATIVE_MAJOR * scaleFactor,
orientation = orientation.nativeOrientation
pointerProperties = pointerProperties,
pointerCoords = pointerCoords
)
val expectedTouchData =
NORMALIZED_TOUCH_DATA.copy(
x = ROTATION_0_INPUTS.getNativeX(isGoodOverlap),
y = ROTATION_0_INPUTS.getNativeY(isGoodOverlap),
)
if (expectedPointerOnSensorId != INVALID_POINTER_ID) {
NORMALIZED_TOUCH_DATA.copy(
pointerId = expectedPointerOnSensorId,
x = ROTATION_0_INPUTS.getNativeX(isWithinSensor = true),
y = ROTATION_0_INPUTS.getNativeY(isWithinSensor = true)
)
} else {
NormalizedTouchData()
}
val expected =
TouchProcessorResult.ProcessedTouch(
event = expectedInteractionEvent,
@@ -423,7 +559,7 @@ private fun genPositiveTestCases(
)
SinglePointerTouchProcessorTest.TestCase(
event = event,
isGoodOverlap = isGoodOverlap,
currentPointers = currentPointers,
previousPointerOnSensorId = previousPointerOnSensorId,
overlayParams = overlayParams,
expected = expected,
@@ -436,7 +572,7 @@ private fun genTestCasesForUnsupportedAction(
motionEventAction: Int
): List<SinglePointerTouchProcessorTest.TestCase> {
val isGoodOverlap = true
val previousPointerOnSensorIds = listOf(INVALID_POINTER_ID, POINTER_ID)
val previousPointerOnSensorIds = listOf(INVALID_POINTER_ID, POINTER_ID_1)
return previousPointerOnSensorIds.map { previousPointerOnSensorId ->
val overlayParams = ROTATION_0_INPUTS.toOverlayParams(scaleFactor = 1f)
val nativeX = ROTATION_0_INPUTS.getNativeX(isGoodOverlap)
@@ -451,7 +587,7 @@ private fun genTestCasesForUnsupportedAction(
)
SinglePointerTouchProcessorTest.TestCase(
event = event,
isGoodOverlap = isGoodOverlap,
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = isGoodOverlap)),
previousPointerOnSensorId = previousPointerOnSensorId,
overlayParams = overlayParams,
expected = TouchProcessorResult.Failure(),
@@ -478,13 +614,23 @@ private fun obtainMotionEvent(
pc.touchMinor = minor
pc.touchMajor = major
pc.orientation = orientation
return obtainMotionEvent(action, arrayOf(pp), arrayOf(pc), time, gestureStart)
}
private fun obtainMotionEvent(
action: Int,
pointerProperties: Array<MotionEvent.PointerProperties>,
pointerCoords: Array<MotionEvent.PointerCoords>,
time: Long,
gestureStart: Long,
): MotionEvent {
return MotionEvent.obtain(
gestureStart /* downTime */,
time /* eventTime */,
action /* action */,
1 /* pointerCount */,
arrayOf(pp) /* pointerProperties */,
arrayOf(pc) /* pointerCoords */,
pointerCoords.size /* pointerCount */,
pointerProperties /* pointerProperties */,
pointerCoords /* pointerCoords */,
0 /* metaState */,
0 /* buttonState */,
1f /* xPrecision */,
@@ -508,4 +654,19 @@ private fun MotionEvent.copy(
gestureStart: Long = this.downTime,
) = obtainMotionEvent(action, pointerId, x, y, minor, major, orientation, time, gestureStart)
private fun MotionEvent.copy(
action: Int = this.action,
pointerProperties: List<MotionEvent.PointerProperties>,
pointerCoords: List<MotionEvent.PointerCoords>,
time: Long = this.eventTime,
gestureStart: Long = this.downTime
) =
obtainMotionEvent(
action,
pointerProperties.toTypedArray(),
pointerCoords.toTypedArray(),
time,
gestureStart
)
private fun Rect.scaled(scaleFactor: Float) = Rect(this).apply { scale(scaleFactor) }

View File

@@ -19,9 +19,10 @@ package com.android.systemui.biometrics.udfps
import android.graphics.Rect
class FakeOverlapDetector : OverlapDetector {
var shouldReturn: Boolean = false
var shouldReturn: Map<Int, Boolean> = mapOf()
override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean {
return shouldReturn
return shouldReturn[touchData.pointerId]
?: error("Unexpected PointerId not declared in TestCase currentPointers")
}
}