diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java index e0814d3393..987937e976 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java @@ -115,7 +115,6 @@ public class BubbleBarController extends IBubblesListener.Stub { private BubbleBarItem mSelectedBubble; private TaskbarSharedState mSharedState; - private ImeVisibilityChecker mImeVisibilityChecker; private BubbleBarViewController mBubbleBarViewController; private BubbleStashController mBubbleStashController; private Optional mBubbleStashedHandleViewController; @@ -126,6 +125,8 @@ public class BubbleBarController extends IBubblesListener.Stub { // Cache last sent top coordinate to avoid sending duplicate updates to shell private int mLastSentBubbleBarTop; + private boolean mIsImeVisible = false; + /** * Similar to {@link BubbleBarUpdate} but rather than {@link BubbleInfo}s it uses * {@link BubbleBarBubble}s so that it can be used to update the views. @@ -192,10 +193,8 @@ public class BubbleBarController extends IBubblesListener.Stub { /** Initializes controllers. */ public void init(BubbleControllers bubbleControllers, BubbleBarLocationListener bubbleBarLocationListener, - ImeVisibilityChecker imeVisibilityChecker, TaskbarSharedState sharedState) { mSharedState = sharedState; - mImeVisibilityChecker = imeVisibilityChecker; mBubbleBarViewController = bubbleControllers.bubbleBarViewController; mBubbleStashController = bubbleControllers.bubbleStashController; mBubbleStashedHandleViewController = bubbleControllers.bubbleStashedHandleViewController; @@ -234,6 +233,10 @@ public class BubbleBarController extends IBubblesListener.Stub { boolean sysuiLocked = (flags & MASK_SYSUI_LOCKED) != 0; mBubbleStashController.setSysuiLocked(sysuiLocked); + mIsImeVisible = (flags & SYSUI_STATE_IME_SHOWING) != 0; + if (mIsImeVisible) { + mBubbleBarViewController.onImeVisible(); + } } // @@ -309,8 +312,7 @@ public class BubbleBarController extends IBubblesListener.Stub { // enabling gesture nav. also suppress animation if the bubble bar is hidden for sysui e.g. // the shade is open, or we're locked. final boolean suppressAnimation = - update.initialState || mBubbleBarViewController.isHiddenForSysui() - || mImeVisibilityChecker.isImeVisible(); + update.initialState || mBubbleBarViewController.isHiddenForSysui() || mIsImeVisible; if (update.initialState && mSharedState.hasSavedBubbles()) { // clear restored state @@ -572,12 +574,6 @@ public class BubbleBarController extends IBubblesListener.Stub { mBubbleBarViewController.addBubble(bubble, isExpanding, suppressAnimation); } - /** Interface for checking whether the IME is visible. */ - public interface ImeVisibilityChecker { - /** Whether the IME is visible. */ - boolean isImeVisible(); - } - /** Listener of {@link BubbleBarLocation} updates. */ public interface BubbleBarLocationListener { diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index d13e0c4d07..203cba1858 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -383,6 +383,13 @@ public class BubbleBarViewController { } } + /** Notifies that the IME became visible. */ + public void onImeVisible() { + if (isAnimatingNewBubble()) { + mBubbleBarViewAnimator.interruptForIme(); + } + } + // // The below animators are exposed to BubbleStashController so it can manage the stashing // animation. diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java index d993685ee2..cb592e6006 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java @@ -89,7 +89,6 @@ public class BubbleControllers { ); bubbleBarController.init(this, bubbleBarLocationListeners, - taskbarControllers.navbarButtonsViewController::isImeVisible, taskbarSharedState); bubbleStashedHandleViewController.ifPresent( controller -> controller.init(/* bubbleControllers = */ this)); 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 5184a9f3de..89e42100af 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt @@ -532,6 +532,21 @@ constructor( ) } + /** Interrupts the animation due to the IME becoming visible. */ + fun interruptForIme() { + cancelFlyout() + val hideAnimation = animatingBubble?.hideAnimation ?: return + scheduler.cancel(hideAnimation) + animatingBubble = null + bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning() + bubbleBarView.relativePivotY = 1f + // stash the bubble bar since the IME is now visible + bubbleStashController.onNewBubbleAnimationInterrupted( + /* isStashed= */ true, + bubbleBarView.translationY, + ) + } + fun expandedWhileAnimating() { val animatingBubble = animatingBubble ?: return this.animatingBubble = animatingBubble.copy(expand = true) 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 582ea54bf0..fe448f4f82 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 @@ -54,6 +54,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.atLeastOnce +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @@ -1266,6 +1267,50 @@ class BubbleBarViewAnimatorTest { verify(bubbleStashController).stashBubbleBarImmediate() } + @Test + fun interruptForIme() { + setUpBubbleBar() + setUpBubbleStashController() + + val handle = View(context) + val handleAnimator = PhysicsAnimator.getInstance(handle) + whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator) + + val animator = + BubbleBarViewAnimator( + bubbleBarView, + bubbleStashController, + flyoutController, + onExpandedNoOp, + animatorScheduler, + ) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + animator.animateBubbleInForStashed(bubble, isExpanding = false) + } + + // wait for the animation to start + InstrumentationRegistry.getInstrumentation().runOnMainSync {} + PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true } + + handleAnimator.assertIsRunning() + assertThat(animator.isAnimating).isTrue() + // verify the hide bubble animation is pending + assertThat(animatorScheduler.delayedBlock).isNotNull() + + InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.interruptForIme() } + + // verify that the hide animation was canceled + assertThat(animatorScheduler.delayedBlock).isNull() + assertThat(animator.isAnimating).isFalse() + verify(bubbleStashController).onNewBubbleAnimationInterrupted(eq(true), any()) + + // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait + // again + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + handleAnimator.assertIsNotRunning() + } + private fun setUpBubbleBar() { bubbleBarView = BubbleBarView(context) InstrumentationRegistry.getInstrumentation().runOnMainSync {