Move Bubbles into a hw-accelerated TYPE_APPLICATION_OVERLAY WindowManager layer.

This addresses several issues caused by Bubbles living in the status bar window and makes it easier to address several more open bugs.

Test: atest SystemUITests
Test: manually, a lot
Fixes: 130579263
Fixes: 142075351
Fixes: 151086286
Fixes: 149473357
Bug: 150906076
Change-Id: I61594931cce55cba78e6cb1fcec440e4fec32bb0
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index dc070cb..d322e09 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -44,14 +44,6 @@
     </com.android.systemui.statusbar.BackDropView>
 
     <com.android.systemui.statusbar.ScrimView
-        android:id="@+id/scrim_for_bubble"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:importantForAccessibility="no"
-        sysui:ignoreRightInset="true"
-        />
-
-    <com.android.systemui.statusbar.ScrimView
         android:id="@+id/scrim_behind"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 013f222..cafa060 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -29,7 +29,7 @@
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
 import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
@@ -53,7 +53,9 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -66,7 +68,7 @@
 import android.util.SparseSetArray;
 import android.view.Display;
 import android.view.ViewGroup;
-import android.widget.FrameLayout;
+import android.view.WindowManager;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.MainThread;
@@ -76,7 +78,6 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dumpable;
-import com.android.systemui.R;
 import com.android.systemui.bubbles.dagger.BubbleModule;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.model.SysUiState;
@@ -88,6 +89,7 @@
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
+import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.NotificationChannelHelper;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -98,6 +100,7 @@
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -145,7 +148,6 @@
     private final NotificationEntryManager mNotificationEntryManager;
     private final NotifPipeline mNotifPipeline;
     private final BubbleTaskStackListener mTaskStackListener;
-    private BubbleStateChangeListener mStateChangeListener;
     private BubbleExpandListener mExpandListener;
     @Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
     private final NotificationGroupManager mNotificationGroupManager;
@@ -153,6 +155,7 @@
     private final FloatingContentCoordinator mFloatingContentCoordinator;
 
     private BubbleData mBubbleData;
+    private ScrimView mBubbleScrim;
     @Nullable private BubbleStackView mStackView;
     private BubbleIconFactory mBubbleIconFactory;
 
@@ -175,11 +178,16 @@
 
     private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
     private IStatusBarService mBarService;
+    private WindowManager mWindowManager;
     private SysUiState mSysUiState;
 
     // Used to post to main UI thread
     private Handler mHandler = new Handler();
 
+    /** LayoutParams used to add the BubbleStackView to the window maanger. */
+    private WindowManager.LayoutParams mWmLayoutParams;
+
+
     // Used for determining view rect for touch interaction
     private Rect mTempRect = new Rect();
 
@@ -195,16 +203,6 @@
     private final List<NotifCallback> mCallbacks = new ArrayList<>();
 
     /**
-     * Listener to be notified when some states of the bubbles change.
-     */
-    public interface BubbleStateChangeListener {
-        /**
-         * Called when the stack has bubbles or no longer has bubbles.
-         */
-        void onHasBubblesChanged(boolean hasBubbles);
-    }
-
-    /**
      * Listener to find out about stack expansion / collapse events.
      */
     public interface BubbleExpandListener {
@@ -393,9 +391,12 @@
         }
         mSurfaceSynchronizer = synchronizer;
 
+        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
+        mBubbleScrim = new ScrimView(mContext);
+
         mSavedBubbleKeysPerUser = new SparseSetArray<>();
         mCurrentUserId = mNotifUserManager.getCurrentUserId();
         mNotifUserManager.addUserChangedListener(
@@ -573,6 +574,15 @@
     }
 
     /**
+     * Returns the scrim drawn behind the bubble stack. This is managed by {@link ScrimController}
+     * since we want the scrim's appearance and behavior to be identical to that of the notification
+     * shade scrim.
+     */
+    public ScrimView getScrimForBubble() {
+        return mBubbleScrim;
+    }
+
+    /**
      * Sets whether to perform inflation on the same thread as the caller. This method should only
      * be used in tests, not in production.
      */
@@ -592,7 +602,6 @@
         return mBubbleData.getOverflowBubbles();
     }
 
