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

Commit 6988f849 authored by omarmt's avatar omarmt
Browse files

Drag events can only start if there is at least one pointer down.

In this CL, there needs to be at least one pointer down. That's because,
 in a later CL, the initial position will be calculated from the instant
  the pointer touches the screen and it'll be nullified when there are
  no more pointers on the screen.

Test: atest MultiPointerDraggableTest
Bug: 330200163
Flag: com.android.systemui.scene_container
Change-Id: I58fd5cc2fefeff1284b492c1313dfb64bc12044d
parent 1b459ac9
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