Merge "Add multitouch to new touch architecture" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
fa87b00c96
@@ -26,28 +26,28 @@ data class NormalizedTouchData(
|
|||||||
* Value obtained from [MotionEvent.getPointerId], or [MotionEvent.INVALID_POINTER_ID] if the ID
|
* Value obtained from [MotionEvent.getPointerId], or [MotionEvent.INVALID_POINTER_ID] if the ID
|
||||||
* is not available.
|
* is not available.
|
||||||
*/
|
*/
|
||||||
val pointerId: Int,
|
val pointerId: Int = MotionEvent.INVALID_POINTER_ID,
|
||||||
|
|
||||||
/** [MotionEvent.getRawX] mapped to natural orientation and native resolution. */
|
/** [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. */
|
/** [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. */
|
/** [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. */
|
/** [MotionEvent.getTouchMajor] mapped to natural orientation and native resolution. */
|
||||||
val major: Float,
|
val major: Float = 0f,
|
||||||
|
|
||||||
/** [MotionEvent.getOrientation] mapped to natural orientation. */
|
/** [MotionEvent.getOrientation] mapped to natural orientation. */
|
||||||
val orientation: Float,
|
val orientation: Float = 0f,
|
||||||
|
|
||||||
/** [MotionEvent.getEventTime]. */
|
/** [MotionEvent.getEventTime]. */
|
||||||
val time: Long,
|
val time: Long = 0,
|
||||||
|
|
||||||
/** [MotionEvent.getDownTime]. */
|
/** [MotionEvent.getDownTime]. */
|
||||||
val gestureStart: Long,
|
val gestureStart: Long = 0,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -43,74 +43,72 @@ class SinglePointerTouchProcessor @Inject constructor(val overlapDetector: Overl
|
|||||||
): TouchProcessorResult {
|
): TouchProcessorResult {
|
||||||
|
|
||||||
fun preprocess(): PreprocessedTouch {
|
fun preprocess(): PreprocessedTouch {
|
||||||
// TODO(b/253085297): Add multitouch support. pointerIndex can be > 0 for ACTION_MOVE.
|
val touchData = List(event.pointerCount) { event.normalize(it, overlayParams) }
|
||||||
val pointerIndex = 0
|
val pointersOnSensor =
|
||||||
val touchData = event.normalize(pointerIndex, overlayParams)
|
touchData
|
||||||
val isGoodOverlap =
|
.filter { overlapDetector.isGoodOverlap(it, overlayParams.nativeSensorBounds) }
|
||||||
overlapDetector.isGoodOverlap(touchData, overlayParams.nativeSensorBounds)
|
.map { it.pointerId }
|
||||||
return PreprocessedTouch(touchData, previousPointerOnSensorId, isGoodOverlap)
|
return PreprocessedTouch(touchData, previousPointerOnSensorId, pointersOnSensor)
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (event.actionMasked) {
|
return when (event.actionMasked) {
|
||||||
MotionEvent.ACTION_DOWN -> processActionDown(preprocess())
|
MotionEvent.ACTION_DOWN,
|
||||||
|
MotionEvent.ACTION_POINTER_DOWN,
|
||||||
MotionEvent.ACTION_MOVE -> processActionMove(preprocess())
|
MotionEvent.ACTION_MOVE -> processActionMove(preprocess())
|
||||||
MotionEvent.ACTION_UP -> processActionUp(preprocess())
|
MotionEvent.ACTION_UP,
|
||||||
MotionEvent.ACTION_CANCEL ->
|
MotionEvent.ACTION_POINTER_UP ->
|
||||||
processActionCancel(event.normalize(pointerIndex = 0, overlayParams))
|
processActionUp(preprocess(), event.getPointerId(event.actionIndex))
|
||||||
|
MotionEvent.ACTION_CANCEL -> processActionCancel(NormalizedTouchData())
|
||||||
else ->
|
else ->
|
||||||
Failure("Unsupported MotionEvent." + MotionEvent.actionToString(event.actionMasked))
|
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(
|
private data class PreprocessedTouch(
|
||||||
val data: NormalizedTouchData,
|
val data: List<NormalizedTouchData>,
|
||||||
val previousPointerOnSensorId: Int,
|
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 {
|
private fun processActionMove(touch: PreprocessedTouch): TouchProcessorResult {
|
||||||
val hadPointerOnSensor = touch.previousPointerOnSensorId != INVALID_POINTER_ID
|
val hadPointerOnSensor = touch.previousPointerOnSensorId != INVALID_POINTER_ID
|
||||||
val interactionEvent =
|
val hasPointerOnSensor = touch.pointersOnSensor.isNotEmpty()
|
||||||
when {
|
val pointerOnSensorId = touch.pointersOnSensor.firstOrNull() ?: INVALID_POINTER_ID
|
||||||
touch.isGoodOverlap && !hadPointerOnSensor -> InteractionEvent.DOWN
|
|
||||||
!touch.isGoodOverlap && hadPointerOnSensor -> InteractionEvent.UP
|
return if (!hadPointerOnSensor && hasPointerOnSensor) {
|
||||||
else -> InteractionEvent.UNCHANGED
|
val data = touch.data.find { it.pointerId == pointerOnSensorId } ?: NormalizedTouchData()
|
||||||
}
|
ProcessedTouch(InteractionEvent.DOWN, data.pointerId, data)
|
||||||
val pointerOnSensorId =
|
} else if (hadPointerOnSensor && !hasPointerOnSensor) {
|
||||||
when (interactionEvent) {
|
ProcessedTouch(InteractionEvent.UP, INVALID_POINTER_ID, NormalizedTouchData())
|
||||||
InteractionEvent.UNCHANGED -> touch.previousPointerOnSensorId
|
} else {
|
||||||
InteractionEvent.DOWN -> touch.data.pointerId
|
val data = touch.data.find { it.pointerId == pointerOnSensorId } ?: NormalizedTouchData()
|
||||||
else -> INVALID_POINTER_ID
|
ProcessedTouch(InteractionEvent.UNCHANGED, pointerOnSensorId, data)
|
||||||
}
|
}
|
||||||
return ProcessedTouch(interactionEvent, pointerOnSensorId, touch.data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processActionUp(touch: PreprocessedTouch): TouchProcessorResult {
|
private fun processActionUp(touch: PreprocessedTouch, actionId: Int): TouchProcessorResult {
|
||||||
return if (touch.isGoodOverlap) {
|
// Finger lifted and it was the only finger on the sensor
|
||||||
ProcessedTouch(InteractionEvent.UP, pointerOnSensorId = INVALID_POINTER_ID, touch.data)
|
return if (touch.pointersOnSensor.size == 1 && touch.pointersOnSensor.contains(actionId)) {
|
||||||
|
ProcessedTouch(
|
||||||
|
InteractionEvent.UP,
|
||||||
|
pointerOnSensorId = INVALID_POINTER_ID,
|
||||||
|
NormalizedTouchData()
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
val event =
|
// Pick new pointerOnSensor that's not the finger that was lifted
|
||||||
if (touch.previousPointerOnSensorId != INVALID_POINTER_ID) {
|
val pointerOnSensorId = touch.pointersOnSensor.find { it != actionId } ?: INVALID_POINTER_ID
|
||||||
InteractionEvent.UP
|
val data = touch.data.find { it.pointerId == pointerOnSensorId } ?: NormalizedTouchData()
|
||||||
} else {
|
ProcessedTouch(InteractionEvent.UNCHANGED, data.pointerId, data)
|
||||||
InteractionEvent.UNCHANGED
|
|
||||||
}
|
|
||||||
ProcessedTouch(event, pointerOnSensorId = INVALID_POINTER_ID, touch.data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ class SinglePointerTouchProcessorTest(val testCase: TestCase) : SysuiTestCase()
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun processTouch() {
|
fun processTouch() {
|
||||||
overlapDetector.shouldReturn = testCase.isGoodOverlap
|
overlapDetector.shouldReturn =
|
||||||
|
testCase.currentPointers.associate { pointer -> pointer.id to pointer.onSensor }
|
||||||
|
|
||||||
val actual =
|
val actual =
|
||||||
underTest.processTouch(
|
underTest.processTouch(
|
||||||
@@ -56,7 +57,7 @@ class SinglePointerTouchProcessorTest(val testCase: TestCase) : SysuiTestCase()
|
|||||||
|
|
||||||
data class TestCase(
|
data class TestCase(
|
||||||
val event: MotionEvent,
|
val event: MotionEvent,
|
||||||
val isGoodOverlap: Boolean,
|
val currentPointers: List<TestPointer>,
|
||||||
val previousPointerOnSensorId: Int,
|
val previousPointerOnSensorId: Int,
|
||||||
val overlayParams: UdfpsOverlayParams,
|
val overlayParams: UdfpsOverlayParams,
|
||||||
val expected: TouchProcessorResult,
|
val expected: TouchProcessorResult,
|
||||||
@@ -91,28 +92,21 @@ class SinglePointerTouchProcessorTest(val testCase: TestCase) : SysuiTestCase()
|
|||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_DOWN,
|
motionEventAction = MotionEvent.ACTION_DOWN,
|
||||||
previousPointerOnSensorId = INVALID_POINTER_ID,
|
previousPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
isGoodOverlap = true,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
|
||||||
expectedInteractionEvent = InteractionEvent.DOWN,
|
expectedInteractionEvent = InteractionEvent.DOWN,
|
||||||
expectedPointerOnSensorId = POINTER_ID,
|
expectedPointerOnSensorId = POINTER_ID_1,
|
||||||
),
|
|
||||||
genPositiveTestCases(
|
|
||||||
motionEventAction = MotionEvent.ACTION_DOWN,
|
|
||||||
previousPointerOnSensorId = POINTER_ID,
|
|
||||||
isGoodOverlap = true,
|
|
||||||
expectedInteractionEvent = InteractionEvent.DOWN,
|
|
||||||
expectedPointerOnSensorId = POINTER_ID,
|
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_DOWN,
|
motionEventAction = MotionEvent.ACTION_DOWN,
|
||||||
previousPointerOnSensorId = INVALID_POINTER_ID,
|
previousPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
isGoodOverlap = false,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
|
||||||
expectedInteractionEvent = InteractionEvent.UNCHANGED,
|
expectedInteractionEvent = InteractionEvent.UNCHANGED,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_DOWN,
|
motionEventAction = MotionEvent.ACTION_DOWN,
|
||||||
previousPointerOnSensorId = POINTER_ID,
|
previousPointerOnSensorId = POINTER_ID_1,
|
||||||
isGoodOverlap = false,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
|
||||||
expectedInteractionEvent = InteractionEvent.UP,
|
expectedInteractionEvent = InteractionEvent.UP,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
),
|
),
|
||||||
@@ -120,109 +114,226 @@ class SinglePointerTouchProcessorTest(val testCase: TestCase) : SysuiTestCase()
|
|||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_MOVE,
|
motionEventAction = MotionEvent.ACTION_MOVE,
|
||||||
previousPointerOnSensorId = INVALID_POINTER_ID,
|
previousPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
isGoodOverlap = true,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
|
||||||
expectedInteractionEvent = InteractionEvent.DOWN,
|
expectedInteractionEvent = InteractionEvent.DOWN,
|
||||||
expectedPointerOnSensorId = POINTER_ID,
|
expectedPointerOnSensorId = POINTER_ID_1,
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_MOVE,
|
motionEventAction = MotionEvent.ACTION_MOVE,
|
||||||
previousPointerOnSensorId = POINTER_ID,
|
previousPointerOnSensorId = POINTER_ID_1,
|
||||||
isGoodOverlap = true,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
|
||||||
expectedInteractionEvent = InteractionEvent.UNCHANGED,
|
expectedInteractionEvent = InteractionEvent.UNCHANGED,
|
||||||
expectedPointerOnSensorId = POINTER_ID,
|
expectedPointerOnSensorId = POINTER_ID_1,
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_MOVE,
|
motionEventAction = MotionEvent.ACTION_MOVE,
|
||||||
previousPointerOnSensorId = INVALID_POINTER_ID,
|
previousPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
isGoodOverlap = false,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
|
||||||
expectedInteractionEvent = InteractionEvent.UNCHANGED,
|
expectedInteractionEvent = InteractionEvent.UNCHANGED,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_MOVE,
|
motionEventAction = MotionEvent.ACTION_MOVE,
|
||||||
previousPointerOnSensorId = POINTER_ID,
|
previousPointerOnSensorId = POINTER_ID_1,
|
||||||
isGoodOverlap = false,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
|
||||||
expectedInteractionEvent = InteractionEvent.UP,
|
expectedInteractionEvent = InteractionEvent.UP,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
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
|
// MotionEvent.ACTION_UP
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_UP,
|
motionEventAction = MotionEvent.ACTION_UP,
|
||||||
previousPointerOnSensorId = INVALID_POINTER_ID,
|
previousPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
isGoodOverlap = true,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
|
||||||
expectedInteractionEvent = InteractionEvent.UP,
|
expectedInteractionEvent = InteractionEvent.UP,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_UP,
|
motionEventAction = MotionEvent.ACTION_UP,
|
||||||
previousPointerOnSensorId = POINTER_ID,
|
previousPointerOnSensorId = POINTER_ID_1,
|
||||||
isGoodOverlap = true,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
|
||||||
expectedInteractionEvent = InteractionEvent.UP,
|
expectedInteractionEvent = InteractionEvent.UP,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_UP,
|
motionEventAction = MotionEvent.ACTION_UP,
|
||||||
previousPointerOnSensorId = INVALID_POINTER_ID,
|
previousPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
isGoodOverlap = false,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
|
||||||
expectedInteractionEvent = InteractionEvent.UNCHANGED,
|
expectedInteractionEvent = InteractionEvent.UNCHANGED,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
|
||||||
motionEventAction = MotionEvent.ACTION_UP,
|
|
||||||
previousPointerOnSensorId = POINTER_ID,
|
|
||||||
isGoodOverlap = false,
|
|
||||||
expectedInteractionEvent = InteractionEvent.UP,
|
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
|
||||||
),
|
|
||||||
// MotionEvent.ACTION_CANCEL
|
// MotionEvent.ACTION_CANCEL
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_CANCEL,
|
motionEventAction = MotionEvent.ACTION_CANCEL,
|
||||||
previousPointerOnSensorId = INVALID_POINTER_ID,
|
previousPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
isGoodOverlap = true,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
|
||||||
expectedInteractionEvent = InteractionEvent.CANCEL,
|
expectedInteractionEvent = InteractionEvent.CANCEL,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_CANCEL,
|
motionEventAction = MotionEvent.ACTION_CANCEL,
|
||||||
previousPointerOnSensorId = POINTER_ID,
|
previousPointerOnSensorId = POINTER_ID_1,
|
||||||
isGoodOverlap = true,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = true)),
|
||||||
expectedInteractionEvent = InteractionEvent.CANCEL,
|
expectedInteractionEvent = InteractionEvent.CANCEL,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_CANCEL,
|
motionEventAction = MotionEvent.ACTION_CANCEL,
|
||||||
previousPointerOnSensorId = INVALID_POINTER_ID,
|
previousPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
isGoodOverlap = false,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
|
||||||
expectedInteractionEvent = InteractionEvent.CANCEL,
|
expectedInteractionEvent = InteractionEvent.CANCEL,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
||||||
),
|
),
|
||||||
genPositiveTestCases(
|
genPositiveTestCases(
|
||||||
motionEventAction = MotionEvent.ACTION_CANCEL,
|
motionEventAction = MotionEvent.ACTION_CANCEL,
|
||||||
previousPointerOnSensorId = POINTER_ID,
|
previousPointerOnSensorId = POINTER_ID_1,
|
||||||
isGoodOverlap = false,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = false)),
|
||||||
expectedInteractionEvent = InteractionEvent.CANCEL,
|
expectedInteractionEvent = InteractionEvent.CANCEL,
|
||||||
expectedPointerOnSensorId = INVALID_POINTER_ID,
|
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() +
|
.flatten() +
|
||||||
listOf(
|
listOf(
|
||||||
// Unsupported MotionEvent actions.
|
|
||||||
genTestCasesForUnsupportedAction(MotionEvent.ACTION_POINTER_DOWN),
|
|
||||||
genTestCasesForUnsupportedAction(MotionEvent.ACTION_POINTER_UP),
|
|
||||||
genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_ENTER),
|
genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_ENTER),
|
||||||
genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_MOVE),
|
genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_MOVE),
|
||||||
genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_EXIT),
|
genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_EXIT)
|
||||||
)
|
)
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class TestPointer(val id: Int, val onSensor: Boolean)
|
||||||
|
|
||||||
/* Display dimensions in native resolution and natural orientation. */
|
/* Display dimensions in native resolution and natural orientation. */
|
||||||
private const val ROTATION_0_NATIVE_DISPLAY_WIDTH = 400
|
private const val ROTATION_0_NATIVE_DISPLAY_WIDTH = 400
|
||||||
private const val ROTATION_0_NATIVE_DISPLAY_HEIGHT = 600
|
private const val ROTATION_0_NATIVE_DISPLAY_HEIGHT = 600
|
||||||
|
|
||||||
/* Placeholder touch parameters. */
|
/* 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_MINOR = 2.71828f
|
||||||
private const val NATIVE_MAJOR = 3.14f
|
private const val NATIVE_MAJOR = 3.14f
|
||||||
private const val ORIENTATION = 1.2345f
|
private const val ORIENTATION = 1.2345f
|
||||||
@@ -325,7 +436,7 @@ private val ROTATION_270_INPUTS =
|
|||||||
private val MOTION_EVENT =
|
private val MOTION_EVENT =
|
||||||
obtainMotionEvent(
|
obtainMotionEvent(
|
||||||
action = 0,
|
action = 0,
|
||||||
pointerId = POINTER_ID,
|
pointerId = POINTER_ID_1,
|
||||||
x = 0f,
|
x = 0f,
|
||||||
y = 0f,
|
y = 0f,
|
||||||
minor = 0f,
|
minor = 0f,
|
||||||
@@ -338,7 +449,7 @@ private val MOTION_EVENT =
|
|||||||
/* Template [NormalizedTouchData]. */
|
/* Template [NormalizedTouchData]. */
|
||||||
private val NORMALIZED_TOUCH_DATA =
|
private val NORMALIZED_TOUCH_DATA =
|
||||||
NormalizedTouchData(
|
NormalizedTouchData(
|
||||||
POINTER_ID,
|
POINTER_ID_1,
|
||||||
x = 0f,
|
x = 0f,
|
||||||
y = 0f,
|
y = 0f,
|
||||||
NATIVE_MINOR,
|
NATIVE_MINOR,
|
||||||
@@ -384,7 +495,7 @@ private data class OrientationBasedInputs(
|
|||||||
private fun genPositiveTestCases(
|
private fun genPositiveTestCases(
|
||||||
motionEventAction: Int,
|
motionEventAction: Int,
|
||||||
previousPointerOnSensorId: Int,
|
previousPointerOnSensorId: Int,
|
||||||
isGoodOverlap: Boolean,
|
currentPointers: List<TestPointer>,
|
||||||
expectedInteractionEvent: InteractionEvent,
|
expectedInteractionEvent: InteractionEvent,
|
||||||
expectedPointerOnSensorId: Int
|
expectedPointerOnSensorId: Int
|
||||||
): List<SinglePointerTouchProcessorTest.TestCase> {
|
): List<SinglePointerTouchProcessorTest.TestCase> {
|
||||||
@@ -399,22 +510,47 @@ private fun genPositiveTestCases(
|
|||||||
return scaleFactors.flatMap { scaleFactor ->
|
return scaleFactors.flatMap { scaleFactor ->
|
||||||
orientations.map { orientation ->
|
orientations.map { orientation ->
|
||||||
val overlayParams = orientation.toOverlayParams(scaleFactor)
|
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 =
|
val event =
|
||||||
MOTION_EVENT.copy(
|
MOTION_EVENT.copy(
|
||||||
action = motionEventAction,
|
action = motionEventAction,
|
||||||
x = nativeX * scaleFactor,
|
pointerProperties = pointerProperties,
|
||||||
y = nativeY * scaleFactor,
|
pointerCoords = pointerCoords
|
||||||
minor = NATIVE_MINOR * scaleFactor,
|
|
||||||
major = NATIVE_MAJOR * scaleFactor,
|
|
||||||
orientation = orientation.nativeOrientation
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val expectedTouchData =
|
val expectedTouchData =
|
||||||
NORMALIZED_TOUCH_DATA.copy(
|
if (expectedPointerOnSensorId != INVALID_POINTER_ID) {
|
||||||
x = ROTATION_0_INPUTS.getNativeX(isGoodOverlap),
|
NORMALIZED_TOUCH_DATA.copy(
|
||||||
y = ROTATION_0_INPUTS.getNativeY(isGoodOverlap),
|
pointerId = expectedPointerOnSensorId,
|
||||||
)
|
x = ROTATION_0_INPUTS.getNativeX(isWithinSensor = true),
|
||||||
|
y = ROTATION_0_INPUTS.getNativeY(isWithinSensor = true)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
NormalizedTouchData()
|
||||||
|
}
|
||||||
|
|
||||||
val expected =
|
val expected =
|
||||||
TouchProcessorResult.ProcessedTouch(
|
TouchProcessorResult.ProcessedTouch(
|
||||||
event = expectedInteractionEvent,
|
event = expectedInteractionEvent,
|
||||||
@@ -423,7 +559,7 @@ private fun genPositiveTestCases(
|
|||||||
)
|
)
|
||||||
SinglePointerTouchProcessorTest.TestCase(
|
SinglePointerTouchProcessorTest.TestCase(
|
||||||
event = event,
|
event = event,
|
||||||
isGoodOverlap = isGoodOverlap,
|
currentPointers = currentPointers,
|
||||||
previousPointerOnSensorId = previousPointerOnSensorId,
|
previousPointerOnSensorId = previousPointerOnSensorId,
|
||||||
overlayParams = overlayParams,
|
overlayParams = overlayParams,
|
||||||
expected = expected,
|
expected = expected,
|
||||||
@@ -436,7 +572,7 @@ private fun genTestCasesForUnsupportedAction(
|
|||||||
motionEventAction: Int
|
motionEventAction: Int
|
||||||
): List<SinglePointerTouchProcessorTest.TestCase> {
|
): List<SinglePointerTouchProcessorTest.TestCase> {
|
||||||
val isGoodOverlap = true
|
val isGoodOverlap = true
|
||||||
val previousPointerOnSensorIds = listOf(INVALID_POINTER_ID, POINTER_ID)
|
val previousPointerOnSensorIds = listOf(INVALID_POINTER_ID, POINTER_ID_1)
|
||||||
return previousPointerOnSensorIds.map { previousPointerOnSensorId ->
|
return previousPointerOnSensorIds.map { previousPointerOnSensorId ->
|
||||||
val overlayParams = ROTATION_0_INPUTS.toOverlayParams(scaleFactor = 1f)
|
val overlayParams = ROTATION_0_INPUTS.toOverlayParams(scaleFactor = 1f)
|
||||||
val nativeX = ROTATION_0_INPUTS.getNativeX(isGoodOverlap)
|
val nativeX = ROTATION_0_INPUTS.getNativeX(isGoodOverlap)
|
||||||
@@ -451,7 +587,7 @@ private fun genTestCasesForUnsupportedAction(
|
|||||||
)
|
)
|
||||||
SinglePointerTouchProcessorTest.TestCase(
|
SinglePointerTouchProcessorTest.TestCase(
|
||||||
event = event,
|
event = event,
|
||||||
isGoodOverlap = isGoodOverlap,
|
currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = isGoodOverlap)),
|
||||||
previousPointerOnSensorId = previousPointerOnSensorId,
|
previousPointerOnSensorId = previousPointerOnSensorId,
|
||||||
overlayParams = overlayParams,
|
overlayParams = overlayParams,
|
||||||
expected = TouchProcessorResult.Failure(),
|
expected = TouchProcessorResult.Failure(),
|
||||||
@@ -478,13 +614,23 @@ private fun obtainMotionEvent(
|
|||||||
pc.touchMinor = minor
|
pc.touchMinor = minor
|
||||||
pc.touchMajor = major
|
pc.touchMajor = major
|
||||||
pc.orientation = orientation
|
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(
|
return MotionEvent.obtain(
|
||||||
gestureStart /* downTime */,
|
gestureStart /* downTime */,
|
||||||
time /* eventTime */,
|
time /* eventTime */,
|
||||||
action /* action */,
|
action /* action */,
|
||||||
1 /* pointerCount */,
|
pointerCoords.size /* pointerCount */,
|
||||||
arrayOf(pp) /* pointerProperties */,
|
pointerProperties /* pointerProperties */,
|
||||||
arrayOf(pc) /* pointerCoords */,
|
pointerCoords /* pointerCoords */,
|
||||||
0 /* metaState */,
|
0 /* metaState */,
|
||||||
0 /* buttonState */,
|
0 /* buttonState */,
|
||||||
1f /* xPrecision */,
|
1f /* xPrecision */,
|
||||||
@@ -508,4 +654,19 @@ private fun MotionEvent.copy(
|
|||||||
gestureStart: Long = this.downTime,
|
gestureStart: Long = this.downTime,
|
||||||
) = obtainMotionEvent(action, pointerId, x, y, minor, major, orientation, time, gestureStart)
|
) = 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) }
|
private fun Rect.scaled(scaleFactor: Float) = Rect(this).apply { scale(scaleFactor) }
|
||||||
|
|||||||
@@ -19,9 +19,10 @@ package com.android.systemui.biometrics.udfps
|
|||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
|
|
||||||
class FakeOverlapDetector : OverlapDetector {
|
class FakeOverlapDetector : OverlapDetector {
|
||||||
var shouldReturn: Boolean = false
|
var shouldReturn: Map<Int, Boolean> = mapOf()
|
||||||
|
|
||||||
override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean {
|
override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean {
|
||||||
return shouldReturn
|
return shouldReturn[touchData.pointerId]
|
||||||
|
?: error("Unexpected PointerId not declared in TestCase currentPointers")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user