-
     /**
      * BubbleStackView is lazily created by this method the first time a Bubble is added. This
      * method initializes the stack view and adds it to the StatusBar just above the scrim.
@@ -602,11 +611,8 @@
             mStackView = new BubbleStackView(
                     mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
                     mSysUiState, mNotificationShadeWindowController);
-            ViewGroup nsv = mNotificationShadeWindowController.getNotificationShadeView();
-            int bubbleScrimIndex = nsv.indexOfChild(nsv.findViewById(R.id.scrim_for_bubble));
-            int stackIndex = bubbleScrimIndex + 1;  // Show stack above bubble scrim.
-            nsv.addView(mStackView, stackIndex,
-                    new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+            mStackView.addView(mBubbleScrim);
+            addToWindowManager();
             if (mExpandListener != null) {
                 mStackView.setExpandListener(mExpandListener);
             }
@@ -616,6 +622,45 @@
         }
     }
 
+    /** Adds the BubbleStackView to the WindowManager. */
+    private void addToWindowManager() {
+        mWmLayoutParams = new WindowManager.LayoutParams(
+                // Fill the screen so we can use translation animations to position the bubble
+                // stack. We'll use touchable regions to ignore touches that are not on the bubbles
+                // themselves.
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+                // Start not focusable - we'll become focusable when expanded so the ActivityView
+                // can use the IME.
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+                PixelFormat.TRANSLUCENT);
+
+        mWmLayoutParams.setFitInsetsTypes(0);
+        mWmLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+        mWmLayoutParams.token = new Binder();
+        mWmLayoutParams.setTitle("Bubbles!");
+        mWmLayoutParams.packageName = mContext.getPackageName();
+        mWmLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
+        mWindowManager.addView(mStackView, mWmLayoutParams);
+    }
+
+    private void updateWmFlags() {
+        if (isStackExpanded()) {
+            // If we're expanded, we want to be focusable so that the ActivityView can receive focus
+            // and show the IME.
+            mWmLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        } else {
+            // If we're collapsed, we don't want to be able to receive focus. Doing so would
+            // preclude applications from using the IME since we are always above them.
+            mWmLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        }
+
+        mWindowManager.updateViewLayout(mStackView, mWmLayoutParams);
+    }
+
     /**
      * Records the notification key for any active bubbles. These are used to restore active
      * bubbles when the user returns to the foreground.
@@ -687,13 +732,6 @@
     }
 
     /**
-     * Set a listener to be notified when some states of the bubbles change.
-     */
-    public void setBubbleStateChangeListener(BubbleStateChangeListener listener) {
-        mStateChangeListener = listener;
-    }
-
-    /**
      * Set a listener to be notified of bubble expand events.
      */
     public void setExpandListener(BubbleExpandListener listener) {
@@ -701,7 +739,8 @@
             if (listener != null) {
                 listener.onBubbleExpandChanged(isExpanding, key);
             }
-            mNotificationShadeWindowController.setBubbleExpanded(isExpanding);
+
+            updateWmFlags();
         });
         if (mStackView != null) {
             mStackView.setExpandListener(mExpandListener);
@@ -712,7 +751,8 @@
      * Whether or not there are bubbles present, regardless of them being visible on the
      * screen (e.g. if on AOD).
      */
-    public boolean hasBubbles() {
+    @VisibleForTesting
+    boolean hasBubbles() {
         if (mStackView == null) {
             return false;
         }
@@ -1146,8 +1186,7 @@
     /**
      * Lets any listeners know if bubble state has changed.
      * Updates the visibility of the bubbles based on current state.
-     * Does not un-bubble, just hides or un-hides. Notifies any
-     * {@link BubbleStateChangeListener}s of visibility changes.
+     * Does not un-bubble, just hides or un-hides.
      * Updates stack description for TalkBack focus.
      */
     public void updateStack() {
@@ -1161,29 +1200,10 @@
             mStackView.setVisibility(INVISIBLE);
         }
 
-        // Let listeners know if bubble state changed.
-        boolean hadBubbles = mNotificationShadeWindowController.getBubblesShowing();
-        boolean hasBubblesShowing = hasBubbles() && mStackView.getVisibility() == VISIBLE;
-        mNotificationShadeWindowController.setBubblesShowing(hasBubblesShowing);
-        if (mStateChangeListener != null && hadBubbles != hasBubblesShowing) {
-            mStateChangeListener.onHasBubblesChanged(hasBubblesShowing);
-        }
-
         mStackView.updateContentDescription();
     }
 
     /**
-     * Rect indicating the touchable region for the bubble stack / expanded stack.
-     */
-    public Rect getTouchableRegion() {
-        if (mStackView == null || mStackView.getVisibility() != VISIBLE) {
-            return null;
-        }
-        mStackView.getBoundsOnScreen(mTempRect);
-        return mTempRect;
-    }
-
-    /**
      * The display id of the expanded view, if the stack is expanded and not occluded by the
      * status bar, otherwise returns {@link Display#INVALID_DISPLAY}.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 366d4a7..c802b59 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -108,7 +108,8 @@
 /**
  * Renders bubbles in a stack and handles animating expanded and collapsed states.
  */
-public class BubbleStackView extends FrameLayout {
+public class BubbleStackView extends FrameLayout
+        implements ViewTreeObserver.OnComputeInternalInsetsListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
 
     /** Animation durations for bubble stack user education views. **/
@@ -647,7 +648,6 @@
     private boolean mShowingManage = false;
     private PhysicsAnimator.SpringConfig mManageSpringConfig = new PhysicsAnimator.SpringConfig(
             SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
-
     @SuppressLint("ClickableViewAccessibility")
     public BubbleStackView(Context context, BubbleData data,
             @Nullable SurfaceSynchronizer synchronizer,
@@ -1052,14 +1052,24 @@
     }
 
     @Override
-    public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
-        getBoundsOnScreen(outRect);
+    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
+        inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+
+        getTouchableRegion(mTempRect);
+        inoutInfo.touchableRegion.set(mTempRect);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        getViewTreeObserver().addOnComputeInternalInsetsListener(this);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         getViewTreeObserver().removeOnPreDrawListener(mViewUpdater);
+        getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
     }
 
     @Override
@@ -1960,8 +1970,16 @@
         mAfterFlyoutHidden = null;
     }
 
-    @Override
-    public void getBoundsOnScreen(Rect outRect) {
+    /**
+     * Fills the Rect with the touchable region of the bubbles. This will be used by WindowManager
+     * to decide which touch events go to Bubbles.
+     *
+     * Bubbles is below the status bar/notification shade but above application windows. If you're
+     * trying to get touch events from the status bar or another higher-level window layer, you'll
+     * need to re-order TYPE_BUBBLES in WindowManagerPolicy so that we have the opportunity to steal
+     * them.
+     */
+    public void getTouchableRegion(Rect outRect) {
         if (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE) {
             // When user education shows then capture all touches
             outRect.set(0, 0, getWidth(), getHeight());
@@ -1971,12 +1989,12 @@
         if (!mIsExpanded) {
             if (getBubbleCount() > 0) {
                 mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect);
+                // Increase the touch target size of the bubble
+                outRect.top -= mBubbleTouchPadding;
+                outRect.left -= mBubbleTouchPadding;
+                outRect.right += mBubbleTouchPadding;
+                outRect.bottom += mBubbleTouchPadding;
             }
-            // Increase the touch target size of the bubble
-            outRect.top -= mBubbleTouchPadding;
-            outRect.left -= mBubbleTouchPadding;
-            outRect.right += mBubbleTouchPadding;
-            outRect.bottom += mBubbleTouchPadding;
         } else {
             mBubbleContainer.getBoundsOnScreen(outRect);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
index 462b42a..fc6a028 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
@@ -273,8 +273,7 @@
     private void applyFocusableFlag(State state) {
         boolean panelFocusable = state.mNotificationShadeFocusable && state.mPanelExpanded;
         if (state.mBouncerShowing && (state.mKeyguardOccluded || state.mKeyguardNeedsInput)
-                || ENABLE_REMOTE_INPUT && state.mRemoteInputActive
-                || state.mBubbleExpanded) {
+                || ENABLE_REMOTE_INPUT && state.mRemoteInputActive) {
             mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
             mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
@@ -320,7 +319,7 @@
     private boolean isExpanded(State state) {
         return !state.mForceCollapsed && (state.isKeyguardShowingAndNotOccluded()
                 || state.mPanelVisible || state.mKeyguardFadingAway || state.mBouncerShowing
-                || state.mHeadsUpShowing || state.mBubblesShowing
+                || state.mHeadsUpShowing
                 || state.mScrimsVisibility != ScrimController.TRANSPARENT)
                 || state.mBackgroundBlurRadius > 0;
     }
@@ -579,36 +578,6 @@
     }
 
     /**
-     * Sets whether there are bubbles showing on the screen.
-     */
-    public void setBubblesShowing(boolean bubblesShowing) {
-        mCurrentState.mBubblesShowing = bubblesShowing;
-        apply(mCurrentState);
-    }
-
-    /**
-     * The bubbles showing state for the status bar.
-     */
-    public boolean getBubblesShowing() {
-        return mCurrentState.mBubblesShowing;
-    }
-
-    /**
-     * Sets if there is a bubble being expanded on the screen.
-     */
-    public void setBubbleExpanded(boolean bubbleExpanded) {
-        mCurrentState.mBubbleExpanded = bubbleExpanded;
-        apply(mCurrentState);
-    }
-
-    /**
-     * Whether the bubble is shown in expanded state for the status bar.
-     */
-    public boolean getBubbleExpanded() {
-        return mCurrentState.mBubbleExpanded;
-    }
-
-    /**
      * Whether the status bar panel is expanded or not.
      */
     public boolean getPanelExpanded() {
@@ -679,8 +648,6 @@
         boolean mBackdropShowing;
         boolean mWallpaperSupportsAmbientMode;
         boolean mNotTouchable;
-        boolean mBubblesShowing;
-        boolean mBubbleExpanded;
         boolean mForceHasTopUi;
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ac5557b..bbf83bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1144,7 +1144,7 @@
 
         ScrimView scrimBehind = mNotificationShadeWindowView.findViewById(R.id.scrim_behind);
         ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front);
-        ScrimView scrimForBubble = mNotificationShadeWindowView.findViewById(R.id.scrim_for_bubble);
+        ScrimView scrimForBubble = mBubbleController.getScrimForBubble();
 
         mScrimController.setScrimVisibleListener(scrimsVisible -> {
             mNotificationShadeWindowController.setScrimsVisibility(scrimsVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 5bab867..9c7f490 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -32,7 +32,6 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.ScreenDecorations;
-import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -45,8 +44,8 @@
 
 /**
  * Manages what parts of the status bar are touchable. Clients are primarily UI that display in the
- * status bar even though the UI doesn't look like part of the status bar. Currently this
- * includes HeadsUpNotifications and Bubbles.
+ * status bar even though the UI doesn't look like part of the status bar. Currently this consists
+ * of HeadsUpNotifications.
  */
 @Singleton
 public final class StatusBarTouchableRegionManager implements Dumpable {
@@ -55,7 +54,6 @@
     private final Context mContext;
     private final HeadsUpManagerPhone mHeadsUpManager;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
-    private final BubbleController mBubbleController;
 
     private boolean mIsStatusBarExpanded = false;
     private boolean mShouldAdjustInsets = false;
@@ -73,8 +71,7 @@
             Context context,
             NotificationShadeWindowController notificationShadeWindowController,
             ConfigurationController configurationController,
-            HeadsUpManagerPhone headsUpManager,
-            BubbleController bubbleController
+            HeadsUpManagerPhone headsUpManager
     ) {
         mContext = context;
         initResources();
@@ -117,11 +114,6 @@
         mNotificationShadeWindowController.setForcePluginOpenListener((forceOpen) -> {
             updateTouchableRegion();
         });
-
-        mBubbleController = bubbleController;
-        mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
-            updateTouchableRegion();
-        });
     }
 
     protected void setup(
@@ -172,12 +164,6 @@
                     mStatusBarHeight);
             updateRegionForNotch(mTouchableRegion);
         }
-
-        // Update touchable region for bubbles
-        Rect bubbleRect = mBubbleController.getTouchableRegion();
-        if (bubbleRect != null) {
-            mTouchableRegion.union(bubbleRect);
-        }
         return mTouchableRegion;
     }
 
@@ -198,7 +184,6 @@
                 && (mNotificationShadeWindowView.getRootWindowInsets().getDisplayCutout() != null);
         boolean shouldObserve = mHeadsUpManager.hasPinnedHeadsUp()
                         || mHeadsUpManager.isHeadsUpGoingAway()
-                        || mBubbleController.hasBubbles()
                         || mForceCollapsedUntilLayout
                         || hasCutoutInset
                         || mNotificationShadeWindowController.getForcePluginOpen();
@@ -266,7 +251,7 @@
             }
 
             // Update touch insets to include any area needed for touching features that live in
-            // the status bar (ie: heads up notifications or bubbles)
+            // the status bar (ie: heads up notifications)
             info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
             info.touchableRegion.set(calculateTouchableRegion());
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index c2b3506..58906d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -30,7 +30,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -162,8 +161,6 @@
     private ExpandableNotificationRow mNonBubbleNotifRow;
 
     @Mock
-    private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
-    @Mock
     private BubbleController.BubbleExpandListener mBubbleExpandListener;
     @Mock
     private PendingIntent mDeleteIntent;
@@ -280,7 +277,6 @@
                 mFloatingContentCoordinator,
                 mSysUiState,
                 mock(INotificationManager.class));
-        mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
         mBubbleController.setExpandListener(mBubbleExpandListener);
 
         // Get a reference to the BubbleController's entry listener
@@ -298,7 +294,6 @@
         mBubbleController.updateBubble(mRow.getEntry());
         assertTrue(mBubbleController.hasBubbles());
 
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
         assertFalse(mSysUiStateBubblesExpanded);
     }
 
@@ -316,14 +311,11 @@
         assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
         assertTrue(mBubbleController.hasBubbles());
         verify(mNotificationEntryManager).updateNotifications(any());
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
 
         mBubbleController.removeBubble(
                 mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
-        assertFalse(mNotificationShadeWindowController.getBubblesShowing());
         assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
         verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
 
         assertFalse(mSysUiStateBubblesExpanded);
     }
@@ -388,7 +380,6 @@
         assertTrue(mBubbleController.hasBubbles());
 
         mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
-        assertFalse(mNotificationShadeWindowController.getBubblesShowing());
         verify(mNotificationEntryManager, times(3)).updateNotifications(any());
         assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
         assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
@@ -408,14 +399,12 @@
         assertTrue(mBubbleController.hasBubbles());
         assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry()));
