diff --git a/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/behavior/BrowserToolbarBottomBehavior.kt b/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/behavior/BrowserToolbarBottomBehavior.kt index f06d3caa151..1d7a80f3cad 100644 --- a/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/behavior/BrowserToolbarBottomBehavior.kt +++ b/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/behavior/BrowserToolbarBottomBehavior.kt @@ -44,6 +44,8 @@ class BrowserToolbarBottomBehavior( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal var shouldSnapAfterScroll: Boolean = false + private var lastSnapStartedWasUp = false + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal var snapAnimator: ValueAnimator = ValueAnimator().apply { interpolator = DecelerateInterpolator() @@ -147,6 +149,7 @@ class BrowserToolbarBottomBehavior( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal fun animateSnap(child: View, direction: SnapDirection) = with(snapAnimator) { + lastSnapStartedWasUp = direction == SnapDirection.UP addUpdateListener { child.translationY = it.animatedValue as Float } setFloatValues(child.translationY, if (direction == SnapDirection.UP) 0f else child.height.toFloat()) start() @@ -188,6 +191,15 @@ class BrowserToolbarBottomBehavior( if (shouldScroll) { browserToolbar.translationY = max(0f, min(browserToolbar.height.toFloat(), browserToolbar.translationY + distance)) + } else { + // Force expand the toolbar if the user scrolled up, it is not already expanded and + // an animation to expand it is not already in progress, + // otherwise the user could get stuck in a state where they cannot show the toolbar + val isAnimatingUp = snapAnimator.isStarted && lastSnapStartedWasUp + if (distance < 0 && browserToolbar.translationY != 0f && !isAnimatingUp) { + snapAnimator.cancel() + forceExpand(browserToolbar) + } } } diff --git a/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/behavior/BrowserToolbarBottomBehaviorTest.kt b/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/behavior/BrowserToolbarBottomBehaviorTest.kt index 40fe34315ec..b935fe2de0b 100644 --- a/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/behavior/BrowserToolbarBottomBehaviorTest.kt +++ b/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/behavior/BrowserToolbarBottomBehaviorTest.kt @@ -153,6 +153,8 @@ class BrowserToolbarBottomBehaviorTest { fun `Behavior will apply translation to toolbar only for vertical scrolls`() { val behavior = spy(BrowserToolbarBottomBehavior(testContext, attrs = null)) behavior.initGesturesDetector(behavior.createGestureDetector()) + val child = spy(BrowserToolbar(testContext, null, 0)) + behavior.browserToolbar = child val downEvent = TestUtils.getMotionEvent(ACTION_DOWN, 0f, 0f) val moveEvent = TestUtils.getMotionEvent(ACTION_MOVE, 0f, 100f, downEvent) @@ -317,4 +319,28 @@ class BrowserToolbarBottomBehaviorTest { verify(behavior).animateSnap(toolbar, SnapDirection.UP) } + + @Test + fun `Behavior will forceExpand when scrolling up and !shouldScroll`() { + val behavior = spy(BrowserToolbarBottomBehavior(testContext, attrs = null)) + behavior.initGesturesDetector(behavior.createGestureDetector()) + doReturn(false).`when`(behavior).shouldScroll + val toolbar: BrowserToolbar = spy(BrowserToolbar(testContext, null, 0)) + behavior.browserToolbar = toolbar + val animator: ValueAnimator = mock() + behavior.snapAnimator = animator + doReturn(false).`when`(animator).isStarted + + doReturn(100).`when`(toolbar).height + doReturn(100f).`when`(toolbar).translationY + + val downEvent = TestUtils.getMotionEvent(ACTION_DOWN, 0f, 0f) + val moveEvent = TestUtils.getMotionEvent(ACTION_MOVE, 0f, 30f, downEvent) + + behavior.onInterceptTouchEvent(mock(), mock(), downEvent) + behavior.onInterceptTouchEvent(mock(), mock(), moveEvent) + + verify(behavior).tryToScrollVertically(-30f) + verify(behavior).forceExpand(toolbar) + } }