Loading quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeController.kt +42 −72 Original line number Diff line number Diff line Loading @@ -21,15 +21,14 @@ import android.content.Context import androidx.annotation.VisibleForTesting import androidx.core.animation.doOnEnd import androidx.dynamicanimation.animation.SpringForce import com.android.launcher3.R import com.android.launcher3.anim.AnimatedFloat import com.android.launcher3.anim.SpringAnimationBuilder import com.android.launcher3.taskbar.TaskbarActivityContext import com.android.launcher3.taskbar.TaskbarThresholdUtils import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.StartState.COLLAPSED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.StartState.EXPANDED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.StartState.STASHED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.StartState.UNKNOWN import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.BarState.COLLAPSED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.BarState.EXPANDED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.BarState.STASHED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.BarState.UNKNOWN import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController import com.android.launcher3.touch.OverScroll Loading @@ -46,11 +45,9 @@ class BubbleBarSwipeController { private val animatedSwipeTranslation = AnimatedFloat(this::onSwipeUpdate) private val unstashThreshold: Int private val expandThreshold: Int private val maxOverscroll: Int private val stashThreshold: Int private var swipeState: SwipeState = SwipeState() private var swipeState: SwipeState = SwipeState(startState = UNKNOWN) constructor(tac: TaskbarActivityContext) : this(tac, DefaultDimensionProvider(tac)) Loading @@ -58,9 +55,7 @@ class BubbleBarSwipeController { constructor(context: Context, dimensionProvider: DimensionProvider) { this.context = context unstashThreshold = dimensionProvider.unstashThreshold expandThreshold = dimensionProvider.expandThreshold maxOverscroll = dimensionProvider.maxOverscroll stashThreshold = dimensionProvider.stashThreshold } fun init(bubbleControllers: BubbleControllers) { Loading @@ -80,7 +75,7 @@ class BubbleBarSwipeController { bubbleStashController.isBubbleBarVisible() -> COLLAPSED else -> UNKNOWN } swipeState = SwipeState(startState = startState) swipeState = SwipeState(startState = startState, currentState = startState) } /** Update swipe distance to [dy] */ Loading @@ -90,47 +85,26 @@ class BubbleBarSwipeController { } animatedSwipeTranslation.updateValue(dy) val prevState = swipeState // We can pass unstash threshold once per gesture, keep it true if it happened once val passedUnstashThreshold = isUnstash(dy) || prevState.passedUnstashThreshold // Expand happens at the end of the gesture, always keep the current value val passedExpandThreshold = isExpand(dy) // Stash happens at the end of the gesture, always keep the current value val passedStashThreshold = isStash(dy) if ( passedUnstashThreshold != prevState.passedUnstashThreshold || passedExpandThreshold != prevState.passedExpandThreshold || passedStashThreshold != prevState.passedStashThreshold ) { swipeState = swipeState.copy( passedUnstashThreshold = passedUnstashThreshold, passedExpandThreshold = passedExpandThreshold, passedStashThreshold = passedStashThreshold, ) } if ( swipeState.startState == STASHED && swipeState.passedUnstashThreshold && !prevState.passedUnstashThreshold ) { swipeState.passedUnstash = isUnstash(dy) // Tracking swipe gesture if we pass unstash threshold at least once during gesture swipeState.isSwipe = swipeState.isSwipe || swipeState.passedUnstash when { canUnstash() && swipeState.passedUnstash -> { swipeState.currentState = COLLAPSED bubbleStashController.showBubbleBar(expandBubbles = false) } canStash() && !swipeState.passedUnstash -> { swipeState.currentState = STASHED bubbleStashController.stashBubbleBar() } } } /** Finish tracking swipe gesture. Animate views back to resting state */ fun finish() { when { swipeState.passedExpandThreshold && swipeState.startState in setOf(STASHED, COLLAPSED) -> { if (swipeState.passedUnstash && swipeState.startState in setOf(STASHED, COLLAPSED)) { bubbleStashController.showBubbleBar(expandBubbles = true) } swipeState.passedStashThreshold && swipeState.startState == COLLAPSED -> { bubbleStashController.stashBubbleBar() } } if (animatedSwipeTranslation.value == 0f) { reset() } else { Loading @@ -140,15 +114,21 @@ class BubbleBarSwipeController { /** Returns `true` if we are tracking a swipe gesture */ fun isSwipeGesture(): Boolean { return swipeState.passedUnstashThreshold || swipeState.passedExpandThreshold || swipeState.passedStashThreshold return swipeState.isSwipe } private fun canHandleSwipe(dy: Float): Boolean { return when (swipeState.startState) { STASHED -> dy < 0 // stashed bar only handles swipe up COLLAPSED -> true // collapsed bar can be swiped in either direction STASHED -> { if (swipeState.currentState == COLLAPSED) { // if we have unstashed the bar, allow swipe in both directions true } else { // otherwise, only allow swipe up on stash handle dy < 0 } } COLLAPSED -> dy < 0 // collapsed bar can only be swiped up UNKNOWN, EXPANDED -> false // expanded bar can't be swiped } Loading @@ -158,12 +138,13 @@ class BubbleBarSwipeController { return dy < -unstashThreshold } private fun isExpand(dy: Float): Boolean { return dy < -expandThreshold private fun canStash(): Boolean { // Only allow stashing if we started from stashed state return swipeState.startState == STASHED && swipeState.currentState == COLLAPSED } private fun isStash(dy: Float): Boolean { return dy > stashThreshold private fun canUnstash(): Boolean { return swipeState.currentState == STASHED } private fun reset() { Loading @@ -175,7 +156,7 @@ class BubbleBarSwipeController { } } springAnimation = null swipeState = SwipeState() swipeState = SwipeState(startState = UNKNOWN) } private fun onSwipeUpdate(value: Float) { Loading @@ -197,13 +178,13 @@ class BubbleBarSwipeController { } internal data class SwipeState( val startState: StartState = UNKNOWN, val passedUnstashThreshold: Boolean = false, val passedExpandThreshold: Boolean = false, val passedStashThreshold: Boolean = false, val startState: BarState, var currentState: BarState = UNKNOWN, var passedUnstash: Boolean = false, var isSwipe: Boolean = false, ) internal enum class StartState { internal enum class BarState { UNKNOWN, STASHED, COLLAPSED, Loading @@ -214,17 +195,13 @@ class BubbleBarSwipeController { @VisibleForTesting interface DimensionProvider { val unstashThreshold: Int val expandThreshold: Int val maxOverscroll: Int val stashThreshold: Int } private class DefaultDimensionProvider(taskbarActivityContext: TaskbarActivityContext) : DimensionProvider { override val unstashThreshold: Int override val expandThreshold: Int override val maxOverscroll: Int override val stashThreshold: Int init { val resources = taskbarActivityContext.resources Loading @@ -233,14 +210,7 @@ class BubbleBarSwipeController { resources, taskbarActivityContext.deviceProfile, ) // TODO(325673340): review threshold with ux expandThreshold = TaskbarThresholdUtils.getAppWindowThreshold( resources, taskbarActivityContext.deviceProfile, ) maxOverscroll = taskbarActivityContext.deviceProfile.heightPx - unstashThreshold stashThreshold = resources.getDimensionPixelSize(R.dimen.taskbar_to_nav_threshold) } } } quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeControllerTest.kt +58 −91 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.atLeastOnce import org.mockito.kotlin.never import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever Loading @@ -45,15 +46,11 @@ class BubbleBarSwipeControllerTest { companion object { const val UNSTASH_THRESHOLD = 100 const val EXPAND_THRESHOLD = 200 const val MAX_OVERSCROLL = 300 const val STASH_THRESHOLD = 50 const val UP_BELOW_UNSTASH = -UNSTASH_THRESHOLD + 10f const val UP_ABOVE_UNSTASH = -UNSTASH_THRESHOLD - 10f const val UP_ABOVE_EXPAND = -EXPAND_THRESHOLD - 10f const val DOWN_UNDER_STASH = STASH_THRESHOLD - 10f const val DOWN_OVER_STASH = STASH_THRESHOLD + 10f const val DOWN = UNSTASH_THRESHOLD + 10f } private val context = ApplicationProvider.getApplicationContext<Context>() Loading @@ -80,14 +77,8 @@ class BubbleBarSwipeControllerTest { override val unstashThreshold: Int get() = UNSTASH_THRESHOLD override val expandThreshold: Int get() = EXPAND_THRESHOLD override val maxOverscroll: Int get() = MAX_OVERSCROLL override val stashThreshold: Int get() = STASH_THRESHOLD } bubbleBarSwipeController = BubbleBarSwipeController(context, dimensionProvider) Loading Loading @@ -134,36 +125,12 @@ class BubbleBarSwipeControllerTest { testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_UNSTASH) } @Test fun swipeUp_stashedBar_aboveExpandThreshold_viewsHaveDampedTranslation() { setUpStashedBar() testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_EXPAND) } @Test fun swipeUp_collapsedBar_aboveUnstashThreshold_viewsHaveDampedTranslation() { setUpCollapsedBar() testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_UNSTASH) } @Test fun swipeUp_collapsedBar_aboveExpandThreshold_viewsHaveDampedTranslation() { setUpCollapsedBar() testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_EXPAND) } @Test fun swipeDown_collapsedBar_belowStashThreshold_viewsHaveDampedTranslation() { setUpCollapsedBar() testViewsHaveDampedTranslationOnSwipe(DOWN_UNDER_STASH) } @Test fun swipeDown_collapsedBar_overStashThreshold_viewsHaveDampedTranslation() { setUpCollapsedBar() testViewsHaveDampedTranslationOnSwipe(DOWN_OVER_STASH) } // endregion // region Test that translation on views is reset on finish Loading Loading @@ -202,30 +169,12 @@ class BubbleBarSwipeControllerTest { testViewsTranslationResetOnFinish(UP_ABOVE_UNSTASH) } @Test fun swipeUp_stashedBar_aboveExpandThreshold_animateTranslationToZeroOnFinish() { setUpStashedBar() testViewsTranslationResetOnFinish(UP_ABOVE_EXPAND) } @Test fun swipeUp_collapsedBar_aboveUnstashThreshold_animateTranslationToZeroOnFinish() { setUpCollapsedBar() testViewsTranslationResetOnFinish(UP_ABOVE_UNSTASH) } @Test fun swipeUp_collapsedBar_aboveExpandThreshold_animateTranslationToZeroOnFinish() { setUpCollapsedBar() testViewsTranslationResetOnFinish(UP_ABOVE_EXPAND) } @Test fun swipeDown_collapsedBar_aboveStashThreshold_animateTranslationToZeroOnFinish() { setUpCollapsedBar() testViewsTranslationResetOnFinish(DOWN_OVER_STASH) } // endregion // region Test swipe interactions on stashed bar Loading @@ -251,7 +200,7 @@ class BubbleBarSwipeControllerTest { } @Test fun swipeUp_stashedBar_aboveUnstashThreshold_unstashBubbleBar() { fun swipeUp_stashedBar_overUnstashThreshold_unstashBubbleBar() { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() Loading @@ -271,50 +220,45 @@ class BubbleBarSwipeControllerTest { } @Test fun swipeUp_stashedBar_overUnstashThresholdMultipleTimes_unstashBubbleBarOnce() { fun swipeUp_stashedBar_overUnstashThresholdMultipleTimes_unstashesMultipleTimes() { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } verify(bubbleStashController).showBubbleBar(expandBubbles = false) verify(bubbleStashController).stashBubbleBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } verify(bubbleStashController, times(2)).showBubbleBar(expandBubbles = false) } @Test fun swipeUp_stashedBar_overExpandThreshold_doesNotExpandBeforeFinish() { fun swipeUp_stashedBar_releaseOverUnstashThreshold_expandsBar() { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } verify(bubbleStashController).showBubbleBar(expandBubbles = false) verify(bubbleStashController, never()).showBubbleBar(expandBubbles = true) getInstrumentation().runOnMainSync { bubbleBarSwipeController.finish() } verify(bubbleStashController).showBubbleBar(expandBubbles = true) } @Test fun swipeUp_stashedBar_overExpandThreshold_isSwipeGestureTrue() { fun swipeUp_stashedBar_overUnstashReleaseBelowUnstash_doesNotExpandBar() { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND) } assertThat(bubbleBarSwipeController.isSwipeGesture()).isTrue() } @Test fun swipeUp_stashedBar_overExpandThresholdAndBackDown_doesNotExpandAfterFinish() { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } verify(bubbleStashController).showBubbleBar(expandBubbles = false) getInstrumentation().runOnMainSync { bubbleBarSwipeController.finish() } verify(bubbleStashController).showBubbleBar(expandBubbles = false) getInstrumentation().runOnMainSync { bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH) bubbleBarSwipeController.finish() } verify(bubbleStashController, never()).showBubbleBar(expandBubbles = true) } @Test Loading @@ -322,7 +266,7 @@ class BubbleBarSwipeControllerTest { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN_OVER_STASH) bubbleBarSwipeController.swipeTo(DOWN) } verify(bubbleStashedHandleViewController, never()).setTranslationYForSwipe(any()) verify(bubbleBarViewController, never()).setTranslationYForSwipe(any()) Loading @@ -338,8 +282,8 @@ class BubbleBarSwipeControllerTest { setUpExpandedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND) bubbleBarSwipeController.swipeTo(DOWN_OVER_STASH) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) bubbleBarSwipeController.swipeTo(DOWN) bubbleBarSwipeController.finish() } verify(bubbleStashedHandleViewController, never()).setTranslationYForSwipe(any()) Loading @@ -352,46 +296,69 @@ class BubbleBarSwipeControllerTest { // region Test swipe interactions on collapsed bar @Test fun swipeDown_collapsedBar_underStashThreshold_doesNotHideBar() { fun swipeUp_collapsedBar_doesNotShowBarDuringDrag() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN_UNDER_STASH) bubbleBarSwipeController.finish() bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } verify(bubbleStashController, never()).stashBubbleBar() verify(bubbleStashController, never()).showBubbleBar(any()) } @Test fun swipeDown_collapsedBar_overStashThreshold_doesNotHideBarBeforeFinish() { fun swipeUp_collapsedBar_belowUnstashThreshold_isSwipeGestureFalse() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN_OVER_STASH) bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH) } verify(bubbleStashController, never()).stashBubbleBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.finish() } verify(bubbleStashController).stashBubbleBar() assertThat(bubbleBarSwipeController.isSwipeGesture()).isFalse() } @Test fun swipeDown_collapsedBar_underStashThreshold_isSwipeGestureFalse() { fun swipeUp_collapsedBar_overUnstashThreshold_isSwipeGestureTrue() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN_UNDER_STASH) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } assertThat(bubbleBarSwipeController.isSwipeGesture()).isFalse() assertThat(bubbleBarSwipeController.isSwipeGesture()).isTrue() } @Test fun swipeDown_collapsedBar_overStashThreshold_isSwipeGestureTrue() { fun swipeUp_collapsedBar_finishOverUnstashThreshold_expandsBar() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN_OVER_STASH) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) bubbleBarSwipeController.finish() } assertThat(bubbleBarSwipeController.isSwipeGesture()).isTrue() verify(bubbleStashController).showBubbleBar(expandBubbles = true) } @Test fun swipeUp_collapsedBar_finishBelowUnstashThreshold_doesNotExpandBar() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH) bubbleBarSwipeController.finish() } verify(bubbleStashController, never()).showBubbleBar(any()) } @Test fun swipeDown_collapsedBar_swipeIgnored() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN) } verify(bubbleStashedHandleViewController, never()).setTranslationYForSwipe(any()) verify(bubbleBarViewController, never()).setTranslationYForSwipe(any()) verify(bubbleStashController, never()).showBubbleBar(any()) verify(bubbleStashController, never()).stashBubbleBar() } // endregion Loading Loading
quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeController.kt +42 −72 Original line number Diff line number Diff line Loading @@ -21,15 +21,14 @@ import android.content.Context import androidx.annotation.VisibleForTesting import androidx.core.animation.doOnEnd import androidx.dynamicanimation.animation.SpringForce import com.android.launcher3.R import com.android.launcher3.anim.AnimatedFloat import com.android.launcher3.anim.SpringAnimationBuilder import com.android.launcher3.taskbar.TaskbarActivityContext import com.android.launcher3.taskbar.TaskbarThresholdUtils import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.StartState.COLLAPSED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.StartState.EXPANDED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.StartState.STASHED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.StartState.UNKNOWN import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.BarState.COLLAPSED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.BarState.EXPANDED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.BarState.STASHED import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController.BarState.UNKNOWN import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController import com.android.launcher3.touch.OverScroll Loading @@ -46,11 +45,9 @@ class BubbleBarSwipeController { private val animatedSwipeTranslation = AnimatedFloat(this::onSwipeUpdate) private val unstashThreshold: Int private val expandThreshold: Int private val maxOverscroll: Int private val stashThreshold: Int private var swipeState: SwipeState = SwipeState() private var swipeState: SwipeState = SwipeState(startState = UNKNOWN) constructor(tac: TaskbarActivityContext) : this(tac, DefaultDimensionProvider(tac)) Loading @@ -58,9 +55,7 @@ class BubbleBarSwipeController { constructor(context: Context, dimensionProvider: DimensionProvider) { this.context = context unstashThreshold = dimensionProvider.unstashThreshold expandThreshold = dimensionProvider.expandThreshold maxOverscroll = dimensionProvider.maxOverscroll stashThreshold = dimensionProvider.stashThreshold } fun init(bubbleControllers: BubbleControllers) { Loading @@ -80,7 +75,7 @@ class BubbleBarSwipeController { bubbleStashController.isBubbleBarVisible() -> COLLAPSED else -> UNKNOWN } swipeState = SwipeState(startState = startState) swipeState = SwipeState(startState = startState, currentState = startState) } /** Update swipe distance to [dy] */ Loading @@ -90,47 +85,26 @@ class BubbleBarSwipeController { } animatedSwipeTranslation.updateValue(dy) val prevState = swipeState // We can pass unstash threshold once per gesture, keep it true if it happened once val passedUnstashThreshold = isUnstash(dy) || prevState.passedUnstashThreshold // Expand happens at the end of the gesture, always keep the current value val passedExpandThreshold = isExpand(dy) // Stash happens at the end of the gesture, always keep the current value val passedStashThreshold = isStash(dy) if ( passedUnstashThreshold != prevState.passedUnstashThreshold || passedExpandThreshold != prevState.passedExpandThreshold || passedStashThreshold != prevState.passedStashThreshold ) { swipeState = swipeState.copy( passedUnstashThreshold = passedUnstashThreshold, passedExpandThreshold = passedExpandThreshold, passedStashThreshold = passedStashThreshold, ) } if ( swipeState.startState == STASHED && swipeState.passedUnstashThreshold && !prevState.passedUnstashThreshold ) { swipeState.passedUnstash = isUnstash(dy) // Tracking swipe gesture if we pass unstash threshold at least once during gesture swipeState.isSwipe = swipeState.isSwipe || swipeState.passedUnstash when { canUnstash() && swipeState.passedUnstash -> { swipeState.currentState = COLLAPSED bubbleStashController.showBubbleBar(expandBubbles = false) } canStash() && !swipeState.passedUnstash -> { swipeState.currentState = STASHED bubbleStashController.stashBubbleBar() } } } /** Finish tracking swipe gesture. Animate views back to resting state */ fun finish() { when { swipeState.passedExpandThreshold && swipeState.startState in setOf(STASHED, COLLAPSED) -> { if (swipeState.passedUnstash && swipeState.startState in setOf(STASHED, COLLAPSED)) { bubbleStashController.showBubbleBar(expandBubbles = true) } swipeState.passedStashThreshold && swipeState.startState == COLLAPSED -> { bubbleStashController.stashBubbleBar() } } if (animatedSwipeTranslation.value == 0f) { reset() } else { Loading @@ -140,15 +114,21 @@ class BubbleBarSwipeController { /** Returns `true` if we are tracking a swipe gesture */ fun isSwipeGesture(): Boolean { return swipeState.passedUnstashThreshold || swipeState.passedExpandThreshold || swipeState.passedStashThreshold return swipeState.isSwipe } private fun canHandleSwipe(dy: Float): Boolean { return when (swipeState.startState) { STASHED -> dy < 0 // stashed bar only handles swipe up COLLAPSED -> true // collapsed bar can be swiped in either direction STASHED -> { if (swipeState.currentState == COLLAPSED) { // if we have unstashed the bar, allow swipe in both directions true } else { // otherwise, only allow swipe up on stash handle dy < 0 } } COLLAPSED -> dy < 0 // collapsed bar can only be swiped up UNKNOWN, EXPANDED -> false // expanded bar can't be swiped } Loading @@ -158,12 +138,13 @@ class BubbleBarSwipeController { return dy < -unstashThreshold } private fun isExpand(dy: Float): Boolean { return dy < -expandThreshold private fun canStash(): Boolean { // Only allow stashing if we started from stashed state return swipeState.startState == STASHED && swipeState.currentState == COLLAPSED } private fun isStash(dy: Float): Boolean { return dy > stashThreshold private fun canUnstash(): Boolean { return swipeState.currentState == STASHED } private fun reset() { Loading @@ -175,7 +156,7 @@ class BubbleBarSwipeController { } } springAnimation = null swipeState = SwipeState() swipeState = SwipeState(startState = UNKNOWN) } private fun onSwipeUpdate(value: Float) { Loading @@ -197,13 +178,13 @@ class BubbleBarSwipeController { } internal data class SwipeState( val startState: StartState = UNKNOWN, val passedUnstashThreshold: Boolean = false, val passedExpandThreshold: Boolean = false, val passedStashThreshold: Boolean = false, val startState: BarState, var currentState: BarState = UNKNOWN, var passedUnstash: Boolean = false, var isSwipe: Boolean = false, ) internal enum class StartState { internal enum class BarState { UNKNOWN, STASHED, COLLAPSED, Loading @@ -214,17 +195,13 @@ class BubbleBarSwipeController { @VisibleForTesting interface DimensionProvider { val unstashThreshold: Int val expandThreshold: Int val maxOverscroll: Int val stashThreshold: Int } private class DefaultDimensionProvider(taskbarActivityContext: TaskbarActivityContext) : DimensionProvider { override val unstashThreshold: Int override val expandThreshold: Int override val maxOverscroll: Int override val stashThreshold: Int init { val resources = taskbarActivityContext.resources Loading @@ -233,14 +210,7 @@ class BubbleBarSwipeController { resources, taskbarActivityContext.deviceProfile, ) // TODO(325673340): review threshold with ux expandThreshold = TaskbarThresholdUtils.getAppWindowThreshold( resources, taskbarActivityContext.deviceProfile, ) maxOverscroll = taskbarActivityContext.deviceProfile.heightPx - unstashThreshold stashThreshold = resources.getDimensionPixelSize(R.dimen.taskbar_to_nav_threshold) } } }
quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeControllerTest.kt +58 −91 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.atLeastOnce import org.mockito.kotlin.never import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever Loading @@ -45,15 +46,11 @@ class BubbleBarSwipeControllerTest { companion object { const val UNSTASH_THRESHOLD = 100 const val EXPAND_THRESHOLD = 200 const val MAX_OVERSCROLL = 300 const val STASH_THRESHOLD = 50 const val UP_BELOW_UNSTASH = -UNSTASH_THRESHOLD + 10f const val UP_ABOVE_UNSTASH = -UNSTASH_THRESHOLD - 10f const val UP_ABOVE_EXPAND = -EXPAND_THRESHOLD - 10f const val DOWN_UNDER_STASH = STASH_THRESHOLD - 10f const val DOWN_OVER_STASH = STASH_THRESHOLD + 10f const val DOWN = UNSTASH_THRESHOLD + 10f } private val context = ApplicationProvider.getApplicationContext<Context>() Loading @@ -80,14 +77,8 @@ class BubbleBarSwipeControllerTest { override val unstashThreshold: Int get() = UNSTASH_THRESHOLD override val expandThreshold: Int get() = EXPAND_THRESHOLD override val maxOverscroll: Int get() = MAX_OVERSCROLL override val stashThreshold: Int get() = STASH_THRESHOLD } bubbleBarSwipeController = BubbleBarSwipeController(context, dimensionProvider) Loading Loading @@ -134,36 +125,12 @@ class BubbleBarSwipeControllerTest { testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_UNSTASH) } @Test fun swipeUp_stashedBar_aboveExpandThreshold_viewsHaveDampedTranslation() { setUpStashedBar() testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_EXPAND) } @Test fun swipeUp_collapsedBar_aboveUnstashThreshold_viewsHaveDampedTranslation() { setUpCollapsedBar() testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_UNSTASH) } @Test fun swipeUp_collapsedBar_aboveExpandThreshold_viewsHaveDampedTranslation() { setUpCollapsedBar() testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_EXPAND) } @Test fun swipeDown_collapsedBar_belowStashThreshold_viewsHaveDampedTranslation() { setUpCollapsedBar() testViewsHaveDampedTranslationOnSwipe(DOWN_UNDER_STASH) } @Test fun swipeDown_collapsedBar_overStashThreshold_viewsHaveDampedTranslation() { setUpCollapsedBar() testViewsHaveDampedTranslationOnSwipe(DOWN_OVER_STASH) } // endregion // region Test that translation on views is reset on finish Loading Loading @@ -202,30 +169,12 @@ class BubbleBarSwipeControllerTest { testViewsTranslationResetOnFinish(UP_ABOVE_UNSTASH) } @Test fun swipeUp_stashedBar_aboveExpandThreshold_animateTranslationToZeroOnFinish() { setUpStashedBar() testViewsTranslationResetOnFinish(UP_ABOVE_EXPAND) } @Test fun swipeUp_collapsedBar_aboveUnstashThreshold_animateTranslationToZeroOnFinish() { setUpCollapsedBar() testViewsTranslationResetOnFinish(UP_ABOVE_UNSTASH) } @Test fun swipeUp_collapsedBar_aboveExpandThreshold_animateTranslationToZeroOnFinish() { setUpCollapsedBar() testViewsTranslationResetOnFinish(UP_ABOVE_EXPAND) } @Test fun swipeDown_collapsedBar_aboveStashThreshold_animateTranslationToZeroOnFinish() { setUpCollapsedBar() testViewsTranslationResetOnFinish(DOWN_OVER_STASH) } // endregion // region Test swipe interactions on stashed bar Loading @@ -251,7 +200,7 @@ class BubbleBarSwipeControllerTest { } @Test fun swipeUp_stashedBar_aboveUnstashThreshold_unstashBubbleBar() { fun swipeUp_stashedBar_overUnstashThreshold_unstashBubbleBar() { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() Loading @@ -271,50 +220,45 @@ class BubbleBarSwipeControllerTest { } @Test fun swipeUp_stashedBar_overUnstashThresholdMultipleTimes_unstashBubbleBarOnce() { fun swipeUp_stashedBar_overUnstashThresholdMultipleTimes_unstashesMultipleTimes() { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } verify(bubbleStashController).showBubbleBar(expandBubbles = false) verify(bubbleStashController).stashBubbleBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } verify(bubbleStashController, times(2)).showBubbleBar(expandBubbles = false) } @Test fun swipeUp_stashedBar_overExpandThreshold_doesNotExpandBeforeFinish() { fun swipeUp_stashedBar_releaseOverUnstashThreshold_expandsBar() { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } verify(bubbleStashController).showBubbleBar(expandBubbles = false) verify(bubbleStashController, never()).showBubbleBar(expandBubbles = true) getInstrumentation().runOnMainSync { bubbleBarSwipeController.finish() } verify(bubbleStashController).showBubbleBar(expandBubbles = true) } @Test fun swipeUp_stashedBar_overExpandThreshold_isSwipeGestureTrue() { fun swipeUp_stashedBar_overUnstashReleaseBelowUnstash_doesNotExpandBar() { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND) } assertThat(bubbleBarSwipeController.isSwipeGesture()).isTrue() } @Test fun swipeUp_stashedBar_overExpandThresholdAndBackDown_doesNotExpandAfterFinish() { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } verify(bubbleStashController).showBubbleBar(expandBubbles = false) getInstrumentation().runOnMainSync { bubbleBarSwipeController.finish() } verify(bubbleStashController).showBubbleBar(expandBubbles = false) getInstrumentation().runOnMainSync { bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH) bubbleBarSwipeController.finish() } verify(bubbleStashController, never()).showBubbleBar(expandBubbles = true) } @Test Loading @@ -322,7 +266,7 @@ class BubbleBarSwipeControllerTest { setUpStashedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN_OVER_STASH) bubbleBarSwipeController.swipeTo(DOWN) } verify(bubbleStashedHandleViewController, never()).setTranslationYForSwipe(any()) verify(bubbleBarViewController, never()).setTranslationYForSwipe(any()) Loading @@ -338,8 +282,8 @@ class BubbleBarSwipeControllerTest { setUpExpandedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND) bubbleBarSwipeController.swipeTo(DOWN_OVER_STASH) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) bubbleBarSwipeController.swipeTo(DOWN) bubbleBarSwipeController.finish() } verify(bubbleStashedHandleViewController, never()).setTranslationYForSwipe(any()) Loading @@ -352,46 +296,69 @@ class BubbleBarSwipeControllerTest { // region Test swipe interactions on collapsed bar @Test fun swipeDown_collapsedBar_underStashThreshold_doesNotHideBar() { fun swipeUp_collapsedBar_doesNotShowBarDuringDrag() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN_UNDER_STASH) bubbleBarSwipeController.finish() bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } verify(bubbleStashController, never()).stashBubbleBar() verify(bubbleStashController, never()).showBubbleBar(any()) } @Test fun swipeDown_collapsedBar_overStashThreshold_doesNotHideBarBeforeFinish() { fun swipeUp_collapsedBar_belowUnstashThreshold_isSwipeGestureFalse() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN_OVER_STASH) bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH) } verify(bubbleStashController, never()).stashBubbleBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.finish() } verify(bubbleStashController).stashBubbleBar() assertThat(bubbleBarSwipeController.isSwipeGesture()).isFalse() } @Test fun swipeDown_collapsedBar_underStashThreshold_isSwipeGestureFalse() { fun swipeUp_collapsedBar_overUnstashThreshold_isSwipeGestureTrue() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN_UNDER_STASH) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) } assertThat(bubbleBarSwipeController.isSwipeGesture()).isFalse() assertThat(bubbleBarSwipeController.isSwipeGesture()).isTrue() } @Test fun swipeDown_collapsedBar_overStashThreshold_isSwipeGestureTrue() { fun swipeUp_collapsedBar_finishOverUnstashThreshold_expandsBar() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN_OVER_STASH) bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) bubbleBarSwipeController.finish() } assertThat(bubbleBarSwipeController.isSwipeGesture()).isTrue() verify(bubbleStashController).showBubbleBar(expandBubbles = true) } @Test fun swipeUp_collapsedBar_finishBelowUnstashThreshold_doesNotExpandBar() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH) bubbleBarSwipeController.finish() } verify(bubbleStashController, never()).showBubbleBar(any()) } @Test fun swipeDown_collapsedBar_swipeIgnored() { setUpCollapsedBar() getInstrumentation().runOnMainSync { bubbleBarSwipeController.start() bubbleBarSwipeController.swipeTo(DOWN) } verify(bubbleStashedHandleViewController, never()).setTranslationYForSwipe(any()) verify(bubbleBarViewController, never()).setTranslationYForSwipe(any()) verify(bubbleStashController, never()).showBubbleBar(any()) verify(bubbleStashController, never()).stashBubbleBar() } // endregion Loading