Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt +80 −77 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -153,7 +153,7 @@ internal class MultiPointerDraggableNode( // Reset the pointer input whenever enabled changed. if (value != field) { field = value delegate.resetPointerInputHandler() pointerInput.resetPointerInputHandler() } } Loading @@ -173,7 +173,7 @@ internal class MultiPointerDraggableNode( if (value != field) { field = value converter = SpaceVectorConverter(value) delegate.resetPointerInputHandler() pointerInput.resetPointerInputHandler() } } Loading @@ -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 Loading @@ -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, Loading Loading @@ -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 Loading Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt +80 −77 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -153,7 +153,7 @@ internal class MultiPointerDraggableNode( // Reset the pointer input whenever enabled changed. if (value != field) { field = value delegate.resetPointerInputHandler() pointerInput.resetPointerInputHandler() } } Loading @@ -173,7 +173,7 @@ internal class MultiPointerDraggableNode( if (value != field) { field = value converter = SpaceVectorConverter(value) delegate.resetPointerInputHandler() pointerInput.resetPointerInputHandler() } } Loading @@ -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 Loading @@ -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, Loading Loading @@ -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 Loading