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

Commit 352d50b3 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Ignore nested scrolls from mouse wheel

This CL makes NestedDraggableTest ignore scroll events coming from the
mouse wheel. This is inspired by ag/29733889 and should be removed once
b/388231324 is fixed.

Bug: 378470603
Test: atest NestedDraggableTest
Flag: EXEMPT NestedDraggable is not used yet
Change-Id: Idf1da730c707e167d3683324c06df4fa3cc38379
parent b4351c14
Loading
Loading
Loading
Loading
+31 −3
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import androidx.compose.ui.input.nestedscroll.nestedScrollModifierNode
import androidx.compose.ui.input.pointer.AwaitPointerEventScope
import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.PointerId
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.PointerInputScope
@@ -168,6 +169,12 @@ private class NestedDraggableNode(
    CompositionLocalConsumerModifierNode,
    OrientationAware {
    private val nestedScrollDispatcher = NestedScrollDispatcher()
    private var trackWheelScroll: SuspendingPointerInputModifierNode? = null
        set(value) {
            field?.let { undelegate(it) }
            field = value?.also { delegate(it) }
        }

    private var trackDownPositionDelegate: SuspendingPointerInputModifierNode? = null
        set(value) {
            field?.let { undelegate(it) }
@@ -189,6 +196,7 @@ private class NestedDraggableNode(
     * This is use to track the started position of a drag started on a nested scrollable.
     */
    private var lastFirstDown: Offset? = null
    private var lastEventWasScrollWheel: Boolean = false

    /** The pointers currently down, in order of which they were done and mapping to their type. */
    private val pointersDown = linkedMapOf<PointerId, PointerType>()
@@ -218,8 +226,11 @@ private class NestedDraggableNode(
        nestedScrollController?.ensureOnDragStoppedIsCalled()
        nestedScrollController = null

        if (!enabled && trackDownPositionDelegate != null) {
        if (!enabled && trackWheelScroll != null) {
            check(trackDownPositionDelegate != null)
            check(detectDragsDelegate != null)

            trackWheelScroll = null
            trackDownPositionDelegate = null
            detectDragsDelegate = null
        }
@@ -232,17 +243,22 @@ private class NestedDraggableNode(
    ) {
        if (!enabled) return

        if (trackDownPositionDelegate == null) {
        if (trackWheelScroll == null) {
            check(trackDownPositionDelegate == null)
            check(detectDragsDelegate == null)

            trackWheelScroll = SuspendingPointerInputModifierNode { trackWheelScroll() }
            trackDownPositionDelegate = SuspendingPointerInputModifierNode { trackDownPosition() }
            detectDragsDelegate = SuspendingPointerInputModifierNode { detectDrags() }
        }

        checkNotNull(trackWheelScroll).onPointerEvent(pointerEvent, pass, bounds)
        checkNotNull(trackDownPositionDelegate).onPointerEvent(pointerEvent, pass, bounds)
        checkNotNull(detectDragsDelegate).onPointerEvent(pointerEvent, pass, bounds)
    }

    override fun onCancelPointerInput() {
        trackWheelScroll?.onCancelPointerInput()
        trackDownPositionDelegate?.onCancelPointerInput()
        detectDragsDelegate?.onCancelPointerInput()
    }
@@ -457,6 +473,13 @@ private class NestedDraggableNode(
     * ===============================
     */

    private suspend fun PointerInputScope.trackWheelScroll() {
        awaitEachGesture {
            val event = awaitPointerEvent(pass = PointerEventPass.Initial)
            lastEventWasScrollWheel = event.type == PointerEventType.Scroll
        }
    }

    private suspend fun PointerInputScope.trackDownPosition() {
        awaitEachGesture {
            try {
@@ -501,7 +524,12 @@ private class NestedDraggableNode(
        }

        val sign = offset.sign
        if (nestedScrollController == null && draggable.shouldConsumeNestedScroll(sign)) {
        if (
            nestedScrollController == null &&
                // TODO(b/388231324): Remove this.
                !lastEventWasScrollWheel &&
                draggable.shouldConsumeNestedScroll(sign)
        ) {
            val startedPosition = checkNotNull(lastFirstDown) { "lastFirstDown is not set" }

            // TODO(b/382665591): Ensure that there is at least one pointer down.
+30 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.compose.gesture

import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.rememberScrollableState
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
@@ -35,6 +37,7 @@ 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.ScrollWheel
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onRoot
@@ -710,6 +713,33 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw
        rule.onRoot().performTouchInput { down(center) }
    }

    @Test
    // TODO(b/388231324): Remove this.
    fun nestedScrollWithMouseWheelIsIgnored() {
        val draggable = TestDraggable()
        val touchSlop =
            rule.setContentWithTouchSlop {
                Box(
                    Modifier.fillMaxSize()
                        .nestedDraggable(draggable, orientation)
                        .scrollable(rememberScrollableState { 0f }, orientation)
                )
            }

        rule.onRoot().performMouseInput {
            enter(center)
            scroll(
                touchSlop + 1f,
                when (orientation) {
                    Orientation.Horizontal -> ScrollWheel.Horizontal
                    Orientation.Vertical -> ScrollWheel.Vertical
                },
            )
        }

        assertThat(draggable.onDragStartedCalled).isFalse()
    }

    private fun ComposeContentTestRule.setContentWithTouchSlop(
        content: @Composable () -> Unit
    ): Float {