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

Commit 3b7c2e6b authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Drag events can only start if there is at least one pointer down." into main

parents 2731289f 6988f849
Loading
Loading
Loading
Loading
+11 −9
Original line number Diff line number Diff line
@@ -362,11 +362,13 @@ internal class MultiPointerDraggableNode(
        pass: () -> PointerEventPass,
    ): PointerEvent {
        fun canBeConsumed(changes: List<PointerInputChange>): Boolean {
            // At least one pointer down AND
            return changes.fastAny { it.pressed } &&
                // All pointers must be:
            return changes.fastAll {
                // A) recently pressed: even if the event has already been consumed, we can still
                // use the recently added finger event to determine whether to initiate dragging the
                // scene.
                changes.fastAll {
                    // A) recently pressed: even if the event has already been consumed, we can
                    // still use the recently added finger event to determine whether to initiate
                    // dragging the scene.
                    it.changedToDownIgnoreConsumed() ||
                        // B) unconsumed AND in a new position (on the current axis)
                        it.positionChange().toFloat() != 0f
+74 −0
Original line number Diff line number Diff line
@@ -120,6 +120,80 @@ class MultiPointerDraggableTest {
        assertThat(stopped).isTrue()
    }

    @Test
    fun shouldNotStartDragEventsWith0PointersDown() {
        val size = 200f
        val middle = Offset(size / 2f, size / 2f)

        var started = false
        var dragged = false
        var stopped = false
        var consumeBeforeMultiPointerDraggable = false

        var touchSlop = 0f
        rule.setContent {
            touchSlop = LocalViewConfiguration.current.touchSlop
            Box(
                Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
                    .multiPointerDraggable(
                        orientation = Orientation.Vertical,
                        enabled = { true },
                        startDragImmediately = { true },
                        onDragStarted = { _, _, _ ->
                            started = true
                            object : DragController {
                                override fun onDrag(delta: Float) {
                                    dragged = true
                                }

                                override fun onStop(velocity: Float, canChangeScene: Boolean) {
                                    stopped = true
                                }
                            }
                        },
                    )
                    .pointerInput(Unit) {
                        coroutineScope {
                            awaitPointerEventScope {
                                while (isActive) {
                                    val change = awaitPointerEvent().changes.first()
                                    if (consumeBeforeMultiPointerDraggable) {
                                        change.consume()
                                    }
                                }
                            }
                        }
                    }
            )
        }

        // The first part of the gesture is consumed by our descendant
        consumeBeforeMultiPointerDraggable = true
        rule.onRoot().performTouchInput {
            down(middle)
            moveBy(Offset(0f, touchSlop))
        }

        started = false
        dragged = false
        stopped = false

        // The next events could be consumed by us
        consumeBeforeMultiPointerDraggable = false
        rule.onRoot().performTouchInput {
            // The pointer is moved to a new position without reporting it
            updatePointerBy(0, Offset(0f, touchSlop))

            // The pointer report an "up" (0 pointers down) with a new position
            up()
        }

        // This event should not be used to start a drag gesture
        assertThat(started).isFalse()
        assertThat(dragged).isFalse()
        assertThat(stopped).isFalse()
    }

    @Test
    fun handleDisappearingScrollableDuringAGesture() {
        val size = 200f