-        assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
 
         // Expand the stack
         BubbleStackView stackView = mBubbleController.getStackView();
         mBubbleData.setExpanded(true);
         assertTrue(mBubbleController.isStackExpanded());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
-        assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
 
         assertTrue(mSysUiStateBubblesExpanded);
 
@@ -427,7 +416,6 @@
         mBubbleController.collapseStack();
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
         assertFalse(mBubbleController.isStackExpanded());
-        assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
 
         assertFalse(mSysUiStateBubblesExpanded);
     }
@@ -553,7 +541,6 @@
         mEntryListener.onPendingEntryAdded(mRow2.getEntry());
         mBubbleController.updateBubble(mRow.getEntry());
         mBubbleController.updateBubble(mRow2.getEntry());
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
 
         // Expand
         BubbleStackView stackView = mBubbleController.getStackView();
@@ -588,7 +575,6 @@
 
         // Make sure state changes and collapse happens
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
         assertFalse(mBubbleController.hasBubbles());
 
         assertFalse(mSysUiStateBubblesExpanded);
@@ -609,9 +595,6 @@
                 mRow.getEntry().getKey());
         assertFalse(mBubbleController.isStackExpanded());
 
-        // # of bubbles should change
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
-
         assertFalse(mSysUiStateBubblesExpanded);
     }
 
