Bubble overflow - core functionality

BubbleStackView
- create show-overflow-button
- create expanded view to show overflow activity

BubbleOverflowActivity
- add adapter for recycler view of BadgedImageViews
- select bubble to promote it out of overflow, to first bubble in row

BubbleExpandedView
- create overflow intent
- add null bubble checks for overflow expanded view

BubbleData
- new list: overflow bubbles
- only repack bubbles in row (leave overflow order alone)
- update sortKey() to account for last access in addition to last
update. When users select a bubble to promote it out of overflow, it
counts as one access (instead of update); if sortKey does not check last
accessed time, the order is lost in the next repacking and the bubble goes
back to overflow.
- remove oldest bubbles if overflow bubble count > 16

BubbleController
- add callback that updates overflow activity when data changes
- allow overflow activity to set callback
- add/remove bubbles from bubble row ui

BadgedImageView
- set update() param to bubble only
- save other params in Bubble.java so that overflow can update
BadgedImageView with just a bubble

Bug: 138116789
Fixes: 148232991
Fixes: 148232992
Test: (manual) add 5+ bubbles: show-overflow-button shows in bubble row
Test: (manual) tap show-overflow-button: overflow shows aged out bubbles
Test: (manual) remove bubbles, count <= 5: overflow button hides
Test: (manual) tap bubble in overflow: bubble promoted to left of top row
Test: atest SystemUITests

Change-Id: I020ee4c9e16b236043c5cc244e610725e86bcc37
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index e642d4e..8c9946f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -103,6 +103,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.function.Consumer;
 
 import javax.inject.Inject;
@@ -151,6 +152,7 @@
     private BubbleData mBubbleData;
     @Nullable private BubbleStackView mStackView;
     private BubbleIconFactory mBubbleIconFactory;
+    private int mMaxBubbles;
 
     // Tracks the id of the current (foreground) user.
     private int mCurrentUserId;
@@ -171,6 +173,8 @@
     private StatusBarStateListener mStatusBarStateListener;
     private final ScreenshotHelper mScreenshotHelper;
 
+    // Callback that updates BubbleOverflowActivity on data change.
+    @Nullable private Runnable mOverflowCallback = null;
 
     private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     private IStatusBarService mBarService;
@@ -301,6 +305,7 @@
 
         mBubbleData = data;
         mBubbleData.setListener(mBubbleDataListener);
+        mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered);
 
         mNotificationEntryManager = entryManager;
         mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
@@ -370,6 +375,18 @@
         mInflateSynchronously = inflateSynchronously;
     }
 
+    void setOverflowCallback(Runnable updateOverflow) {
+        mOverflowCallback = updateOverflow;
+    }
+
+    /**
+     * @return Bubbles for updating overflow.
+     */
+    List<Bubble> getOverflowBubbles() {
+        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.
@@ -537,6 +554,10 @@
         mBubbleData.setSelectedBubble(bubble);
     }
 
+    void promoteBubbleFromOverflow(Bubble bubble) {
+        mBubbleData.promoteBubbleFromOverflow(bubble);
+    }
+
     /**
      * Request the stack expand if needed, then select the specified Bubble as current.
      *
@@ -817,6 +838,11 @@
 
         @Override
         public void applyUpdate(BubbleData.Update update) {
+            // Update bubbles in overflow.
+            if (mOverflowCallback != null) {
+                mOverflowCallback.run();
+            }
+
             if (update.addedBubble != null) {
                 mStackView.addBubble(update.addedBubble);
             }
@@ -890,6 +916,8 @@
                 mStackView.updateBubble(update.updatedBubble);
             }
 
+            // At this point, the correct bubbles are inflated in the stack.
+            // Make sure the order in bubble data is reflected in bubble row.
             if (update.orderChanged) {
                 mStackView.updateBubbleOrder(update.bubbles);
             }
@@ -912,15 +940,18 @@
             updateStack();
 
             if (DEBUG_BUBBLE_CONTROLLER) {
-                Log.d(TAG, "[BubbleData]");
+                Log.d(TAG, "\n[BubbleData] bubbles:");
                 Log.d(TAG, BubbleDebugConfig.formatBubblesString(mBubbleData.getBubbles(),
                         mBubbleData.getSelectedBubble()));
 
                 if (mStackView != null) {
-                    Log.d(TAG, "[BubbleStackView]");
+                    Log.d(TAG, "\n[BubbleStackView]");
                     Log.d(TAG, BubbleDebugConfig.formatBubblesString(mStackView.getBubblesOnScreen(),
                             mStackView.getExpandedBubble()));
                 }
+                Log.d(TAG, "\n[BubbleData] overflow:");
+                Log.d(TAG, BubbleDebugConfig.formatBubblesString(mBubbleData.getOverflowBubbles(),
+                        null));
             }
         }
     };