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

Commit 158f837e authored by Omar Miatello's avatar Omar Miatello Committed by Android (Google) Code Review
Browse files

Merge "DragController methods return the consumed gesture" into main

parents e4f21283 2a54b7b8
Loading
Loading
Loading
Loading
+30 −19
Original line number Diff line number Diff line
@@ -52,11 +52,19 @@ internal interface DraggableHandler {
 * and [onStop] methods.
 */
internal interface DragController {
    /** Drag the current scene by [delta] pixels. */
    fun onDrag(delta: Float)
    /**
     * Drag the current scene by [delta] pixels.
     *
     * @return the consumed [delta]
     */
    fun onDrag(delta: Float): Float

    /** Starts a transition to a target scene. */
    fun onStop(velocity: Float, canChangeScene: Boolean)
    /**
     * Starts a transition to a target scene.
     *
     * @return the consumed [velocity]
     */
    fun onStop(velocity: Float, canChangeScene: Boolean): Float
}

internal class DraggableHandlerImpl(
@@ -272,8 +280,10 @@ private class DragControllerImpl(
     *
     * @return the consumed delta
     */
    override fun onDrag(delta: Float) {
        if (delta == 0f || !isDrivingTransition || swipeTransition.isFinishing) return
    override fun onDrag(delta: Float): Float {
        if (delta == 0f || !isDrivingTransition || swipeTransition.isFinishing) {
            return 0f
        }
        swipeTransition.dragOffset += delta

        val (fromScene, acceleratedOffset) =
@@ -289,7 +299,7 @@ private class DragControllerImpl(

        if (result == null) {
            onStop(velocity = delta, canChangeScene = true)
            return
            return 0f
        }

        if (
@@ -314,6 +324,8 @@ private class DragControllerImpl(

            updateTransition(swipeTransition)
        }

        return delta
    }

    /**
@@ -351,10 +363,10 @@ private class DragControllerImpl(
        }
    }

    override fun onStop(velocity: Float, canChangeScene: Boolean) {
    override fun onStop(velocity: Float, canChangeScene: Boolean): Float {
        // The state was changed since the drag started; don't do anything.
        if (!isDrivingTransition || swipeTransition.isFinishing) {
            return
            return 0f
        }

        // Important: Make sure that all the code here references the current transition when
@@ -440,7 +452,7 @@ private class DragControllerImpl(
                if (result == null) {
                    // We will not animate
                    swipeTransition.snapToScene(fromScene.key)
                    return
                    return 0f
                }

                val newSwipeTransition =
@@ -462,6 +474,9 @@ private class DragControllerImpl(
                animateTo(targetScene = fromScene, targetOffset = 0f)
            }
        }

        // The onStop animation consumes any remaining velocity.
        return velocity
    }

    /**
@@ -1081,17 +1096,13 @@ internal class NestedScrollHandlerImpl(
                // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
                // initiated in a nested child.
                controller.onDrag(delta = offsetAvailable)

                offsetAvailable
            },
            onStop = { velocityAvailable ->
                val controller = dragController ?: error("Should be called after onStart")

                controller.onStop(velocity = velocityAvailable, canChangeScene = canChangeScene)

                dragController = null
                // The onDragStopped animation consumes any remaining velocity.
                velocityAvailable
                controller
                    .onStop(velocity = velocityAvailable, canChangeScene = canChangeScene)
                    .also { dragController = null }
            },
        )
    }
@@ -1106,7 +1117,7 @@ internal class NestedScrollHandlerImpl(
internal const val OffsetVisibilityThreshold = 0.5f

private object NoOpDragController : DragController {
    override fun onDrag(delta: Float) {}
    override fun onDrag(delta: Float) = 0f

    override fun onStop(velocity: Float, canChangeScene: Boolean) {}
    override fun onStop(velocity: Float, canChangeScene: Boolean) = 0f
}
+28 −13
Original line number Diff line number Diff line
@@ -212,7 +212,8 @@ class DraggableHandlerTest {
            draggableHandler: DraggableHandler,
            startedPosition: Offset = Offset.Zero,
            overSlop: Float = 0f,
            pointersDown: Int = 1
            pointersDown: Int = 1,
            expectedConsumed: Boolean = true,
        ): DragController {
            val dragController =
                draggableHandler.onDragStarted(
@@ -222,17 +223,23 @@ class DraggableHandlerTest {
                )

            // MultiPointerDraggable will always call onDelta with the initial overSlop right after
            dragController.onDragDelta(pixels = overSlop)
            dragController.onDragDelta(pixels = overSlop, expectedConsumed = expectedConsumed)

            return dragController
        }

        fun DragController.onDragDelta(pixels: Float) {
            onDrag(delta = pixels)
        fun DragController.onDragDelta(pixels: Float, expectedConsumed: Boolean = true) {
            val consumed = onDrag(delta = pixels)
            assertThat(consumed).isEqualTo(if (expectedConsumed) pixels else 0f)
        }

        fun DragController.onDragStopped(velocity: Float, canChangeScene: Boolean = true) {
            onStop(velocity, canChangeScene)
        fun DragController.onDragStopped(
            velocity: Float,
            canChangeScene: Boolean = true,
            expectedConsumed: Boolean = true
        ) {
            val consumed = onStop(velocity, canChangeScene)
            assertThat(consumed).isEqualTo(if (expectedConsumed) velocity else 0f)
        }

        fun NestedScrollConnection.scroll(
@@ -360,10 +367,18 @@ class DraggableHandlerTest {

    @Test
    fun onDragStartedWithoutActionsInBothDirections_stayIdle() = runGestureTest {
        onDragStarted(horizontalDraggableHandler, overSlop = up(fractionOfScreen = 0.3f))
        onDragStarted(
            horizontalDraggableHandler,
            overSlop = up(fractionOfScreen = 0.3f),
            expectedConsumed = false,
        )
        assertIdle(currentScene = SceneA)

        onDragStarted(horizontalDraggableHandler, overSlop = down(fractionOfScreen = 0.3f))
        onDragStarted(
            horizontalDraggableHandler,
            overSlop = down(fractionOfScreen = 0.3f),
            expectedConsumed = false,
        )
        assertIdle(currentScene = SceneA)
    }

@@ -489,19 +504,19 @@ class DraggableHandlerTest {

        // start accelaratedScroll and scroll over to B -> null
        val dragController2 = onDragStartedImmediately()
        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = false)
        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = false)

        // here onDragStopped is already triggered, but subsequent onDelta/onDragStopped calls may
        // still be called. Make sure that they don't crash or change the scene
        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = false)
        dragController2.onDragStopped(velocity = 0f)

        advanceUntilIdle()
        assertIdle(SceneB)

        // These events can still come in after the animation has settled
        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = false)
        dragController2.onDragStopped(velocity = 0f)
        assertIdle(SceneB)
    }
@@ -845,7 +860,7 @@ class DraggableHandlerTest {
        assertThat(progress).isEqualTo(0.2f)

        // this should be ignored, we are scrolling now!
        dragController.onDragStopped(-velocityThreshold)
        dragController.onDragStopped(-velocityThreshold, expectedConsumed = false)
        assertTransition(currentScene = SceneA)

        nestedScroll.scroll(available = -offsetY10)
+43 −59
Original line number Diff line number Diff line
@@ -49,6 +49,21 @@ import org.junit.runner.RunWith
class MultiPointerDraggableTest {
    @get:Rule val rule = createComposeRule()

    private class SimpleDragController(
        val onDrag: () -> Unit,
        val onStop: () -> Unit,
    ) : DragController {
        override fun onDrag(delta: Float): Float {
            onDrag()
            return delta
        }

        override fun onStop(velocity: Float, canChangeScene: Boolean): Float {
            onStop()
            return velocity
        }
    }

    @Test
    fun cancellingPointerCallsOnDragStopped() {
        val size = 200f
@@ -70,15 +85,10 @@ class MultiPointerDraggableTest {
                        startDragImmediately = { false },
                        onDragStarted = { _, _, _ ->
                            started = true
                            object : DragController {
                                override fun onDrag(delta: Float) {
                                    dragged = true
                                }

                                override fun onStop(velocity: Float, canChangeScene: Boolean) {
                                    stopped = true
                                }
                            }
                            SimpleDragController(
                                onDrag = { dragged = true },
                                onStop = { stopped = true },
                            )
                        },
                    )
            )
@@ -142,15 +152,10 @@ class MultiPointerDraggableTest {
                        startDragImmediately = { true },
                        onDragStarted = { _, _, _ ->
                            started = true
                            object : DragController {
                                override fun onDrag(delta: Float) {
                                    dragged = true
                                }

                                override fun onStop(velocity: Float, canChangeScene: Boolean) {
                                    stopped = true
                                }
                            }
                            SimpleDragController(
                                onDrag = { dragged = true },
                                onStop = { stopped = true },
                            )
                        },
                    )
                    .pointerInput(Unit) {
@@ -218,15 +223,10 @@ class MultiPointerDraggableTest {
                        startDragImmediately = { false },
                        onDragStarted = { _, _, _ ->
                            started = true
                            object : DragController {
                                override fun onDrag(delta: Float) {
                                    dragged = true
                                }

                                override fun onStop(velocity: Float, canChangeScene: Boolean) {
                                    stopped = true
                                }
                            }
                            SimpleDragController(
                                onDrag = { dragged = true },
                                onStop = { stopped = true },
                            )
                        },
                    )
            ) {
@@ -341,15 +341,10 @@ class MultiPointerDraggableTest {
                        startDragImmediately = { false },
                        onDragStarted = { _, _, _ ->
                            started = true
                            object : DragController {
                                override fun onDrag(delta: Float) {
                                    dragged = true
                                }

                                override fun onStop(velocity: Float, canChangeScene: Boolean) {
                                    stopped = true
                                }
                            }
                            SimpleDragController(
                                onDrag = { dragged = true },
                                onStop = { stopped = true },
                            )
                        },
                    )
            ) {
@@ -447,15 +442,10 @@ class MultiPointerDraggableTest {
                        startDragImmediately = { false },
                        onDragStarted = { _, _, _ ->
                            verticalStarted = true
                            object : DragController {
                                override fun onDrag(delta: Float) {
                                    verticalDragged = true
                                }

                                override fun onStop(velocity: Float, canChangeScene: Boolean) {
                                    verticalStopped = true
                                }
                            }
                            SimpleDragController(
                                onDrag = { verticalDragged = true },
                                onStop = { verticalStopped = true },
                            )
                        },
                    )
                    .multiPointerDraggable(
@@ -464,15 +454,10 @@ class MultiPointerDraggableTest {
                        startDragImmediately = { false },
                        onDragStarted = { _, _, _ ->
                            horizontalStarted = true
                            object : DragController {
                                override fun onDrag(delta: Float) {
                                    horizontalDragged = true
                                }

                                override fun onStop(velocity: Float, canChangeScene: Boolean) {
                                    horizontalStopped = true
                                }
                            }
                            SimpleDragController(
                                onDrag = { horizontalDragged = true },
                                onStop = { horizontalStopped = true },
                            )
                        },
                    )
            )
@@ -567,11 +552,10 @@ class MultiPointerDraggableTest {
                            },
                        onDragStarted = { _, _, _ ->
                            started = true
                            object : DragController {
                                override fun onDrag(delta: Float) {}

                                override fun onStop(velocity: Float, canChangeScene: Boolean) {}
                            }
                            SimpleDragController(
                                onDrag = { /* do nothing */ },
                                onStop = { /* do nothing */ },
                            )
                        },
                    )
            ) {}