@@ -629,9 +612,6 @@
                 mRow.getEntry().getKey());
         assertTrue(mBubbleController.isStackExpanded());
 
-        // # of bubbles should change
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
-
         assertTrue(mSysUiStateBubblesExpanded);
     }
 
@@ -651,9 +631,6 @@
         assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
         assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
 
-        // # of bubbles should change
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
-
         assertFalse(mSysUiStateBubblesExpanded);
     }
 
@@ -679,9 +656,6 @@
         assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
         assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
 
-        // # of bubbles should change
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
-
         assertFalse(mSysUiStateBubblesExpanded);
     }
 
@@ -716,7 +690,6 @@
         mEntryListener.onPendingEntryAdded(mNonBubbleNotifRow.getEntry());
         mEntryListener.onPreEntryUpdated(mNonBubbleNotifRow.getEntry());
 
-        verify(mBubbleStateChangeListener, never()).onHasBubblesChanged(anyBoolean());
         assertThat(mBubbleController.hasBubbles()).isFalse();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 23dfb7c..ec1a797 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -26,7 +26,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -150,8 +149,6 @@
     private ExpandableNotificationRow mRow2;
     private ExpandableNotificationRow mNonBubbleNotifRow;
     @Mock
-    private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
-    @Mock
     private BubbleController.BubbleExpandListener mBubbleExpandListener;
     @Mock
     private PendingIntent mDeleteIntent;
