diff options
4 files changed, 283 insertions, 123 deletions
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 62bedc627b07..48d48450e13e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/NormalizedTouchData.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/NormalizedTouchData.kt @@ -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,  ) {      /** 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 693f64a1f93d..3a01cd502929 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt @@ -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)      }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt index 56043e306c16..34ddf795c7e7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt @@ -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) } 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 8176dd07b84a..1bdee3667d04 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 @@ -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")      }  }  |