Handle when an Activity within a Bubble finishes

Bug: 123631242
Test: manual via test app, see go/bubbles-testing
Change-Id: I66e044116b029a53a16c723255484a0a22d940dc
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index e3f6add..0fc2b27 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -42,6 +42,8 @@
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 
+import androidx.annotation.MainThread;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dependency;
@@ -289,7 +291,10 @@
 
     /**
      * Removes the bubble associated with the {@param uri}.
+     * <p>
+     * Must be called from the main thread.
      */
+    @MainThread
     void removeBubble(String key) {
         BubbleView bv = mBubbles.remove(key);
         if (mStackView != null && bv != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index de322e6..ad7df4b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -287,19 +287,22 @@
     public void removeBubble(BubbleView bubbleView) {
         int removedIndex = mBubbleContainer.indexOfChild(bubbleView);
         mBubbleContainer.removeView(bubbleView);
-        boolean wasExpanded = mIsExpanded;
         int bubbleCount = mBubbleContainer.getChildCount();
-        if (mIsExpanded && bubbleView.equals(mExpandedBubble) && bubbleCount > 0) {
+        if (bubbleCount == 0) {
+            // If no bubbles remain, collapse the entire stack.
+            collapseStack();
+            return;
+        } else if (bubbleView.equals(mExpandedBubble)) {
+            // Was the current bubble just removed?
             // If we have other bubbles and are expanded go to the next one or previous
             // if the bubble removed was last
             int nextIndex = bubbleCount > removedIndex ? removedIndex : bubbleCount - 1;
             BubbleView expandedBubble = (BubbleView) mBubbleContainer.getChildAt(nextIndex);
-            setExpandedBubble(expandedBubble);
-            requestUpdate();
-        }
-        mIsExpanded = wasExpanded && mBubbleContainer.getChildCount() > 0;
-        if (wasExpanded != mIsExpanded) {
-            notifyExpansionChanged(mExpandedBubble, mIsExpanded);
+            if (mIsExpanded) {
+                setExpandedBubble(expandedBubble);
+            } else {
+                mExpandedBubble = null;
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index dc94832..2c23c0c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -37,6 +37,7 @@
 import android.widget.TextView;
 
 import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -59,6 +60,7 @@
 
     private NotificationEntry mEntry;
     private PendingIntent mAppOverlayIntent;
+    private BubbleController mBubbleController;
     private ActivityView mActivityView;
     private boolean mActivityViewReady;
     private boolean mActivityViewStarted;
@@ -81,6 +83,7 @@
         // XXX: can this padding just be on the view and we look it up?
         mPadding = getResources().getDimensionPixelSize(R.dimen.bubble_view_padding);
         mIconInset = getResources().getDimensionPixelSize(R.dimen.bubble_icon_inset);
+        mBubbleController = Dependency.get(BubbleController.class);
     }
 
     @Override
@@ -248,6 +251,20 @@
                 public void onActivityViewDestroyed(ActivityView view) {
                     mActivityViewReady = false;
                 }
+
+                /**
+                 * This is only called for tasks on this ActivityView, which is also set to
+                 * single-task mode -- meaning never more than one task on this display. If a task
+                 * is being removed, it's the top Activity finishing and this bubble should
+                 * be removed or collapsed.
+                 */
+                @Override
+                public void onTaskRemovalStarted(int taskId) {
+                    if (mEntry != null) {
+                        // Must post because this is called from a binder thread.
+                        post(() -> mBubbleController.removeBubble(mEntry.key));
+                    }
+                }
             });
         }
         return mActivityView;