@@ -256,7 +253,6 @@
                 mSysUiState,
                 mock(INotificationManager.class));
         mBubbleController.addNotifCallback(mNotifCallback);
-        mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
         mBubbleController.setExpandListener(mBubbleExpandListener);
 
         // Get a reference to the BubbleController's entry listener
@@ -269,8 +265,6 @@
     public void testAddBubble() {
         mBubbleController.updateBubble(mRow.getEntry());
         assertTrue(mBubbleController.hasBubbles());
-
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
     }
 
     @Test
@@ -286,13 +280,10 @@
         assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
         assertTrue(mBubbleController.hasBubbles());
         verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
 
         mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
-        assertFalse(mNotificationShadeWindowController.getBubblesShowing());
         assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
         verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
     }
 
     @Test
@@ -347,7 +338,6 @@
         assertTrue(mBubbleController.hasBubbles());
 
         mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
-        assertFalse(mNotificationShadeWindowController.getBubblesShowing());
         verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
         assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
         assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
@@ -365,14 +355,12 @@
         assertTrue(mBubbleController.hasBubbles());
         assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry()));
-        assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
 
         // Expand the stack
         BubbleStackView stackView = mBubbleController.getStackView();
         mBubbleData.setExpanded(true);
         assertTrue(mBubbleController.isStackExpanded());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
