summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author omarmt <omarmt@google.com> 2024-09-12 14:34:15 +0000
committer omarmt <omarmt@google.com> 2024-10-01 12:35:22 +0000
commit408325d2d265d67b4e4e3ae119a7f8ca03fa0f9b (patch)
tree37997a61242acf14c1525d173215f00074a18a4b
parent78388235f37aa7b78070cc0bcf5a35acdc2e5411 (diff)
animateOffset can partially consume the fling velocity
When a scene is configured to disallow overscrolling (`overscrollDisabled()` is enabled), a fling gesture on that scene may not use up all of the velocity. The unused velocity can then be passed on to the ancestor of the component. Test: atest DraggableHandlerTest Bug: 336710600 Flag: com.android.systemui.scene_container Change-Id: Ia1b0620fe37cfaf5b339d1e87c38ba5c22be95e8
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt11
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt23
2 files changed, 30 insertions, 4 deletions
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
index 18d8328b2856..205267da151a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
@@ -28,10 +28,8 @@ import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.content.state.TransitionState.HasOverscrollProperties.Companion.DistanceUnspecified
import com.android.compose.nestedscroll.SuspendedValue
-import kotlinx.coroutines.CancellationException
import kotlin.math.absoluteValue
import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.withTimeout
internal fun createSwipeAnimation(
layoutState: MutableSceneTransitionLayoutStateImpl,
@@ -425,6 +423,9 @@ internal class SwipeAnimation<T : ContentKey>(
// Immediately stop this transition if we are bouncing on a content that
// does not bounce.
if (!contentTransition.isWithinProgressRange(progress)) {
+ // We are no longer able to consume the velocity, the rest can be
+ // consumed by another component in the hierarchy.
+ velocityConsumed.complete(initialVelocity - velocity)
throw SnapException()
}
}
@@ -433,8 +434,10 @@ internal class SwipeAnimation<T : ContentKey>(
} catch (_: SnapException) {
/* Ignore. */
} finally {
- // The animation consumed the whole available velocity
- velocityConsumed.complete(initialVelocity)
+ if (!velocityConsumed.isCompleted) {
+ // The animation consumed the whole available velocity
+ velocityConsumed.complete(initialVelocity)
+ }
}
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index c0524b730ab8..2c41b35da998 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -1177,6 +1177,29 @@ class DraggableHandlerTest {
}
@Test
+ fun emptyOverscrollAbortsSettleAnimationAndExposeTheConsumedVelocity() = runGestureTest {
+ // Overscrolling on scene B does nothing.
+ layoutState.transitions = transitions { overscrollDisabled(SceneB, Orientation.Vertical) }
+
+ // Swipe up to scene B at progress = 200%.
+ val middle = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)
+ val dragController = onDragStarted(startedPosition = middle, overSlop = up(0.99f))
+ assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.99f)
+
+ // Release the finger.
+ dragController.onDragStoppedAnimateNow(
+ velocity = -velocityThreshold,
+ onAnimationStart = { assertTransition(fromScene = SceneA, toScene = SceneB) },
+ onAnimationEnd = { consumedVelocity ->
+ // Our progress value was 0.99f and it is coerced in `[0..1]` (overscrollDisabled).
+ // Some of the velocity will be used for animation, but not all of it.
+ assertThat(consumedVelocity).isLessThan(0f)
+ assertThat(consumedVelocity).isGreaterThan(-velocityThreshold)
+ },
+ )
+ }
+
+ @Test
fun overscroll_releaseBetween0And100Percent_up() = runGestureTest {
// Make scene B overscrollable.
layoutState.transitions = transitions {