Handle PendingIntent cancellation v2

On cancel:
- Remove unopened bubble
- Mark opened bubble as canceled to skip overflowing later

Fixes: 152889099

Test: manual
1) Expand bubble with FLAG_ONE_SHOT PendingIntent => bubble NOT removed
2) Overflow bubble => bubble removed

Test: manual
1) Overflow bubble with FLAG_ONE_SHOT PendingIntent without expanding it
2) Promote bubble from overflow
3) Expand bubble => bubble NOT removed
4) Overflow bubble => bubble removed

Change-Id: I1657e84985ff1535205f8e32d1ace9dd3a3cc7ef
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 38bfffb..0dbee66 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -78,6 +78,7 @@
 
     private BubbleViewInfoTask mInflationTask;
     private boolean mInflateSynchronously;
+    private boolean mPendingIntentCanceled;
 
     /**
      * Presentational info about the flyout.
@@ -182,6 +183,14 @@
         mIconView = null;
     }
 
+    void setPendingIntentCanceled() {
+        mPendingIntentCanceled = true;
+    }
+
+    boolean getPendingIntentCanceled() {
+        return mPendingIntentCanceled;
+    }
+
     /**
      * Sets whether to perform inflation on the same thread as the caller. This method should only
      * be used in tests, not in production.
@@ -295,6 +304,13 @@
     }
 
     /**
+     * @return if the bubble was ever expanded
+     */
+    boolean getWasAccessed() {
+        return mLastAccessed != 0L;
+    }
+
+    /**
      * @return the display id of the virtual display on which bubble contents is drawn.
      */
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 5239a37..013f222 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -54,6 +54,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.service.notification.NotificationListenerService;
@@ -176,6 +177,9 @@
     private IStatusBarService mBarService;
     private SysUiState mSysUiState;
 
+    // Used to post to main UI thread
+    private Handler mHandler = new Handler();
+
     // Used for determining view rect for touch interaction
     private Rect mTempRect = new Rect();
 
@@ -808,7 +812,21 @@
         Bubble bubble = mBubbleData.getOrCreateBubble(notif);
         bubble.setInflateSynchronously(mInflateSynchronously);
         bubble.inflate(
-                b -> mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade),
+                b -> {
+                    mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade);
+                    if (bubble.getBubbleIntent() == null) {
+                        return;
+                    }
+                    bubble.getBubbleIntent().registerCancelListener(pendingIntent -> {
+                        if (bubble.getWasAccessed()) {
+                            bubble.setPendingIntentCanceled();
+                            return;
+                        }
+                        mHandler.post(
+                                () -> removeBubble(bubble.getEntry(),
+                                        BubbleController.DISMISS_INVALID_INTENT));
+                    });
+                },
                 mContext, mStackView, mBubbleIconFactory);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 2ac60f2..f2b1c03 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -480,7 +480,8 @@
     }
 
     void overflowBubble(@DismissReason int reason, Bubble bubble) {
-        if (!(reason == BubbleController.DISMISS_AGED
+        if (bubble.getPendingIntentCanceled()
+                || !(reason == BubbleController.DISMISS_AGED
                 || reason == BubbleController.DISMISS_USER_GESTURE)) {
             return;
         }