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

Commit f0b04418 authored by omarmt's avatar omarmt
Browse files

Add support for fromSource in nested scroll

STL's nested scroll connection now uses the information available in the
 DraggableHandler to compute the current action (Swipe.Resolved).

Test: atest DraggableHandlerTest
Bug: 366387626
Flag: com.android.systemui.scene_container
Change-Id: Ib6b53679de0a3a1aa8bf4fe096f3bb04f3292c8f
parent 1e34a1df
Loading
Loading
Loading
Loading
+20 −29
Original line number Diff line number Diff line
@@ -188,7 +188,7 @@ internal class DraggableHandlerImpl(
        return createSwipeAnimation(layoutImpl, result, isUpOrLeft, orientation)
    }

    private fun resolveSwipeSource(startedPosition: Offset?): SwipeSource.Resolved? {
    internal fun resolveSwipeSource(startedPosition: Offset?): SwipeSource.Resolved? {
        if (startedPosition == null) return null
        return layoutImpl.swipeSourceDetector.source(
            layoutSize = layoutImpl.lastSize,
@@ -198,7 +198,7 @@ internal class DraggableHandlerImpl(
        )
    }

    private fun resolveSwipe(
    internal fun resolveSwipe(
        pointersDown: Int,
        fromSource: SwipeSource.Resolved?,
        isUpOrLeft: Boolean,
@@ -558,6 +558,14 @@ internal class NestedScrollHandlerImpl(

    val connection: PriorityNestedScrollConnection = nestedScrollConnection()

    private fun PointersInfo.resolveSwipe(isUpOrLeft: Boolean): Swipe.Resolved {
        return draggableHandler.resolveSwipe(
            pointersDown = pointersDown,
            fromSource = draggableHandler.resolveSwipeSource(startedPosition),
            isUpOrLeft = isUpOrLeft,
        )
    }

    private fun nestedScrollConnection(): PriorityNestedScrollConnection {
        // If we performed a long gesture before entering priority mode, we would have to avoid
        // moving on to the next scene.
@@ -574,36 +582,19 @@ internal class NestedScrollHandlerImpl(
            val transitionState = layoutState.transitionState
            val scene = transitionState.currentScene
            val fromScene = layoutImpl.scene(scene)
            val nextScene =
            val resolvedSwipe =
                when {
                    amount < 0f -> {
                        val actionUpOrLeft =
                            Swipe.Resolved(
                                direction =
                                    when (orientation) {
                                        Orientation.Horizontal -> SwipeDirection.Resolved.Left
                                        Orientation.Vertical -> SwipeDirection.Resolved.Up
                                    },
                                pointerCount = pointersInfo().pointersDown,
                                fromSource = null,
                            )
                        fromScene.userActions[actionUpOrLeft]
                    }
                    amount > 0f -> {
                        val actionDownOrRight =
                            Swipe.Resolved(
                                direction =
                                    when (orientation) {
                                        Orientation.Horizontal -> SwipeDirection.Resolved.Right
                                        Orientation.Vertical -> SwipeDirection.Resolved.Down
                                    },
                                pointerCount = pointersInfo().pointersDown,
                                fromSource = null,
                            )
                        fromScene.userActions[actionDownOrRight]
                    }
                    amount < 0f -> pointersInfo().resolveSwipe(isUpOrLeft = true)
                    amount > 0f -> pointersInfo().resolveSwipe(isUpOrLeft = false)
                    else -> null
                }
            val nextScene =
                resolvedSwipe?.let {
                    fromScene.userActions[it]
                        ?: if (it.fromSource != null) {
                            fromScene.userActions[it.copy(fromSource = null)]
                        } else null
                }
            if (nextScene != null) return true

            if (transitionState !is TransitionState.Idle) return false
+2 −1
Original line number Diff line number Diff line
@@ -213,8 +213,9 @@ internal class MultiPointerDraggableNode(

    internal fun pointersInfo(): PointersInfo {
        return PointersInfo(
            // This may be null, i.e. when the user uses TalkBack
            startedPosition = startedPosition,
            // Note: We could have 0 pointers during fling or for other reasons.
            // We could have 0 pointers during fling or for other reasons.
            pointersDown = pointersDown.coerceAtLeast(1),
        )
    }
+52 −4
Original line number Diff line number Diff line
@@ -129,6 +129,10 @@ class DraggableHandlerTest {
        val draggableHandler = layoutImpl.draggableHandler(Orientation.Vertical)
        val horizontalDraggableHandler = layoutImpl.draggableHandler(Orientation.Horizontal)

        var pointerInfoOwner: () -> PointersInfo = {
            PointersInfo(startedPosition = Offset.Zero, pointersDown = 1)
        }

        fun nestedScrollConnection(
            nestedScrollBehavior: NestedScrollBehavior,
            isExternalOverscrollGesture: Boolean = false,
@@ -139,9 +143,7 @@ class DraggableHandlerTest {
                    topOrLeftBehavior = nestedScrollBehavior,
                    bottomOrRightBehavior = nestedScrollBehavior,
                    isExternalOverscrollGesture = { isExternalOverscrollGesture },
                    pointersInfoOwner = {
                        PointersInfo(startedPosition = Offset.Zero, pointersDown = 1)
                    },
                    pointersInfoOwner = { pointerInfoOwner() },
                )
                .connection

@@ -155,11 +157,18 @@ class DraggableHandlerTest {

        fun downOffset(fractionOfScreen: Float) =
            if (fractionOfScreen < 0f) {
                error("upOffset() is required, not implemented yet")
                error("use upOffset()")
            } else {
                Offset(x = 0f, y = down(fractionOfScreen))
            }

        fun upOffset(fractionOfScreen: Float) =
            if (fractionOfScreen < 0f) {
                error("use downOffset()")
            } else {
                Offset(x = 0f, y = up(fractionOfScreen))
            }

        val transitionState: TransitionState
            get() = layoutState.transitionState

@@ -1070,6 +1079,45 @@ class DraggableHandlerTest {
        assertThat(transition!!.progress).isEqualTo(-0.1f)
    }

    @Test
    fun nestedScrollUseFromSourceInfo() = runGestureTest {
        // Start at scene C.
        navigateToSceneC()
        val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)

        // Drag from the **top** of the screen
        pointerInfoOwner = { PointersInfo(startedPosition = Offset(0f, 0f), pointersDown = 1) }
        assertIdle(currentScene = SceneC)

        nestedScroll.scroll(available = upOffset(fractionOfScreen = 0.1f))
        assertTransition(
            currentScene = SceneC,
            fromScene = SceneC,
            // userAction: Swipe.Up to SceneB
            toScene = SceneB,
            progress = 0.1f,
        )

        // Reset to SceneC
        nestedScroll.preFling(Velocity.Zero)
        advanceUntilIdle()

        // Drag from the **bottom** of the screen
        pointerInfoOwner = {
            PointersInfo(startedPosition = Offset(0f, SCREEN_SIZE), pointersDown = 1)
        }
        assertIdle(currentScene = SceneC)

        nestedScroll.scroll(available = upOffset(fractionOfScreen = 0.1f))
        assertTransition(
            currentScene = SceneC,
            fromScene = SceneC,
            // userAction: Swipe(SwipeDirection.Up, fromSource = Edge.Bottom) to SceneA
            toScene = SceneA,
            progress = 0.1f,
        )
    }

    @Test
    fun transitionIsImmediatelyUpdatedWhenReleasingFinger() = runGestureTest {
        // Swipe up from the middle to transition to scene B.