Visually suppress summaries & keep track of them so they may be removed when needed

When an actual group is swiped away, we keep the NotifEntry around so
that the app can cancel that group. This CL keeps track of those entries,
visually suppresses them, and removes them when all of the bubbles of that
group are also removed.

Test: manual
      1) have a group of bubbles with summary
      2) swipe away summary => observe that bubbles remain and
         that the summary remains hidden
      3) check dumpsys Bubble Controller => observe the summary suppressed
         check dumpsys Notification List => observe summary is in the list
      4) dismiss the bubble stack,
         check dumpsys Bubble Controller => summary key no longer there
         check dumpsys Notification List => summary is not in the list
Change-Id: Ib195c5cfa7099fbf8ec210024e11af4702337154
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index ca4c56f..46139b8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -424,14 +424,21 @@
     }
 
     /**
-     * Whether (1) there is a bubble associated with the provided key and
-     *         (2) if the notification for that bubble is hidden from the shade.
+     * True if either:
+     * (1) There is a bubble associated with the provided key and if its notification is hidden
+     *     from the shade.
+     * (2) There is a group summary associated with the provided key that is hidden from the shade
+     *     because it has been dismissed but still has child bubbles active.
      *
-     * False if there isn't a bubble or if the notification for that bubble appears in the shade.
+     * False otherwise.
      */
     public boolean isBubbleNotificationSuppressedFromShade(String key) {
-        return mBubbleData.hasBubbleWithKey(key)
+        boolean isBubbleAndSuppressed = mBubbleData.hasBubbleWithKey(key)
                 && !mBubbleData.getBubbleWithKey(key).showInShadeWhenBubble();
+        NotificationEntry entry = mNotificationEntryManager.getNotificationData().get(key);
+        String groupKey = entry != null ? entry.notification.getGroupKey() : null;
+        boolean isSuppressedSummary = mBubbleData.isSummarySuppressed(groupKey);
+        return isSuppressedSummary || isBubbleAndSuppressed;
     }
 
     void selectBubble(Bubble bubble) {
@@ -515,10 +522,12 @@
                 ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
 
                 boolean inBubbleData = mBubbleData.hasBubbleWithKey(key);
+                boolean isSuppressedSummary = (mBubbleData.isSummarySuppressed(groupKey)
+                        && mBubbleData.getSummaryKey(groupKey).equals(key));
                 boolean isSummary = entry != null
                         && entry.notification.getNotification().isGroupSummary();
-                boolean isSummaryOfBubbles = isSummary && bubbleChildren != null
-                        && !bubbleChildren.isEmpty();
+                boolean isSummaryOfBubbles = (isSuppressedSummary || isSummary)
+                        && bubbleChildren != null && !bubbleChildren.isEmpty();
 
                 if (!inBubbleData && !isSummaryOfBubbles) {
                     return false;
@@ -585,8 +594,17 @@
             // because apps can't cancel it; so we only intercept & suppress real summaries.
             boolean isAutogroupSummary = (summary.notification.getNotification().flags
                     & FLAG_AUTOGROUP_SUMMARY) != 0;
+            if (!isAutogroupSummary) {
+                mBubbleData.addSummaryToSuppress(summary.notification.getGroupKey(),
+                        summary.key);
+                // Tell shade to update for the suppression
+                mNotificationEntryManager.updateNotifications();
+            }
             return !isAutogroupSummary;
         } else {
+            // If it's not a user dismiss it's a cancel.
+            mBubbleData.removeSuppressedSummary(groupKey);
+
             // Remove any associated bubble children.
             for (int i = 0; i < bubbleChildren.size(); i++) {
                 Bubble bubbleChild = bubbleChildren.get(i);
@@ -686,6 +704,24 @@
                         }
                     }
 
+                    // Check if removed bubble has an associated suppressed group summary that needs
+                    // to be removed now.
+                    final String groupKey = bubble.getEntry().notification.getGroupKey();
+                    if (mBubbleData.isSummarySuppressed(groupKey)
+                            && mBubbleData.getBubblesInGroup(groupKey).isEmpty()) {
+                        // Time to actually remove the summary.
+                        String notifKey = mBubbleData.getSummaryKey(groupKey);
+                        mBubbleData.removeSuppressedSummary(groupKey);
+                        NotificationEntry entry =
+                                mNotificationEntryManager.getNotificationData().get(notifKey);
+                        if (entry == null) {
+                            Log.w("mady", "WTF summary isn't in data... " + notifKey);
+                            return;
+                        }
+                        mNotificationEntryManager.performRemoveNotification(
+                                entry.notification, UNDEFINED_DISMISS_REASON);
+                    }
+
                     // Check if summary should be removed from NoManGroup
                     NotificationEntry summary = mNotificationGroupManager.getLogicalGroupSummary(
                             bubble.getEntry().notification);