Collapse bubble stack when other activity brought to top
Bug: 123631582
Test: manually
Change-Id: I1f1708bff2fc632797cafd45a4ab7bcbab6bc27d
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index b15c5de..41bc1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -28,6 +28,9 @@
import static com.android.systemui.statusbar.notification.NotificationAlertingManager.alertAgain;
import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -35,11 +38,13 @@
import android.content.pm.ActivityInfo;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.util.StatsLog;
+import android.view.Display;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -52,6 +57,8 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
@@ -60,6 +67,7 @@
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -93,6 +101,8 @@
private final Context mContext;
private final NotificationEntryManager mNotificationEntryManager;
+ private final IActivityTaskManager mActivityTaskManager;
+ private final BubbleTaskStackListener mTaskStackListener;
private BubbleStateChangeListener mStateChangeListener;
private BubbleExpandListener mExpandListener;
private LayoutInflater mInflater;
@@ -176,6 +186,10 @@
mStatusBarWindowController = statusBarWindowController;
mStatusBarStateListener = new StatusBarStateListener();
Dependency.get(StatusBarStateController.class).addCallback(mStatusBarStateListener);
+
+ mActivityTaskManager = ActivityTaskManager.getService();
+ mTaskStackListener = new BubbleTaskStackListener();
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
}
/**
@@ -533,6 +547,64 @@
|| autoBubbleAll;
}
+ /**
+ * This task stack listener is responsible for responding to tasks moved to the front
+ * which are on the default (main) display. When this happens, expanded bubbles must be
+ * collapsed so the user may interact with the app which was just moved to the front.
+ * <p>
+ * This listener is registered with SystemUI's ActivityManagerWrapper which dispatches
+ * these calls via a main thread Handler.
+ */
+ @MainThread
+ private class BubbleTaskStackListener extends TaskStackChangeListener {
+
+ @Nullable
+ private ActivityManager.StackInfo findStackInfo(int taskId) throws RemoteException {
+ final List<ActivityManager.StackInfo> stackInfoList =
+ mActivityTaskManager.getAllStackInfos();
+ // Iterate through stacks from top to bottom.
+ final int stackCount = stackInfoList.size();
+ for (int stackIndex = 0; stackIndex < stackCount; stackIndex++) {
+ final ActivityManager.StackInfo stackInfo = stackInfoList.get(stackIndex);
+ // Iterate through tasks from top to bottom.
+ for (int taskIndex = stackInfo.taskIds.length - 1; taskIndex >= 0; taskIndex--) {
+ if (stackInfo.taskIds[taskIndex] == taskId) {
+ return stackInfo;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void onTaskMovedToFront(int taskId) {
+ ActivityManager.StackInfo stackInfo = null;
+ try {
+ stackInfo = findStackInfo(taskId);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ if (stackInfo != null && stackInfo.displayId == Display.DEFAULT_DISPLAY
+ && mStackView != null) {
+ mStackView.collapseStack();
+ }
+ }
+
+ /**
+ * This is a workaround for the case when the activity had to be created in a new task.
+ * Existing code in ActivityStackSupervisor checks the display where the activity
+ * ultimately ended up, displays an error message toast, and calls this method instead of
+ * onTaskMovedToFront.
+ */
+ // TODO(b/124058588): add requestedDisplayId to this callback, ignore unless matches
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayFailed() {
+ if (mStackView != null) {
+ mStackView.collapseStack();
+ }
+ }
+ }
+
private static boolean shouldAutoBubbleMessages(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
ENABLE_AUTO_BUBBLE_MESSAGES, 0) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 305f866..f6f3fa6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -41,6 +41,7 @@
import android.widget.FrameLayout;
import android.widget.LinearLayout;
+import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
@@ -384,7 +385,10 @@
/**
* Collapses the stack of bubbles.
+ * <p>
+ * Must be called from the main thread.
*/
+ @MainThread
public void collapseStack() {
if (mIsExpanded) {
// TODO: Save opened bubble & move it to top of stack
@@ -402,7 +406,10 @@
/**
* Expands the stack fo bubbles.
+ * <p>
+ * Must be called from the main thread.
*/
+ @MainThread
public void expandStack() {
if (!mIsExpanded) {
mExpandedBubble = getTopBubble();