Hide the IME using InputMethodManagerInternal, because doing it that way actually works.

This technique is also used by the Recents animation to hide the IME. It replaces the AV back press workaround entirely, which fixes the IME hanging around issue (and by extension, the weirdness around the insets).

Test: open a bubble (go/use-bubbles), focus an input field, then tap outside the bubbles UI to close the stack, observe that the IME hides
Test: open a bubble, focus an input field, switch to another bubble, observe IME hides
Test: open bubble, focus input field, switch to another bubble, focus input field, switch to the original bubble, focus input field, collapse stack, observe IME hides (previously the IME would remain visible)
Bug: 159369847
Bug: 159561847
Change-Id: I09f27b3c187a7bcfbef663cd3101a74ad8ab95ab
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index 79397b8..4b968b4 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -46,7 +46,8 @@
         SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE,
         SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME,
         SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED,
-        SoftInputShowHideReason.HIDE_RECENTS_ANIMATION})
+        SoftInputShowHideReason.HIDE_RECENTS_ANIMATION,
+        SoftInputShowHideReason.HIDE_BUBBLES})
 public @interface SoftInputShowHideReason {
     /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
     int SHOW_SOFT_INPUT = 0;
@@ -140,4 +141,10 @@
      * intercept touch from app window.
      */
     int HIDE_RECENTS_ANIMATION = 18;
+
+    /**
+     * Hide soft input when {@link com.android.systemui.bubbles.BubbleController} is expanding,
+     * switching, or collapsing Bubbles.
+     */
+    int HIDE_BUBBLES = 19;
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index c320824..4999ec0 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -79,6 +79,7 @@
     void onNotificationSettingsViewed(String key);
     void onNotificationBubbleChanged(String key, boolean isBubble, int flags);
     void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed);
+    void hideCurrentInputMethodForBubbles();
     void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName);
     void clearInlineReplyUriPermissions(String key);
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index aa41719..ccfbd8f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -483,12 +483,13 @@
     }
 
     /**
-     * Dispatches a back press into the expanded Bubble's ActivityView if its IME is visible,
-     * causing it to hide.
+     * Hides the current input method, wherever it may be focused, via InputMethodManagerInternal.
      */
