summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt50
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt41
2 files changed, 78 insertions, 13 deletions
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 3f6bce724b1b..f386cf5842e6 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
@@ -37,11 +37,7 @@ internal fun Modifier.swipeToScene(
draggableHandler: DraggableHandlerImpl,
swipeDetector: SwipeDetector,
): Modifier {
- return if (draggableHandler.enabled()) {
- this.then(SwipeToSceneElement(draggableHandler, swipeDetector))
- } else {
- this
- }
+ return then(SwipeToSceneElement(draggableHandler, swipeDetector, draggableHandler.enabled()))
}
private fun DraggableHandlerImpl.enabled(): Boolean {
@@ -114,31 +110,59 @@ internal fun Content.findActionResultBestMatch(swipe: Swipe.Resolved): UserActio
private data class SwipeToSceneElement(
val draggableHandler: DraggableHandlerImpl,
val swipeDetector: SwipeDetector,
+ val enabled: Boolean,
) : ModifierNodeElement<SwipeToSceneRootNode>() {
override fun create(): SwipeToSceneRootNode =
- SwipeToSceneRootNode(draggableHandler, swipeDetector)
+ SwipeToSceneRootNode(draggableHandler, swipeDetector, enabled)
override fun update(node: SwipeToSceneRootNode) {
- node.update(draggableHandler, swipeDetector)
+ node.update(draggableHandler, swipeDetector, enabled)
}
}
private class SwipeToSceneRootNode(
draggableHandler: DraggableHandlerImpl,
swipeDetector: SwipeDetector,
+ enabled: Boolean,
) : DelegatingNode() {
- private var delegateNode = delegate(SwipeToSceneNode(draggableHandler, swipeDetector))
+ private var delegateNode = if (enabled) create(draggableHandler, swipeDetector) else null
+
+ fun update(
+ draggableHandler: DraggableHandlerImpl,
+ swipeDetector: SwipeDetector,
+ enabled: Boolean,
+ ) {
+ // Disabled.
+ if (!enabled) {
+ delegateNode?.let { undelegate(it) }
+ delegateNode = null
+ return
+ }
+
+ // Disabled => Enabled.
+ val nullableDelegate = delegateNode
+ if (nullableDelegate == null) {
+ delegateNode = create(draggableHandler, swipeDetector)
+ return
+ }
- fun update(draggableHandler: DraggableHandlerImpl, swipeDetector: SwipeDetector) {
- if (draggableHandler == delegateNode.draggableHandler) {
+ // Enabled => Enabled (update).
+ if (draggableHandler == nullableDelegate.draggableHandler) {
// Simple update, just update the swipe detector directly and keep the node.
- delegateNode.swipeDetector = swipeDetector
+ nullableDelegate.swipeDetector = swipeDetector
} else {
// The draggableHandler changed, force recreate the underlying SwipeToSceneNode.
- undelegate(delegateNode)
- delegateNode = delegate(SwipeToSceneNode(draggableHandler, swipeDetector))
+ undelegate(nullableDelegate)
+ delegateNode = create(draggableHandler, swipeDetector)
}
}
+
+ private fun create(
+ draggableHandler: DraggableHandlerImpl,
+ swipeDetector: SwipeDetector,
+ ): SwipeToSceneNode {
+ return delegate(SwipeToSceneNode(draggableHandler, swipeDetector))
+ }
}
private class SwipeToSceneNode(
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 9135fdd15b3a..e80805a4e374 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -936,4 +936,45 @@ class SwipeToSceneTest {
assertThat(state.transitionState).isIdle()
assertThat(state.transitionState).hasCurrentScene(SceneC)
}
+
+ @Test
+ fun swipeToSceneNodeIsKeptWhenDisabled() {
+ var hasHorizontalActions by mutableStateOf(false)
+ val state = rule.runOnUiThread { MutableSceneTransitionLayoutState(SceneA) }
+ var touchSlop = 0f
+ rule.setContent {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ SceneTransitionLayout(state) {
+ scene(
+ SceneA,
+ userActions =
+ buildList {
+ add(Swipe.Down to SceneB)
+
+ if (hasHorizontalActions) {
+ add(Swipe.Left to SceneC)
+ }
+ }
+ .toMap(),
+ ) {
+ Box(Modifier.fillMaxSize())
+ }
+ scene(SceneB) { Box(Modifier.fillMaxSize()) }
+ }
+ }
+
+ // Swipe down to start a transition to B.
+ rule.onRoot().performTouchInput {
+ down(middle)
+ moveBy(Offset(0f, touchSlop))
+ }
+
+ assertThat(state.transitionState).isSceneTransition()
+
+ // Add new horizontal user actions. This should not stop the current transition, even if a
+ // new horizontal Modifier.swipeToScene() handler is introduced where the vertical one was.
+ hasHorizontalActions = true
+ rule.waitForIdle()
+ assertThat(state.transitionState).isSceneTransition()
+ }
}