summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author omarmt <omarmt@google.com> 2024-02-06 15:18:25 +0000
committer omarmt <omarmt@google.com> 2024-02-08 10:39:40 +0000
commit1d967cdccd9d08df38d2ab8a387c75b860e6bc89 (patch)
treedffc6fe6576aa31f89ca53238bdbf7b57649dfe8
parent2c47d801c40824184bacb5b9c010b0473ac726bf (diff)
Make SwipeTransition an implementation detail of SceneGestureHandler
In this refactor the class has been extracted and made private. Test: atest SceneGestureHandlerTest Bug: 317063114 Flag: NA Change-Id: Ia6a610eeee36d1b2d0e72846250f14808c8022eb
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt289
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt8
2 files changed, 164 insertions, 133 deletions
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 b3d2bc994c08..90dfa108ab24 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
@@ -46,7 +46,7 @@ internal class SceneGestureHandler(
val draggable: DraggableHandler = SceneDraggableHandler(this)
private var _swipeTransition: SwipeTransition? = null
- internal var swipeTransition: SwipeTransition
+ private var swipeTransition: SwipeTransition
get() = _swipeTransition ?: error("SwipeTransition needs to be initialized")
set(value) {
_swipeTransition = value
@@ -149,7 +149,17 @@ internal class SceneGestureHandler(
val result =
findUserActionResult(fromScene, directionOffset = overSlop, updateSwipesResults = true)
?: return
- updateTransition(SwipeTransition(fromScene, result), force = true)
+ val newSwipeTransition =
+ SwipeTransition(
+ fromScene = fromScene,
+ result = result,
+ upOrLeftResult = upOrLeftResult,
+ downOrRightResult = downOrRightResult,
+ layoutImpl = layoutImpl,
+ orientation = orientation
+ )
+
+ updateTransition(newSwipeTransition, force = true)
}
private fun updateSwipes(fromScene: Scene, startedPosition: Offset?, pointersDown: Int) {
@@ -242,11 +252,18 @@ internal class SceneGestureHandler(
result.toScene != swipeTransition.toScene ||
result.transitionKey != swipeTransition.key
) {
- updateTransition(
- SwipeTransition(fromScene, result).apply {
- this.dragOffset = swipeTransition.dragOffset
- }
- )
+ val newSwipeTransition =
+ SwipeTransition(
+ fromScene = fromScene,
+ result = result,
+ upOrLeftResult = upOrLeftResult,
+ downOrRightResult = downOrRightResult,
+ layoutImpl = layoutImpl,
+ orientation = orientation
+ )
+ .apply { dragOffset = swipeTransition.dragOffset }
+
+ updateTransition(newSwipeTransition)
}
}
@@ -354,18 +371,6 @@ internal class SceneGestureHandler(
}
}
- private fun computeAbsoluteDistance(
- fromScene: Scene,
- result: UserActionResult,
- ): Float {
- return if (result == upOrLeftResult) {
- -fromScene.getAbsoluteDistance(result.distance)
- } else {
- check(result == downOrRightResult)
- fromScene.getAbsoluteDistance(result.distance)
- }
- }
-
internal fun onDragStopped(velocity: Float, canChangeScene: Boolean) {
// The state was changed since the drag started; don't do anything.
if (!isDrivingTransition) {
@@ -438,11 +443,18 @@ internal class SceneGestureHandler(
return
}
- updateTransition(
- SwipeTransition(fromScene, result).apply {
- _currentScene = swipeTransition._currentScene
- }
- )
+ val newSwipeTransition =
+ SwipeTransition(
+ fromScene = fromScene,
+ result = result,
+ upOrLeftResult = upOrLeftResult,
+ downOrRightResult = downOrRightResult,
+ layoutImpl = layoutImpl,
+ orientation = orientation
+ )
+ .apply { _currentScene = swipeTransition._currentScene }
+
+ updateTransition(newSwipeTransition)
animateTo(targetScene = fromScene, targetOffset = 0f)
} else {
// We were between two scenes: animate to the initial scene.
@@ -486,136 +498,153 @@ internal class SceneGestureHandler(
}
}
- private fun SwipeTransition(fromScene: Scene, result: UserActionResult): SwipeTransition {
- return SwipeTransition(
- result.transitionKey,
- fromScene,
- layoutImpl.scene(result.toScene),
- computeAbsoluteDistance(fromScene, result),
- )
+ companion object {
+ private const val TAG = "SceneGestureHandler"
}
+}
- internal class SwipeTransition(
- val key: TransitionKey?,
- val _fromScene: Scene,
- val _toScene: Scene,
- /**
- * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is
- * above or to the left of [toScene].
- */
- val distance: Float,
- ) : TransitionState.Transition(_fromScene.key, _toScene.key) {
- var _currentScene by mutableStateOf(_fromScene)
- override val currentScene: SceneKey
- get() = _currentScene.key
-
- override val progress: Float
- get() {
- val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
- return offset / distance
- }
-
- override val isInitiatedByUserInput = true
-
- /** The current offset caused by the drag gesture. */
- var dragOffset by mutableFloatStateOf(0f)
+private fun SwipeTransition(
+ fromScene: Scene,
+ result: UserActionResult,
+ upOrLeftResult: UserActionResult?,
+ downOrRightResult: UserActionResult?,
+ layoutImpl: SceneTransitionLayoutImpl,
+ orientation: Orientation,
+): SwipeTransition {
+ val userActionDistance = result.distance ?: DefaultSwipeDistance
+ val absoluteDistance =
+ with(userActionDistance) {
+ layoutImpl.density.absoluteDistance(fromScene.targetSize, orientation)
+ }
- /**
- * Whether the offset is animated (the user lifted their finger) or if it is driven by
- * gesture.
- */
- var isAnimatingOffset by mutableStateOf(false)
+ return SwipeTransition(
+ key = result.transitionKey,
+ _fromScene = fromScene,
+ _toScene = layoutImpl.scene(result.toScene),
+ distance =
+ when (result) {
+ upOrLeftResult -> -absoluteDistance
+ downOrRightResult -> absoluteDistance
+ else -> error("Unknown result $result ($upOrLeftResult $downOrRightResult)")
+ },
+ )
+}
- // If we are not animating offset, it means the offset is being driven by the user's finger.
- override val isUserInputOngoing: Boolean
- get() = !isAnimatingOffset
+private class SwipeTransition(
+ val key: TransitionKey?,
+ val _fromScene: Scene,
+ val _toScene: Scene,
+ /**
+ * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is above
+ * or to the left of [toScene]
+ */
+ val distance: Float,
+) : TransitionState.Transition(_fromScene.key, _toScene.key) {
+ var _currentScene by mutableStateOf(_fromScene)
+ override val currentScene: SceneKey
+ get() = _currentScene.key
+
+ override val progress: Float
+ get() {
+ val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
+ return offset / distance
+ }
- /** The animatable used to animate the offset once the user lifted its finger. */
- val offsetAnimatable = Animatable(0f, OffsetVisibilityThreshold)
+ override val isInitiatedByUserInput = true
- /** Job to check that there is at most one offset animation in progress. */
- private var offsetAnimationJob: Job? = null
+ /** The current offset caused by the drag gesture. */
+ var dragOffset by mutableFloatStateOf(0f)
- /** The spec to use when animating this transition to either [fromScene] or [toScene]. */
- lateinit var swipeSpec: SpringSpec<Float>
+ /**
+ * Whether the offset is animated (the user lifted their finger) or if it is driven by gesture.
+ */
+ var isAnimatingOffset by mutableStateOf(false)
- /** Ends any previous [offsetAnimationJob] and runs the new [job]. */
- private fun startOffsetAnimation(job: () -> Job) {
- cancelOffsetAnimation()
- offsetAnimationJob = job()
- }
+ // If we are not animating offset, it means the offset is being driven by the user's finger.
+ override val isUserInputOngoing: Boolean
+ get() = !isAnimatingOffset
- /** Cancel any ongoing offset animation. */
- // TODO(b/317063114) This should be a suspended function to avoid multiple jobs running at
- // the same time.
- fun cancelOffsetAnimation() {
- offsetAnimationJob?.cancel()
- finishOffsetAnimation()
- }
+ /** The animatable used to animate the offset once the user lifted its finger. */
+ val offsetAnimatable = Animatable(0f, OffsetVisibilityThreshold)
- fun finishOffsetAnimation() {
- if (isAnimatingOffset) {
- isAnimatingOffset = false
- dragOffset = offsetAnimatable.value
- }
- }
+ /** Job to check that there is at most one offset animation in progress. */
+ private var offsetAnimationJob: Job? = null
- fun animateOffset(
- // TODO(b/317063114) The CoroutineScope should be removed.
- coroutineScope: CoroutineScope,
- initialVelocity: Float,
- targetOffset: Float,
- onAnimationCompleted: () -> Unit,
- ) {
- startOffsetAnimation {
- coroutineScope.launch {
- animateOffset(targetOffset, initialVelocity)
- onAnimationCompleted()
- }
- }
- }
+ /** The spec to use when animating this transition to either [fromScene] or [toScene]. */
+ lateinit var swipeSpec: SpringSpec<Float>
- private suspend fun animateOffset(targetOffset: Float, initialVelocity: Float) {
- if (!isAnimatingOffset) {
- offsetAnimatable.snapTo(dragOffset)
- }
- isAnimatingOffset = true
+ /** Ends any previous [offsetAnimationJob] and runs the new [job]. */
+ private fun startOffsetAnimation(job: () -> Job) {
+ cancelOffsetAnimation()
+ offsetAnimationJob = job()
+ }
- offsetAnimatable.animateTo(
- targetValue = targetOffset,
- animationSpec = swipeSpec,
- initialVelocity = initialVelocity,
- )
+ /** Cancel any ongoing offset animation. */
+ // TODO(b/317063114) This should be a suspended function to avoid multiple jobs running at
+ // the same time.
+ fun cancelOffsetAnimation() {
+ offsetAnimationJob?.cancel()
+ finishOffsetAnimation()
+ }
- finishOffsetAnimation()
+ fun finishOffsetAnimation() {
+ if (isAnimatingOffset) {
+ isAnimatingOffset = false
+ dragOffset = offsetAnimatable.value
}
}
- companion object {
- private const val TAG = "SceneGestureHandler"
+ fun animateOffset(
+ // TODO(b/317063114) The CoroutineScope should be removed.
+ coroutineScope: CoroutineScope,
+ initialVelocity: Float,
+ targetOffset: Float,
+ onAnimationCompleted: () -> Unit,
+ ) {
+ startOffsetAnimation {
+ coroutineScope.launch {
+ animateOffset(targetOffset, initialVelocity)
+ onAnimationCompleted()
+ }
+ }
}
- private object DefaultSwipeDistance : UserActionDistance {
- override fun Density.absoluteDistance(
- fromSceneSize: IntSize,
- orientation: Orientation,
- ): Float {
- return when (orientation) {
- Orientation.Horizontal -> fromSceneSize.width
- Orientation.Vertical -> fromSceneSize.height
- }.toFloat()
+ private suspend fun animateOffset(targetOffset: Float, initialVelocity: Float) {
+ if (!isAnimatingOffset) {
+ offsetAnimatable.snapTo(dragOffset)
}
+ isAnimatingOffset = true
+
+ offsetAnimatable.animateTo(
+ targetValue = targetOffset,
+ animationSpec = swipeSpec,
+ initialVelocity = initialVelocity,
+ )
+
+ finishOffsetAnimation()
}
+}
- /** The [Swipe] associated to a given fromScene, startedPosition and pointersDown. */
- private class Swipes(
- val upOrLeft: Swipe?,
- val downOrRight: Swipe?,
- val upOrLeftNoSource: Swipe?,
- val downOrRightNoSource: Swipe?,
- )
+private object DefaultSwipeDistance : UserActionDistance {
+ override fun Density.absoluteDistance(
+ fromSceneSize: IntSize,
+ orientation: Orientation,
+ ): Float {
+ return when (orientation) {
+ Orientation.Horizontal -> fromSceneSize.width
+ Orientation.Vertical -> fromSceneSize.height
+ }.toFloat()
+ }
}
+/** The [Swipe] associated to a given fromScene, startedPosition and pointersDown. */
+private class Swipes(
+ val upOrLeft: Swipe?,
+ val downOrRight: Swipe?,
+ val upOrLeftNoSource: Swipe?,
+ val downOrRightNoSource: Swipe?,
+)
+
private class SceneDraggableHandler(
private val gestureHandler: SceneGestureHandler,
) : DraggableHandler {
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 dacbdb484d0c..c91d29880ffb 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
@@ -127,6 +127,9 @@ class SceneGestureHandlerTest {
val progress: Float
get() = (transitionState as Transition).progress
+ val isUserInputOngoing: Boolean
+ get() = (transitionState as Transition).isUserInputOngoing
+
fun advanceUntilIdle() {
testScope.testScheduler.advanceUntilIdle()
}
@@ -538,12 +541,11 @@ class SceneGestureHandlerTest {
onDragStopped(velocity = velocityThreshold)
assertTransition(currentScene = SceneC)
- assertThat(sceneGestureHandler.isDrivingTransition).isTrue()
- assertThat(sceneGestureHandler.swipeTransition.isAnimatingOffset).isTrue()
+ assertThat(isUserInputOngoing).isFalse()
// Start a new gesture while the offset is animating
onDragStartedImmediately()
- assertThat(sceneGestureHandler.swipeTransition.isAnimatingOffset).isFalse()
+ assertThat(isUserInputOngoing).isTrue()
}
@Test