diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index b02b85fad4..b90a5b001a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -276,7 +276,10 @@ public class BubbleBarViewController { @Override public boolean isOnLeft() { - return mBarView.getBubbleBarLocation().isOnLeft(mBarView.isLayoutRtl()); + boolean shouldRevertLocation = + mBarView.isShowingDropTarget() && mIsLocationUpdatedForDropTarget; + boolean isOnLeft = mBarView.getBubbleBarLocation().isOnLeft(mBarView.isLayoutRtl()); + return shouldRevertLocation != isOnLeft; } @Override @@ -1053,7 +1056,12 @@ public class BubbleBarViewController { boolean isInApp = mTaskbarStashController.isInApp(); // if this is the first bubble, animate to the initial state. if (mBarView.getBubbleChildCount() == 1 && !isUpdate) { - mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding); + // If a drop target is visible and the first bubble is added, hide the empty drop target + if (mBarView.isShowingDropTarget()) { + mBubbleBarPinController.hideDropTarget(); + } + mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding, + mBarView.isShowingDropTarget()); return; } // if we're not stashed or we're in persistent taskbar, animate for collapsed state. diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt index 745c689541..30cfafe694 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt @@ -365,7 +365,12 @@ constructor( } /** Animates to the initial state of the bubble bar, when there are no previous bubbles. */ - fun animateToInitialState(b: BubbleBarBubble, isInApp: Boolean, isExpanding: Boolean) { + fun animateToInitialState( + b: BubbleBarBubble, + isInApp: Boolean, + isExpanding: Boolean, + isDragging: Boolean = false, + ) { val bubbleView = b.view val animator = PhysicsAnimator.getInstance(bubbleView) if (animator.isRunning()) animator.cancel() @@ -374,15 +379,12 @@ constructor( // bubble bar to the handle if we're in an app. val showAnimation = buildBubbleBarSpringInAnimation() val hideAnimation = - if (isInApp && !isExpanding) { + if (isInApp && !isExpanding && !isDragging) { buildBubbleBarToHandleAnimation() } else { Runnable { - moveToState(AnimatingBubble.State.ANIMATING_OUT) - bubbleBarFlyoutController.collapseFlyout { - onFlyoutRemoved() - clearAnimatingBubble() - } + collapseFlyoutAndUpdateState() + if (isDragging) return@Runnable bubbleStashController.showBubbleBarImmediate() bubbleStashController.updateTaskbarTouchRegion() } @@ -440,11 +442,7 @@ constructor( // first bounce the bubble bar and show the flyout. Then hide the flyout. val showAnimation = buildBubbleBarBounceAnimation() val hideAnimation = Runnable { - moveToState(AnimatingBubble.State.ANIMATING_OUT) - bubbleBarFlyoutController.collapseFlyout { - onFlyoutRemoved() - clearAnimatingBubble() - } + collapseFlyoutAndUpdateState() bubbleStashController.showBubbleBarImmediate() bubbleStashController.updateTaskbarTouchRegion() } @@ -454,6 +452,14 @@ constructor( scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation) } + private fun collapseFlyoutAndUpdateState() { + moveToState(AnimatingBubble.State.ANIMATING_OUT) + bubbleBarFlyoutController.collapseFlyout { + onFlyoutRemoved() + clearAnimatingBubble() + } + } + /** * The bubble bar animation when it is collapsed is divided into 2 chained animations. The first * animation is a regular accelerate animation that moves the bubble bar upwards. When it ends diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt index 46b5659ce9..a456fb9c73 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt @@ -60,6 +60,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.atLeastOnce import org.mockito.kotlin.eq import org.mockito.kotlin.mock +import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @@ -572,6 +573,71 @@ class BubbleBarViewAnimatorTest { verify(bubbleStashController).stashBubbleBarImmediate() } + @Test + fun animateToInitialState_whileDragging_inApp() { + setUpBubbleBar() + setUpBubbleStashController() + whenever(bubbleStashController.bubbleBarTranslationY) + .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR) + + val handle = View(context) + val handleAnimator = PhysicsAnimator.getInstance(handle) + whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator) + + val barAnimator = PhysicsAnimator.getInstance(bubbleBarView) + + var notifiedBubbleBarVisible = false + val onBubbleBarVisible = Runnable { notifiedBubbleBarVisible = true } + val animator = + BubbleBarViewAnimator( + bubbleBarView, + bubbleStashController, + flyoutController, + bubbleBarParentViewController, + onExpanded = emptyRunnable, + onBubbleBarVisible = onBubbleBarVisible, + animatorScheduler, + ) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleBarView.visibility = INVISIBLE + animator.animateToInitialState( + bubble, + isInApp = true, + isExpanding = false, + isDragging = true, + ) + } + + InstrumentationRegistry.getInstrumentation().runOnMainSync {} + PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y) + + barAnimator.assertIsNotRunning() + assertThat(animator.isAnimating).isTrue() + assertThat(bubbleBarView.alpha).isEqualTo(1) + assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR) + assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1) + waitForFlyoutToShow() + + assertThat(animatorScheduler.delayedBlock).isNotNull() + InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!) + + waitForFlyoutToHide() + + InstrumentationRegistry.getInstrumentation().runOnMainSync {} + PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y) + + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2) + assertThat(animator.isAnimating).isFalse() + assertThat(bubbleBarView.alpha).isEqualTo(1) + assertThat(handle.translationY).isEqualTo(0) + assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE) + assertThat(notifiedBubbleBarVisible).isTrue() + + verify(bubbleStashController, never()).stashBubbleBarImmediate() + } + @Test fun animateToInitialState_inApp_autoExpanding() { setUpBubbleBar()