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

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

Merge "MultiPointerDraggable should not lose pointerInput events" into main

parents 5a81c1b7 cad79bfe
Loading
Loading
Loading
Loading
+80 −77
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ import androidx.compose.ui.util.fastSumBy
import com.android.compose.ui.util.SpaceVectorConverter
import kotlin.coroutines.cancellation.CancellationException
import kotlin.math.sign
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

@@ -143,8 +143,8 @@ internal class MultiPointerDraggableNode(
    CompositionLocalConsumerModifierNode,
    ObserverModifierNode,
    SpaceVectorConverter {
    private val pointerInputHandler: suspend PointerInputScope.() -> Unit = { pointerInput() }
    private val delegate = delegate(SuspendingPointerInputModifierNode(pointerInputHandler))
    private val pointerTracker = delegate(SuspendingPointerInputModifierNode { pointerTracker() })
    private val pointerInput = delegate(SuspendingPointerInputModifierNode { pointerInput() })
    private val velocityTracker = VelocityTracker()
    private var previousEnabled: Boolean = false

@@ -153,7 +153,7 @@ internal class MultiPointerDraggableNode(
            // Reset the pointer input whenever enabled changed.
            if (value != field) {
                field = value
                delegate.resetPointerInputHandler()
                pointerInput.resetPointerInputHandler()
            }
        }

@@ -173,7 +173,7 @@ internal class MultiPointerDraggableNode(
            if (value != field) {
                field = value
                converter = SpaceVectorConverter(value)
                delegate.resetPointerInputHandler()
                pointerInput.resetPointerInputHandler()
            }
        }

@@ -186,19 +186,26 @@ internal class MultiPointerDraggableNode(
        observeReads {
            val newEnabled = enabled()
            if (newEnabled != previousEnabled) {
                delegate.resetPointerInputHandler()
                pointerInput.resetPointerInputHandler()
            }
            previousEnabled = newEnabled
        }
    }

    override fun onCancelPointerInput() = delegate.onCancelPointerInput()
    override fun onCancelPointerInput() {
        pointerTracker.onCancelPointerInput()
        pointerInput.onCancelPointerInput()
    }

    override fun onPointerEvent(
        pointerEvent: PointerEvent,
        pass: PointerEventPass,
        bounds: IntSize
    ) = delegate.onPointerEvent(pointerEvent, pass, bounds)
    ) {
        // The order is important here: the tracker is always called first.
        pointerTracker.onPointerEvent(pointerEvent, pass, bounds)
        pointerInput.onPointerEvent(pointerEvent, pass, bounds)
    }

    private var startedPosition: Offset? = null
    private var pointersDown: Int = 0
@@ -211,38 +218,36 @@ internal class MultiPointerDraggableNode(
        )
    }

    private suspend fun PointerInputScope.pointerInput() {
        if (!enabled()) {
            return
        }

        coroutineScope {
            launch {
    private suspend fun PointerInputScope.pointerTracker() {
        val currentContext = currentCoroutineContext()
        awaitPointerEventScope {
            // Intercepts pointer inputs and exposes [PointersInfo], via
            // [requireAncestorPointersInfoOwner], to our descendants.
                awaitPointerEventScope {
                    while (isActive) {
            while (currentContext.isActive) {
                // During the Initial pass, we receive the event after our ancestors.
                val pointers = awaitPointerEvent(PointerEventPass.Initial).changes

                pointersDown = pointers.countDown()
                if (pointersDown == 0) {
                    // There are no more pointers down
                    startedPosition = null
                } else if (startedPosition == null) {
                    startedPosition = pointers.first().position
                    if (enabled()) {
                        onFirstPointerDown()
                    }
                }
            }
        }
    }

            // The order is important here: we want to make sure that the previous PointerEventScope
            // is initialized first. This ensures that the following PointerEventScope doesn't
            // receive more events than the first one.
            launch {
    private suspend fun PointerInputScope.pointerInput() {
        if (!enabled()) {
            return
        }

        val currentContext = currentCoroutineContext()
        awaitPointerEventScope {
                    while (isActive) {
            while (currentContext.isActive) {
                try {
                    detectDragGestures(
                        orientation = orientation,
@@ -282,15 +287,13 @@ internal class MultiPointerDraggableNode(
                    )
                } catch (exception: CancellationException) {
                    // If the coroutine scope is active, we can just restart the drag cycle.
                            if (!isActive) {
                    if (!currentContext.isActive) {
                        throw exception
                    }
                }
            }
        }
    }
        }
    }

    /**
     * Start a fling gesture in another CoroutineScope, this is to ensure that even when the pointer