Add Bubbles and BubblesListener to SystemUiProxy and use it

Adds a method to call into WMShell to set the listener and
indicate when a bubble is shown or when the expanded state
changes.

BubbleBarController sets or clears out the listener.

BubbleBarViewController calls SystemUiProxy when bubbles are shown
or when the expanded state changes.

Bug: 253318833
Test: manual, with other CLs, see go/bubble-bar-tests
Flag: WM_BUBBLE_BAR
Change-Id: I2364b9bbdea237fc268b0999d9c896585c194a86
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 228aabd..a466548 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -152,7 +152,9 @@
         mContext = context;
         mBarView = bubbleView; // Need the view for inflating bubble views.
 
-        // TODO: register the listener with SysUiProxu
+        if (BUBBLE_BAR_ENABLED) {
+            SystemUiProxy.INSTANCE.get(context).setBubblesListener(this);
+        }
         mMainExecutor = MAIN_EXECUTOR;
         mLauncherApps = context.getSystemService(LauncherApps.class);
         mIconFactory = new BubbleIconFactory(context,
@@ -164,7 +166,7 @@
     }
 
     public void onDestroy() {
-        // TODO: unregister the listener with SysUiProxy
+        SystemUiProxy.INSTANCE.get(mContext).setBubblesListener(null);
     }
 
     public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 0afc2cb..82494c6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -30,6 +30,7 @@
 import com.android.launcher3.taskbar.TaskbarControllers;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
+import com.android.quickstep.SystemUiProxy;
 
 import java.util.List;
 import java.util.Objects;
@@ -42,6 +43,7 @@
 
     private static final String TAG = BubbleBarViewController.class.getSimpleName();
 
+    private final SystemUiProxy mSystemUiProxy;
     private final TaskbarActivityContext mActivity;
     private final BubbleBarView mBarView;
     private final int mIconSize;
@@ -69,6 +71,7 @@
     public BubbleBarViewController(TaskbarActivityContext activity, BubbleBarView barView) {
         mActivity = activity;
         mBarView = barView;
+        mSystemUiProxy = SystemUiProxy.INSTANCE.get(mActivity);
         mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
         mBubbleBarAlpha.setUpdateVisibility(true);
         mIconSize = activity.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
@@ -101,7 +104,8 @@
             mBubbleStashController.stashBubbleBar();
         } else {
             mBubbleBarController.setSelectedBubble(bubble);
-            // TODO: Tell SysUi to show the expanded view for this bubble.
+            mSystemUiProxy.showBubble(bubble.getKey(),
+                    mBubbleStashController.isBubblesShowingOnHome());
         }
     }
 
