Replace swipe Edge (detector) by SwipeSource (detector) (1/2)
This CL replaces Edge and EdgeDetector by a more generic SwipeSource and
SwipeSourceDetector. This will allow users to define their own
SwipeSource's, for instance to implement a dual shade where swipe down
from the left half of the screen has a different behavior than swiping
down on the right side of the screen.
Bug: 322130260
Test: FixedSizeEdgeDetectorTest
Test: SwipeToSceneTest
Flag: N/A
Change-Id: Ib50c75ea7bb5a9fa0d775845a2ee16acb4aceecd
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index c073b79b..bbba826 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -85,13 +85,14 @@
SceneTransitionLayout(
state = sceneTransitionLayoutState,
modifier = modifier.fillMaxSize(),
- edgeDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize),
+ swipeSourceDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize),
) {
scene(
TransitionSceneKey.Blank,
userActions =
mapOf(
- Swipe(SwipeDirection.Left, fromEdge = Edge.Right) to TransitionSceneKey.Communal
+ Swipe(SwipeDirection.Left, fromSource = Edge.Right) to
+ TransitionSceneKey.Communal
)
) {
// This scene shows nothing only allowing for transitions to the communal scene.
@@ -102,7 +103,7 @@
TransitionSceneKey.Communal,
userActions =
mapOf(
- Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to TransitionSceneKey.Blank
+ Swipe(SwipeDirection.Right, fromSource = Edge.Left) to TransitionSceneKey.Blank
),
) {
CommunalScene(viewModel, modifier = modifier)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index c35202c..9f9e1f5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -183,7 +183,7 @@
is UserAction.Swipe ->
Swipe(
pointerCount = pointerCount,
- fromEdge =
+ fromSource =
when (this.fromEdge) {
null -> null
Edge.LEFT -> SceneTransitionEdge.Left
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt
index 82d4239..b0dc3a1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt
@@ -23,24 +23,19 @@
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
-interface EdgeDetector {
- /**
- * Return the [Edge] associated to [position] inside a layout of size [layoutSize], given
- * [density] and [orientation].
- */
- fun edge(
- layoutSize: IntSize,
- position: IntOffset,
- density: Density,
- orientation: Orientation,
- ): Edge?
+/** The edge of a [SceneTransitionLayout]. */
+enum class Edge : SwipeSource {
+ Left,
+ Right,
+ Top,
+ Bottom,
}
val DefaultEdgeDetector = FixedSizeEdgeDetector(40.dp)
-/** An [EdgeDetector] that detects edges assuming a fixed edge size of [size]. */
-class FixedSizeEdgeDetector(val size: Dp) : EdgeDetector {
- override fun edge(
+/** An [SwipeSourceDetector] that detects edges assuming a fixed edge size of [size]. */
+class FixedSizeEdgeDetector(val size: Dp) : SwipeSourceDetector {
+ override fun source(
layoutSize: IntSize,
position: IntOffset,
density: Density,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
index 0a2370a..333eef7 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -80,8 +80,8 @@
/** The [Swipe]s associated to the current gesture. */
private var upOrLeftSwipe: Swipe? = null
private var downOrRightSwipe: Swipe? = null
- private var upOrLeftNoEdgeSwipe: Swipe? = null
- private var downOrRightNoEdgeSwipe: Swipe? = null
+ private var upOrLeftNoSourceSwipe: Swipe? = null
+ private var downOrRightNoSourceSwipe: Swipe? = null
/** The [UserActionResult] associated to up and down swipes. */
private var upOrLeftResult: UserActionResult? = null
@@ -117,9 +117,9 @@
}
private fun setCurrentActions(fromScene: Scene, startedPosition: Offset?, pointersDown: Int) {
- val fromEdge =
+ val fromSource =
startedPosition?.let { position ->
- layoutImpl.edgeDetector.edge(
+ layoutImpl.swipeSourceDetector.source(
fromScene.targetSize,
position.round(),
layoutImpl.density,
@@ -135,7 +135,7 @@
Orientation.Vertical -> SwipeDirection.Up
},
pointerCount = pointersDown,
- fromEdge = fromEdge,
+ fromSource = fromSource,
)
val downOrRight =
@@ -146,19 +146,19 @@
Orientation.Vertical -> SwipeDirection.Down
},
pointerCount = pointersDown,
- fromEdge = fromEdge,
+ fromSource = fromSource,
)
- if (fromEdge == null) {
+ if (fromSource == null) {
upOrLeftSwipe = null
downOrRightSwipe = null
- upOrLeftNoEdgeSwipe = upOrLeft
- downOrRightNoEdgeSwipe = downOrRight
+ upOrLeftNoSourceSwipe = upOrLeft
+ downOrRightNoSourceSwipe = downOrRight
} else {
upOrLeftSwipe = upOrLeft
downOrRightSwipe = downOrRight
- upOrLeftNoEdgeSwipe = upOrLeft.copy(fromEdge = null)
- downOrRightNoEdgeSwipe = downOrRight.copy(fromEdge = null)
+ upOrLeftNoSourceSwipe = upOrLeft.copy(fromSource = null)
+ downOrRightNoSourceSwipe = downOrRight.copy(fromSource = null)
}
}
@@ -204,9 +204,9 @@
return userActions[swipe ?: return null]
}
- upOrLeftResult = sceneToSwipePair(upOrLeftSwipe) ?: sceneToSwipePair(upOrLeftNoEdgeSwipe)
+ upOrLeftResult = sceneToSwipePair(upOrLeftSwipe) ?: sceneToSwipePair(upOrLeftNoSourceSwipe)
downOrRightResult =
- sceneToSwipePair(downOrRightSwipe) ?: sceneToSwipePair(downOrRightNoEdgeSwipe)
+ sceneToSwipePair(downOrRightSwipe) ?: sceneToSwipePair(downOrRightNoSourceSwipe)
}
/**
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index aa232df..7e0aa9c3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -29,6 +29,7 @@
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
/**
@@ -41,7 +42,8 @@
* UI code.
*
* @param state the state of this layout.
- * @param edgeDetector the edge detector used to detect which edge a swipe is started from, if any.
+ * @param swipeSourceDetector the edge detector used to detect which edge a swipe is started from,
+ * if any.
* @param transitionInterceptionThreshold used during a scene transition. For the scene to be
* intercepted, the progress value must be above the threshold, and below (1 - threshold).
* @param scenes the configuration of the different scenes of this layout.
@@ -51,14 +53,14 @@
fun SceneTransitionLayout(
state: SceneTransitionLayoutState,
modifier: Modifier = Modifier,
- edgeDetector: EdgeDetector = DefaultEdgeDetector,
+ swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector,
@FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0f,
scenes: SceneTransitionLayoutScope.() -> Unit,
) {
SceneTransitionLayoutForTesting(
state,
modifier,
- edgeDetector,
+ swipeSourceDetector,
transitionInterceptionThreshold,
onLayoutImpl = null,
scenes,
@@ -79,7 +81,8 @@
* This is called when the user commits a transition to a new scene because of a [UserAction], for
* instance by triggering back navigation or by swiping to a new scene.
* @param transitions the definition of the transitions used to animate a change of scene.
- * @param edgeDetector the edge detector used to detect which edge a swipe is started from, if any.
+ * @param swipeSourceDetector the source detector used to detect which source a swipe is started
+ * from, if any.
* @param transitionInterceptionThreshold used during a scene transition. For the scene to be
* intercepted, the progress value must be above the threshold, and below (1 - threshold).
* @param scenes the configuration of the different scenes of this layout.
@@ -90,7 +93,7 @@
onChangeScene: (SceneKey) -> Unit,
transitions: SceneTransitions,
modifier: Modifier = Modifier,
- edgeDetector: EdgeDetector = DefaultEdgeDetector,
+ swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector,
@FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0f,
scenes: SceneTransitionLayoutScope.() -> Unit,
) {
@@ -98,7 +101,7 @@
SceneTransitionLayout(
state,
modifier,
- edgeDetector,
+ swipeSourceDetector,
transitionInterceptionThreshold,
scenes,
)
@@ -338,7 +341,7 @@
data class Swipe(
val direction: SwipeDirection,
val pointerCount: Int = 1,
- val fromEdge: Edge? = null,
+ val fromSource: SwipeSource? = null,
) : UserAction {
companion object {
val Left = Swipe(SwipeDirection.Left)
@@ -356,6 +359,33 @@
}
/**
+ * The source of a Swipe.
+ *
+ * Important: This can be anything that can be returned by any [SwipeSourceDetector], but this must
+ * implement [equals] and [hashCode]. Note that those can be trivially implemented using data
+ * classes.
+ */
+interface SwipeSource {
+ // Require equals() and hashCode() to be implemented.
+ override fun equals(other: Any?): Boolean
+
+ override fun hashCode(): Int
+}
+
+interface SwipeSourceDetector {
+ /**
+ * Return the [SwipeSource] associated to [position] inside a layout of size [layoutSize], given
+ * [density] and [orientation].
+ */
+ fun source(
+ layoutSize: IntSize,
+ position: IntOffset,
+ density: Density,
+ orientation: Orientation,
+ ): SwipeSource?
+}
+
+/**
* The result of performing a [UserAction].
*
* Note: [UserActionResult] is implemented by [SceneKey], and you can also use [withDistance] to
@@ -427,7 +457,7 @@
internal fun SceneTransitionLayoutForTesting(
state: SceneTransitionLayoutState,
modifier: Modifier = Modifier,
- edgeDetector: EdgeDetector = DefaultEdgeDetector,
+ swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector,
transitionInterceptionThreshold: Float = 0f,
onLayoutImpl: ((SceneTransitionLayoutImpl) -> Unit)? = null,
scenes: SceneTransitionLayoutScope.() -> Unit,
@@ -438,7 +468,7 @@
SceneTransitionLayoutImpl(
state = state as BaseSceneTransitionLayoutState,
density = density,
- edgeDetector = edgeDetector,
+ swipeSourceDetector = swipeSourceDetector,
transitionInterceptionThreshold = transitionInterceptionThreshold,
builder = scenes,
coroutineScope = coroutineScope,
@@ -459,7 +489,7 @@
}
layoutImpl.density = density
- layoutImpl.edgeDetector = edgeDetector
+ layoutImpl.swipeSourceDetector = swipeSourceDetector
}
layoutImpl.Content(modifier)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index 982b0e0..8c5a472 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -47,7 +47,7 @@
internal class SceneTransitionLayoutImpl(
internal val state: BaseSceneTransitionLayoutState,
internal var density: Density,
- internal var edgeDetector: EdgeDetector,
+ internal var swipeSourceDetector: SwipeSourceDetector,
internal var transitionInterceptionThreshold: Float,
builder: SceneTransitionLayoutScope.() -> Unit,
private val coroutineScope: CoroutineScope,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index dc8505c..a764a527 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -320,11 +320,3 @@
anchorHeight: Boolean = true,
)
}
-
-/** The edge of a [SceneTransitionLayout]. */
-enum class Edge {
- Left,
- Right,
- Top,
- Bottom,
-}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt
index a68282a..cceaf57 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt
@@ -35,7 +35,7 @@
@Test
fun horizontalEdges() {
fun horizontalEdge(position: Int): Edge? =
- detector.edge(
+ detector.source(
layoutSize,
position = IntOffset(position, 0),
density,
@@ -53,7 +53,7 @@
@Test
fun verticalEdges() {
fun verticalEdge(position: Int): Edge? =
- detector.edge(
+ detector.source(
layoutSize,
position = IntOffset(0, position),
density,
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 066a3e4..4b3b369 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
@@ -77,7 +77,7 @@
userActions =
mapOf(
Swipe.Up to SceneB,
- Swipe(SwipeDirection.Up, fromEdge = Edge.Bottom) to SceneA
+ Swipe(SwipeDirection.Up, fromSource = Edge.Bottom) to SceneA
),
) {
Text("SceneC")
@@ -90,7 +90,7 @@
SceneTransitionLayoutImpl(
state = layoutState,
density = Density(1f),
- edgeDetector = DefaultEdgeDetector,
+ swipeSourceDetector = DefaultEdgeDetector,
transitionInterceptionThreshold = transitionInterceptionThreshold,
builder = scenesBuilder,
coroutineScope = coroutineScope,
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 4571d8e..9403358 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
@@ -90,8 +90,8 @@
mapOf(
Swipe.Down to TestScenes.SceneA,
Swipe(SwipeDirection.Down, pointerCount = 2) to TestScenes.SceneB,
- Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to TestScenes.SceneB,
- Swipe(SwipeDirection.Down, fromEdge = Edge.Top) to TestScenes.SceneB,
+ Swipe(SwipeDirection.Right, fromSource = Edge.Left) to TestScenes.SceneB,
+ Swipe(SwipeDirection.Down, fromSource = Edge.Top) to TestScenes.SceneB,
),
) {
Box(Modifier.fillMaxSize())