Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt +16 −0 Original line number Diff line number Diff line Loading @@ -658,12 +658,28 @@ private class SwipeTransition( targetOffset: Float, targetScene: SceneKey, ): OffsetAnimation { // Skip the animation if we have already reached the target scene and the overscroll does // not animate anything. val hasReachedTargetScene = (targetScene == toScene && progress >= 1f) || (targetScene == fromScene && progress <= 0f) val skipAnimation = hasReachedTargetScene && currentOverscrollSpec?.transformationSpec?.transformations?.isEmpty() == true return startOffsetAnimation { val animatable = Animatable(dragOffset, OffsetVisibilityThreshold) val isTargetGreater = targetOffset > animatable.value val job = coroutineScope .launch { // TODO(b/327249191): Refactor the code so that we don't even launch a // coroutine if we don't need to animate. if (skipAnimation) { snapToScene(targetScene) return@launch } try { val swipeSpec = transformationSpec.swipeSpec Loading packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt +19 −0 Original line number Diff line number Diff line Loading @@ -1007,4 +1007,23 @@ class DraggableHandlerTest { dragController.onDragStopped(velocity = 0f) assertTransition(isUserInputOngoing = false) } @Test fun emptyOverscrollImmediatelyAbortsSettleAnimationWhenOverProgress() = runGestureTest { // Overscrolling on scene B does nothing. layoutState.transitions = transitions { overscroll(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(2f)) assertTransition(fromScene = SceneA, toScene = SceneB, progress = 2f) // Release the finger. dragController.onDragStopped(velocity = -velocityThreshold) // Exhaust all coroutines *without advancing the clock*. Given that we are at progress >= // 100% and that the overscroll on scene B is doing nothing, we are already idle. runCurrent() assertIdle(SceneB) } } Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt +16 −0 Original line number Diff line number Diff line Loading @@ -658,12 +658,28 @@ private class SwipeTransition( targetOffset: Float, targetScene: SceneKey, ): OffsetAnimation { // Skip the animation if we have already reached the target scene and the overscroll does // not animate anything. val hasReachedTargetScene = (targetScene == toScene && progress >= 1f) || (targetScene == fromScene && progress <= 0f) val skipAnimation = hasReachedTargetScene && currentOverscrollSpec?.transformationSpec?.transformations?.isEmpty() == true return startOffsetAnimation { val animatable = Animatable(dragOffset, OffsetVisibilityThreshold) val isTargetGreater = targetOffset > animatable.value val job = coroutineScope .launch { // TODO(b/327249191): Refactor the code so that we don't even launch a // coroutine if we don't need to animate. if (skipAnimation) { snapToScene(targetScene) return@launch } try { val swipeSpec = transformationSpec.swipeSpec Loading
packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt +19 −0 Original line number Diff line number Diff line Loading @@ -1007,4 +1007,23 @@ class DraggableHandlerTest { dragController.onDragStopped(velocity = 0f) assertTransition(isUserInputOngoing = false) } @Test fun emptyOverscrollImmediatelyAbortsSettleAnimationWhenOverProgress() = runGestureTest { // Overscrolling on scene B does nothing. layoutState.transitions = transitions { overscroll(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(2f)) assertTransition(fromScene = SceneA, toScene = SceneB, progress = 2f) // Release the finger. dragController.onDragStopped(velocity = -velocityThreshold) // Exhaust all coroutines *without advancing the clock*. Given that we are at progress >= // 100% and that the overscroll on scene B is doing nothing, we are already idle. runCurrent() assertIdle(SceneB) } }