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

Commit 9b4e15ea authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Add pointerType to NestedDraggable.onDragStarted()

This CL adds the type of the first pointer that was down when a drag is
detected. This will be used to be able to specify different actions
depending on the pointer type.

Bug: 378470603
Test: atest NestedDraggableTest
Flag: EXEMPT NestedDraggable is not used yet
Change-Id: I9af3f5eb4196f728e5da8bd9bca3718643c39e5a
parent c3513a5f
Loading
Loading
Loading
Loading
+28 −18
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.PointerId
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.PointerInputScope
import androidx.compose.ui.input.pointer.PointerType
import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
import androidx.compose.ui.input.pointer.changedToDownIgnoreConsumed
import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed
@@ -52,7 +53,6 @@ import androidx.compose.ui.node.currentValueOf
import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.util.fastSumBy
import com.android.compose.modifiers.thenIf
import kotlin.math.sign
import kotlinx.coroutines.CompletableDeferred
@@ -81,7 +81,13 @@ interface NestedDraggable {
     * in the direction given by [sign], with the given number of [pointersDown] when the touch slop
     * was detected.
     */
    fun onDragStarted(position: Offset, sign: Float, pointersDown: Int): Controller
    fun onDragStarted(
        position: Offset,
        sign: Float,
        pointersDown: Int,
        // TODO(b/382665591): Make this non-nullable.
        pointerType: PointerType?,
    ): Controller

    /**
     * Whether this draggable should consume any scroll amount with the given [sign] coming from a
@@ -184,8 +190,8 @@ private class NestedDraggableNode(
     */
    private var lastFirstDown: Offset? = null

    /** The number of pointers down. */
    private var pointersDownCount = 0
    /** The pointers currently down, in order of which they were done and mapping to their type. */
    private val pointersDown = linkedMapOf<PointerId, PointerType>()

    init {
        delegate(nestedScrollModifierNode(this, nestedScrollDispatcher))
@@ -256,7 +262,9 @@ private class NestedDraggableNode(
            check(down.position == lastFirstDown) {
                "Position from detectDrags() is not the same as position in trackDownPosition()"
            }
            check(pointersDownCount == 1) { "pointersDownCount is equal to $pointersDownCount" }
            check(pointersDown.size == 1 && pointersDown.keys.first() == down.id) {
                "pointersDown should only contain $down but it contains $pointersDown"
            }

            var overSlop = 0f
            val onTouchSlopReached = { change: PointerInputChange, over: Float ->
@@ -295,8 +303,9 @@ private class NestedDraggableNode(
                    }
                }

                check(pointersDownCount > 0) { "pointersDownCount is equal to $pointersDownCount" }
                val controller = draggable.onDragStarted(down.position, sign, pointersDownCount)
                check(pointersDown.size > 0) { "pointersDown is empty" }
                val controller =
                    draggable.onDragStarted(down.position, sign, pointersDown.size, drag.type)
                if (overSlop != 0f) {
                    onDrag(controller, drag, overSlop, velocityTracker)
                }
@@ -452,18 +461,18 @@ private class NestedDraggableNode(
        awaitEachGesture {
            val down = awaitFirstDown(requireUnconsumed = false)
            lastFirstDown = down.position
            pointersDownCount = 1
            pointersDown[down.id] = down.type

            do {
                pointersDownCount +=
                    awaitPointerEvent().changes.fastSumBy { change ->
                awaitPointerEvent().changes.forEach { change ->
                    when {
                            change.changedToDownIgnoreConsumed() -> 1
                            change.changedToUpIgnoreConsumed() -> -1
                            else -> 0
                        change.changedToDownIgnoreConsumed() -> {
                            pointersDown[change.id] = change.type
                        }
                        change.changedToUpIgnoreConsumed() -> pointersDown.remove(change.id)
                    }
                }
            } while (pointersDownCount > 0)
            } while (pointersDown.size > 0)
        }
    }

@@ -491,12 +500,13 @@ private class NestedDraggableNode(
        if (nestedScrollController == null && draggable.shouldConsumeNestedScroll(sign)) {
            val startedPosition = checkNotNull(lastFirstDown) { "lastFirstDown is not set" }

            // TODO(b/382665591): Replace this by check(pointersDownCount > 0).
            val pointersDown = pointersDownCount.coerceAtLeast(1)
            // TODO(b/382665591): Ensure that there is at least one pointer down.
            val pointersDownCount = pointersDown.size.coerceAtLeast(1)
            val pointerType = pointersDown.entries.firstOrNull()?.value
            nestedScrollController =
                NestedScrollController(
                    overscrollEffect,
                    draggable.onDragStarted(startedPosition, sign, pointersDown),
                    draggable.onDragStarted(startedPosition, sign, pointersDownCount, pointerType),
                )
        }

+39 −0
Original line number Diff line number Diff line
@@ -33,10 +33,12 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.PointerType
import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performMouseInput
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeDown
import androidx.compose.ui.test.swipeLeft
@@ -653,6 +655,40 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw
        assertThat(flingIsDone).isTrue()
    }

    @Test
    fun pointerType() {
        val draggable = TestDraggable()
        val touchSlop =
            rule.setContentWithTouchSlop {
                Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation))
            }

        rule.onRoot().performTouchInput {
            down(center)
            moveBy(touchSlop.toOffset())
        }

        assertThat(draggable.onDragStartedPointerType).isEqualTo(PointerType.Touch)
    }

    @Test
    fun pointerType_mouse() {
        val draggable = TestDraggable()
        val touchSlop =
            rule.setContentWithTouchSlop {
                Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation))
            }

        rule.onRoot().performMouseInput {
            moveTo(center)
            press()
            moveBy(touchSlop.toOffset())
            release()
        }

        assertThat(draggable.onDragStartedPointerType).isEqualTo(PointerType.Mouse)
    }

    private fun ComposeContentTestRule.setContentWithTouchSlop(
        content: @Composable () -> Unit
    ): Float {
@@ -688,6 +724,7 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw
        var onDragStartedPosition = Offset.Zero
        var onDragStartedSign = 0f
        var onDragStartedPointersDown = 0
        var onDragStartedPointerType: PointerType? = null
        var onDragDelta = 0f

        override fun shouldStartDrag(change: PointerInputChange): Boolean = shouldStartDrag
@@ -696,11 +733,13 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw
            position: Offset,
            sign: Float,
            pointersDown: Int,
            pointerType: PointerType?,
        ): NestedDraggable.Controller {
            onDragStartedCalled = true
            onDragStartedPosition = position
            onDragStartedSign = sign
            onDragStartedPointersDown = pointersDown
            onDragStartedPointerType = pointerType
            onDragDelta = 0f

            onDragStarted.invoke(position, sign)