-    public void hideImeFromExpandedBubble() {
-        if (mStackView != null) {
-            mStackView.hideImeFromExpandedBubble();
+    public void hideCurrentInputMethod() {
+        try {
+            mBarService.hideCurrentInputMethodForBubbles();
+        } catch (RemoteException e) {
+            e.printStackTrace();
         }
     }
 
@@ -693,8 +694,8 @@
         if (mStackView == null) {
             mStackView = new BubbleStackView(
                     mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
-                    mSysUiState, this::onAllBubblesAnimatedOut,
-                    this::onImeVisibilityChanged);
+                    mSysUiState, this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged,
+                    this::hideCurrentInputMethod);
             mStackView.addView(mBubbleScrim);
             if (mExpandListener != null) {
                 mStackView.setExpandListener(mExpandListener);
@@ -1589,7 +1590,11 @@
         @Override
         public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
             if (mStackView != null && taskInfo.displayId == getExpandedDisplayId(mContext)) {
-                mBubbleData.setExpanded(false);
+                if (mImeVisible) {
+                    hideCurrentInputMethod();
+                } else {
+                    mBubbleData.setExpanded(false);
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 7c3e027..551c1a6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -465,7 +465,6 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        hideImeIfVisible();
         mKeyboardVisible = false;
         mNeedsNewHeight = false;
         if (mActivityView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index c985b08..356ee94 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -384,6 +384,11 @@
     public final Consumer<Boolean> mOnImeVisibilityChanged;
 
     /**
+     * Callback to run to ask BubbleController to hide the current IME.
+     */
+    private final Runnable mHideCurrentInputMethodCallback;
+
+    /**
      * The currently magnetized object, which is being dragged and will be attracted to the magnetic
      * dismiss target.
      *
@@ -560,7 +565,7 @@
                         mMagneticTarget,
                         mIndividualBubbleMagnetListener);
 
-                hideImeFromExpandedBubble();
+                hideCurrentInputMethod();
 
                 // Save the magnetized individual bubble so we can dispatch touch events to it.
                 mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut();
@@ -732,7 +737,8 @@
             FloatingContentCoordinator floatingContentCoordinator,
             SysUiState sysUiState,
             Runnable allBubblesAnimatedOutAction,
-            Consumer<Boolean> onImeVisibilityChanged) {
+            Consumer<Boolean> onImeVisibilityChanged,
+            Runnable hideCurrentInputMethodCallback) {
         super(context);
 
         mBubbleData = data;
@@ -868,6 +874,7 @@
         setUpOverflow();
 
         mOnImeVisibilityChanged = onImeVisibilityChanged;
+        mHideCurrentInputMethodCallback = hideCurrentInputMethodCallback;
 
         setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
             onImeVisibilityChanged.accept(insets.getInsets(WindowInsets.Type.ime()).bottom > 0);
@@ -1584,6 +1591,8 @@
         updatePointerPosition();
 
         if (mIsExpanded) {
+            hideCurrentInputMethod();
+
             // Make the container of the expanded view transparent before removing the expanded view
             // from it. Otherwise a punch hole created by {@link android.view.SurfaceView} in the
             // expanded view becomes visible on the screen. See b/126856255
@@ -1592,11 +1601,6 @@
                 if (previouslySelected != null) {
                     previouslySelected.setContentVisibility(false);
                 }
-                if (previouslySelected != null && previouslySelected.getExpandedView() != null) {
-                    // Hide the currently expanded bubble's IME if it's visible before switching
-                    // to a new bubble.
-                    previouslySelected.getExpandedView().hideImeIfVisible();
-                }
 
                 updateExpandedBubble();
                 requestUpdate();
@@ -1624,6 +1628,8 @@
             return;
         }
 
+        hideCurrentInputMethod();
+
         mSysUiState
                 .setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
                 .commitUpdate(mContext.getDisplayId());
@@ -1807,12 +1813,12 @@
         }
     }
 
-    void hideImeFromExpandedBubble() {
-        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
-            // Hide the currently expanded bubble's IME if it's visible before switching to a new
-            // bubble.
-            mExpandedBubble.getExpandedView().hideImeIfVisible();
-        }
+    /**
+     * Asks the BubbleController to hide the IME from anywhere, whether it's focused on Bubbles or
+     * not.
+     */
+    void hideCurrentInputMethod() {
+        mHideCurrentInputMethodCallback.run();
     }
 
     private void beforeExpandedViewAnimation() {
@@ -1927,10 +1933,6 @@
         mAnimatingOutSurfaceContainer.setScaleX(0f);
         mAnimatingOutSurfaceContainer.setScaleY(0f);
 
-        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
-            mExpandedBubble.getExpandedView().hideImeIfVisible();
-        }
-
         // Let the expanded animation controller know that it shouldn't animate child adds/reorders
         // since we're about to animate collapsed.
         mExpandedAnimationController.notifyPreparingToCollapse();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 4ba58bd..39e839d 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -52,6 +52,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
@@ -61,6 +62,7 @@
 import com.android.internal.view.AppearanceRegion;
 import com.android.server.LocalServices;
 import com.android.server.UiThread;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.notification.NotificationDelegate;
 import com.android.server.policy.GlobalActionsProvider;
 import com.android.server.power.ShutdownThread;
@@ -1402,6 +1404,17 @@
     }
 
     @Override
+    public void hideCurrentInputMethodForBubbles() {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            InputMethodManagerInternal.get().hideCurrentInputMethod(
+                    SoftInputShowHideReason.HIDE_BUBBLES);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override
     public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user,
             String packageName) {
         enforceStatusBarService();