Merge "Support for multiple gestures at once" into main
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index d70a248..2dc53ab 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -157,6 +157,8 @@
*/
private val positionalThreshold = with(layoutImpl.density) { 56.dp.toPx() }
+ internal var gestureWithPriority: Any? = null
+
internal fun onDragStarted() {
if (isDrivingTransition) {
// This [transition] was already driving the animation: simply take over it.
@@ -525,15 +527,21 @@
private val gestureHandler: SceneGestureHandler,
) : DraggableHandler {
override suspend fun onDragStarted(coroutineScope: CoroutineScope, startedPosition: Offset) {
+ gestureHandler.gestureWithPriority = this
gestureHandler.onDragStarted()
}
override fun onDelta(pixels: Float) {
- gestureHandler.onDrag(delta = pixels)
+ if (gestureHandler.gestureWithPriority == this) {
+ gestureHandler.onDrag(delta = pixels)
+ }
}
override suspend fun onDragStopped(coroutineScope: CoroutineScope, velocity: Float) {
- gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true)
+ if (gestureHandler.gestureWithPriority == this) {
+ gestureHandler.gestureWithPriority = null
+ gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true)
+ }
}
}
@@ -615,10 +623,15 @@
},
canContinueScroll = { priorityScene == gestureHandler.swipeTransitionToScene.key },
onStart = {
+ gestureHandler.gestureWithPriority = this
priorityScene = nextScene
gestureHandler.onDragStarted()
},
onScroll = { offsetAvailable ->
+ if (gestureHandler.gestureWithPriority != this) {
+ return@PriorityNestedScrollConnection Offset.Zero
+ }
+
val amount = offsetAvailable.toAmount()
// TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
@@ -628,6 +641,10 @@
amount.toOffset()
},
onStop = { velocityAvailable ->
+ if (gestureHandler.gestureWithPriority != this) {
+ return@PriorityNestedScrollConnection Velocity.Zero
+ }
+
priorityScene = null
gestureHandler.onDragStopped(
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
index 9b9e70d..6791a85 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
@@ -312,4 +312,52 @@
advanceUntilIdle()
assertScene(currentScene = SceneA, isIdle = true)
}
+
+ @Test
+ fun beforeDraggableStart_drag_shouldBeIgnored() = runGestureTest {
+ draggable.onDelta(deltaInPixels10)
+ assertScene(currentScene = SceneA, isIdle = true)
+ }
+ @Test
+ fun beforeDraggableStart_stop_shouldBeIgnored() = runGestureTest {
+ draggable.onDragStopped(coroutineScope, velocityThreshold)
+ assertScene(currentScene = SceneA, isIdle = true)
+ }
+
+ @Test
+ fun beforeNestedScrollStart_stop_shouldBeIgnored() = runGestureTest {
+ nestedScroll.onPreFling(Velocity(0f, velocityThreshold))
+ assertScene(currentScene = SceneA, isIdle = true)
+ }
+
+ @Test
+ fun startNestedScrollWhileDragging() = runGestureTest {
+ draggable.onDragStarted(coroutineScope, Offset.Zero)
+ assertScene(currentScene = SceneA, isIdle = false)
+ val transition = transitionState as Transition
+
+ draggable.onDelta(deltaInPixels10)
+ assertThat(transition.progress).isEqualTo(0.1f)
+
+ // now we can intercept the scroll events
+ nestedScrollEvents(available = offsetY10)
+ assertThat(transition.progress).isEqualTo(0.2f)
+
+ // this should be ignored, we are scrolling now!
+ draggable.onDragStopped(coroutineScope, velocityThreshold)
+ assertScene(currentScene = SceneA, isIdle = false)
+
+ nestedScrollEvents(available = offsetY10)
+ assertThat(transition.progress).isEqualTo(0.3f)
+
+ nestedScrollEvents(available = offsetY10)
+ assertThat(transition.progress).isEqualTo(0.4f)
+
+ nestedScroll.onPreFling(available = Velocity(0f, velocityThreshold))
+ assertScene(currentScene = SceneC, isIdle = false)
+
+ // wait for the stop animation
+ advanceUntilIdle()
+ assertScene(currentScene = SceneC, isIdle = true)
+ }
}