@@ -270,11 +274,12 @@
         if (isExpanded != mBarView.isExpanded()) {
             mBarView.setExpanded(isExpanded);
             if (!isExpanded) {
-                // TODO: Tell SysUi to collapse the bubble
+                mSystemUiProxy.collapseBubbles();
             } else {
                 final String selectedKey = mBubbleBarController.getSelectedBubbleKey();
                 if (selectedKey != null) {
-                    // TODO: Tell SysUi to show the bubble
+                    mSystemUiProxy.showBubble(selectedKey,
+                            mBubbleStashController.isBubblesShowingOnHome());
                 } else {
                     Log.w(TAG, "trying to expand bubbles when there isn't one selected");
                 }
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 36aa6f5..0549d9f 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -71,6 +71,8 @@
 import com.android.systemui.unfold.progress.IUnfoldAnimation;
 import com.android.systemui.unfold.progress.IUnfoldTransitionListener;
 import com.android.wm.shell.back.IBackAnimation;
+import com.android.wm.shell.bubbles.IBubbles;
+import com.android.wm.shell.bubbles.IBubblesListener;
 import com.android.wm.shell.desktopmode.IDesktopMode;
 import com.android.wm.shell.draganddrop.IDragAndDrop;
 import com.android.wm.shell.onehanded.IOneHanded;
@@ -103,6 +105,7 @@
 
     private ISystemUiProxy mSystemUiProxy;
     private IPip mPip;
+    private IBubbles mBubbles;
     private ISysuiUnlockAnimationController mSysuiUnlockAnimationController;
     private ISplitScreen mSplitScreen;
     private IOneHanded mOneHanded;
@@ -121,6 +124,7 @@
     // up to the caller to clear the listeners to prevent leaks as these can be held indefinitely
     // in case SysUI needs to rebind.
     private IPipAnimationListener mPipAnimationListener;
+    private IBubblesListener mBubblesListener;
     private ISplitScreenListener mSplitScreenListener;
     private IStartingWindowListener mStartingWindowListener;
     private ILauncherUnlockAnimationController mLauncherUnlockAnimationController;
@@ -206,7 +210,7 @@
      * Sets proxy state, including death linkage, various listeners, and other configuration objects
      */
     @MainThread
-    public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen,
+    public void setProxy(ISystemUiProxy proxy, IPip pip, IBubbles bubbles, ISplitScreen splitScreen,
             IOneHanded oneHanded, IShellTransitions shellTransitions,
             IStartingWindow startingWindow, IRecentTasks recentTasks,
             ISysuiUnlockAnimationController sysuiUnlockAnimationController,
@@ -216,6 +220,7 @@
         unlinkToDeath();
         mSystemUiProxy = proxy;
         mPip = pip;
+        mBubbles = bubbles;
         mSplitScreen = splitScreen;
         mOneHanded = oneHanded;
         mShellTransitions = shellTransitions;
@@ -229,6 +234,7 @@
         linkToDeath();
         // re-attach the listeners once missing due to setProxy has not been initialized yet.
         setPipAnimationListener(mPipAnimationListener);
+        setBubblesListener(mBubblesListener);
         registerSplitScreenListener(mSplitScreenListener);
         setStartingWindowListener(mStartingWindowListener);
         setLauncherUnlockAnimationController(mLauncherUnlockAnimationController);
@@ -244,7 +250,7 @@
      */
     @MainThread
     public void clearProxy() {
-        setProxy(null, null, null, null, null, null, null, null, null, null, null, null);
+        setProxy(null, null, null, null, null, null, null, null, null, null, null, null, null);
     }
 
     // TODO(141886704): Find a way to remove this
@@ -585,6 +591,59 @@
     }
 
     //
+    // Bubbles
+    //
+
+    /**
+     * Sets the listener to be notified of bubble state changes.
+     */
+    public void setBubblesListener(IBubblesListener listener) {
+        if (mBubbles != null) {
+            try {
+                if (mBubblesListener != null) {
+                    // Clear out any previous listener
+                    mBubbles.unregisterBubbleListener(mBubblesListener);
+                }
+                if (listener != null) {
+                    mBubbles.registerBubbleListener(listener);
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call registerBubblesListener");
+            }
+        }
+        mBubblesListener = listener;
+    }
+
+    /**
+     * Tells SysUI to show the bubble with the provided key.
+     * @param key the key of the bubble to show.
+     * @param onLauncherHome whether the bubble is showing on launcher home or not (modifies where
+     *                       the expanded bubble view is placed).
+     */
+    public void showBubble(String key, boolean onLauncherHome) {
+        if (mBubbles != null) {
+            try {
+                mBubbles.showBubble(key, onLauncherHome);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call showBubble");
+            }
+        }
+    }
+
+    /**
+     * Tells SysUI to collapse the bubbles.
+     */
+    public void collapseBubbles() {
+        if (mBubbles != null) {
+            try {
+                mBubbles.collapseBubbles();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call collapseBubbles");
+            }
+        }
+    }
+
+    //
     // Splitscreen
     //
 
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 66aeee7..682763f 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -43,6 +43,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED;
@@ -126,6 +127,7 @@
 import com.android.systemui.shared.tracing.ProtoTraceable;
 import com.android.systemui.unfold.progress.IUnfoldAnimation;
 import com.android.wm.shell.back.IBackAnimation;
+import com.android.wm.shell.bubbles.IBubbles;
 import com.android.wm.shell.desktopmode.IDesktopMode;
 import com.android.wm.shell.draganddrop.IDragAndDrop;
 import com.android.wm.shell.onehanded.IOneHanded;
@@ -169,6 +171,7 @@
             ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface(
                     bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
             IPip pip = IPip.Stub.asInterface(bundle.getBinder(KEY_EXTRA_SHELL_PIP));
+            IBubbles bubbles = IBubbles.Stub.asInterface(bundle.getBinder(KEY_EXTRA_SHELL_BUBBLES));
             ISplitScreen splitscreen = ISplitScreen.Stub.asInterface(bundle.getBinder(
                     KEY_EXTRA_SHELL_SPLIT_SCREEN));
             IOneHanded onehanded = IOneHanded.Stub.asInterface(
@@ -192,7 +195,7 @@
                     bundle.getBinder(KEY_EXTRA_SHELL_DRAG_AND_DROP));
             MAIN_EXECUTOR.execute(() -> {
                 SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip,
-                        splitscreen, onehanded, shellTransitions, startingWindow,
+                        bubbles, splitscreen, onehanded, shellTransitions, startingWindow,
                         recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode,
                         unfoldTransition, dragAndDrop);
                 TouchInteractionService.this.initInputMonitor("TISBinder#onInitialize()");