Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa87b00c authored by Austin Delgado's avatar Austin Delgado Committed by Android (Google) Code Review
Browse files

Merge "Add multitouch to new touch architecture" into tm-qpr-dev

parents d6fac7a4 e2123df9
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -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,
) {

    /**
+47 −49
Original line number Diff line number Diff line
@@ -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
    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)
    }
    return ProcessedTouch(interactionEvent, pointerOnSensorId, touch.data)
}

private fun processActionUp(touch: PreprocessedTouch): TouchProcessorResult {
    return if (touch.isGoodOverlap) {
        ProcessedTouch(InteractionEvent.UP, pointerOnSensorId = INVALID_POINTER_ID, touch.data)
    } else {
        val event =
            if (touch.previousPointerOnSensorId != INVALID_POINTER_ID) {
                InteractionEvent.UP
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 {
                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)
    }
}

+225 −64

File changed.

Preview size limit exceeded, changes collapsed.

+3 −2
Original line number Diff line number Diff line
@@ -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")
    }
}