-        assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
 
         // Make sure the notif is suppressed
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
@@ -381,7 +369,6 @@
         mBubbleController.collapseStack();
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
         assertFalse(mBubbleController.isStackExpanded());
-        assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
     }
 
     @Test
@@ -495,7 +482,6 @@
         mEntryListener.onEntryAdded(mRow2.getEntry());
         mBubbleController.updateBubble(mRow.getEntry());
         mBubbleController.updateBubble(mRow2.getEntry());
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
 
         // Expand
         BubbleStackView stackView = mBubbleController.getStackView();
@@ -528,7 +514,6 @@
 
         // Make sure state changes and collapse happens
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
         assertFalse(mBubbleController.hasBubbles());
     }
 
@@ -546,9 +531,6 @@
         verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
                 mRow.getEntry().getKey());
         assertFalse(mBubbleController.isStackExpanded());
-
-        // # of bubbles should change
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
     }
 
     @Test
@@ -564,9 +546,6 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
                 mRow.getEntry().getKey());
         assertTrue(mBubbleController.isStackExpanded());
-
-        // # of bubbles should change
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
     }
 
     @Test
@@ -584,9 +563,6 @@
         // Dot + flyout is hidden because notif is suppressed
         assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
         assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
-
-        // # of bubbles should change
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
     }
 
     @Test
@@ -610,9 +586,6 @@
         // Dot + flyout is hidden because notif is suppressed
         assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
         assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
-
-        // # of bubbles should change
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
     }
 
     @Test
@@ -630,7 +603,6 @@
         mEntryListener.onEntryAdded(mNonBubbleNotifRow.getEntry());
         mEntryListener.onEntryUpdated(mNonBubbleNotifRow.getEntry());
 
-        verify(mBubbleStateChangeListener, never()).onHasBubblesChanged(anyBoolean());
         assertThat(mBubbleController.hasBubbles()).isFalse();
     }