From 39c4bf24482aeb85a7bc10874a7f7383619490d0 Mon Sep 17 00:00:00 2001 From: mpodolian Date: Thu, 13 Feb 2025 16:56:16 -0800 Subject: [PATCH] Handle new bubble notification while drag is in progress. Handle new bubble notification while drag is in progress. Updated logic to react to new bubble notifications arriving during drag operations before a drop occurs. Bug: 388894910 Flag: com.android.wm.shell.enable_create_any_bubble Test: BubbleBarViewAnimatorTest Test: Manual. Go to some application and have no bubbles. Start dragging the taskbar icon over the bubble bar drop zone. Trigger new bubble with the bubbles test application. Observe drop target is hidden and new bubble is animated in, followed by flyout. When flyout disappears, bubble bar remains on the screen. Release icon over the bubble bar. Observe newly added application bubble is expanded. Repeat same test, but drag the taskbar icon to the opposite side. Test: Manual. Go to some application, but have bubbles. Start dragging the taskbar icon over the bubble bar drop zone. Trigger new bubble with the bubbles test application. Observe new bubble is added and the flyout is shown. When flyout disappears, bubble bar remains on the screen. Release icon over the bubble bar. Observe newly added application bubble is expanded. Repeat same test, but drag the taskbar icon to the opposite side. Change-Id: I6fe1139ef56f4ad40d36a804016d23a9b34abf5f --- .../bubbles/BubbleBarViewController.java | 12 +++- .../animation/BubbleBarViewAnimator.kt | 30 +++++---- .../animation/BubbleBarViewAnimatorTest.kt | 66 +++++++++++++++++++ 3 files changed, 94 insertions(+), 14 deletions(-) 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()