Merge "8/ Updating bubbles to run on shell thread" into sc-dev
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 122f917..ffeabd8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -49,6 +49,7 @@
import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* Encapsulates the data and UI elements of a bubble.
@@ -58,6 +59,7 @@
private static final String TAG = "Bubble";
private final String mKey;
+ private final Executor mMainExecutor;
private long mLastUpdated;
private long mLastAccessed;
@@ -156,7 +158,8 @@
* Note: Currently this is only being used when the bubble is persisted to disk.
*/
Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
- final int desiredHeight, final int desiredHeightResId, @Nullable final String title) {
+ final int desiredHeight, final int desiredHeightResId, @Nullable final String title,
+ Executor mainExecutor) {
Objects.requireNonNull(key);
Objects.requireNonNull(shortcutInfo);
mMetadataShortcutId = shortcutInfo.getId();
@@ -170,20 +173,25 @@
mDesiredHeightResId = desiredHeightResId;
mTitle = title;
mShowBubbleUpdateDot = false;
+ mMainExecutor = mainExecutor;
}
@VisibleForTesting(visibility = PRIVATE)
Bubble(@NonNull final BubbleEntry entry,
@Nullable final Bubbles.NotificationSuppressionChangedListener listener,
- final Bubbles.PendingIntentCanceledListener intentCancelListener) {
+ final Bubbles.PendingIntentCanceledListener intentCancelListener,
+ Executor mainExecutor) {
mKey = entry.getKey();
mSuppressionListener = listener;
mIntentCancelListener = intent -> {
if (mIntent != null) {
mIntent.unregisterCancelListener(mIntentCancelListener);
}
- intentCancelListener.onPendingIntentCanceled(this);
+ mainExecutor.execute(() -> {
+ intentCancelListener.onPendingIntentCanceled(this);
+ });
};
+ mMainExecutor = mainExecutor;
setEntry(entry);
}
@@ -329,7 +337,8 @@
stackView,
iconFactory,
skipInflation,
- callback);
+ callback,
+ mMainExecutor);
if (mInflateSynchronously) {
mInflationTask.onPostExecute(mInflationTask.doInBackground());
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 9419b9c..7538c8b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -28,6 +28,16 @@
import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_LEFT;
import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_NONE;
import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_RIGHT;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_AGED;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_BLOCKED;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_GROUP_CANCELLED;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_INVALID_INTENT;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_NOTIF_CANCEL;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_NO_BUBBLE_UP;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_NO_LONGER_BUBBLE;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_PACKAGE_REMOVED;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_SHORTCUT_REMOVED;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_CHANGED;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -45,6 +55,8 @@
import android.graphics.PointF;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -53,6 +65,7 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
+import android.util.Slog;
import android.util.SparseSetArray;
import android.view.View;
import android.view.ViewGroup;
@@ -75,6 +88,9 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import java.util.function.IntConsumer;
/**
@@ -83,7 +99,7 @@
*
* The controller manages addition, removal, and visible state of bubbles on screen.
*/
-public class BubbleController implements Bubbles {
+public class BubbleController {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES;
@@ -101,7 +117,8 @@
public static final String BOTTOM_POSITION = "Bottom";
private final Context mContext;
- private BubbleExpandListener mExpandListener;
+ private final BubblesImpl mImpl = new BubblesImpl();
+ private Bubbles.BubbleExpandListener mExpandListener;
@Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
private final FloatingContentCoordinator mFloatingContentCoordinator;
private final BubbleDataRepository mDataRepository;
@@ -111,7 +128,7 @@
@Nullable private BubbleStackView mStackView;
private BubbleIconFactory mBubbleIconFactory;
private BubblePositioner mBubblePositioner;
- private SysuiProxy mSysuiProxy;
+ private Bubbles.SysuiProxy mSysuiProxy;
// Tracks the id of the current (foreground) user.
private int mCurrentUserId;
@@ -177,7 +194,7 @@
/**
* Injected constructor.
*/
- public static BubbleController create(Context context,
+ public static Bubbles create(Context context,
@Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
FloatingContentCoordinator floatingContentCoordinator,
@Nullable IStatusBarService statusBarService,
@@ -186,14 +203,15 @@
LauncherApps launcherApps,
UiEventLogger uiEventLogger,
ShellTaskOrganizer organizer,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ Handler mainHandler) {
BubbleLogger logger = new BubbleLogger(uiEventLogger);
BubblePositioner positioner = new BubblePositioner(context, windowManager);
- BubbleData data = new BubbleData(context, logger, positioner);
+ BubbleData data = new BubbleData(context, logger, positioner, mainExecutor);
return new BubbleController(context, data, synchronizer, floatingContentCoordinator,
- new BubbleDataRepository(context, launcherApps),
+ new BubbleDataRepository(context, launcherApps, mainExecutor),
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
- logger, organizer, positioner, mainExecutor);
+ logger, organizer, positioner, mainExecutor, mainHandler).mImpl;
}
/**
@@ -212,7 +230,8 @@
BubbleLogger bubbleLogger,
ShellTaskOrganizer organizer,
BubblePositioner positioner,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ Handler mainHandler) {
mContext = context;
mFloatingContentCoordinator = floatingContentCoordinator;
mDataRepository = dataRepository;
@@ -299,7 +318,12 @@
mBubbleData.removeBubblesWithInvalidShortcuts(
packageName, validShortcuts, DISMISS_SHORTCUT_REMOVED);
}
- });
+ }, mainHandler);
+ }
+
+ @VisibleForTesting
+ public Bubbles getImpl() {
+ return mImpl;
}
/**
@@ -313,8 +337,7 @@
}
}
- @Override
- public void openBubbleOverflow() {
+ private void openBubbleOverflow() {
ensureStackViewCreated();
mBubbleData.setShowingOverflow(true);
mBubbleData.setSelectedBubble(mBubbleData.getOverflow());
@@ -322,8 +345,7 @@
}
/** Called when any taskbar state changes (e.g. visibility, position, sizes). */
- @Override
- public void onTaskbarChanged(Bundle b) {
+ private void onTaskbarChanged(Bundle b) {
if (b == null) {
return;
}
@@ -371,8 +393,7 @@
* Called when the status bar has become visible or invisible (either permanently or
* temporarily).
*/
- @Override
- public void onStatusBarVisibilityChanged(boolean visible) {
+ private void onStatusBarVisibilityChanged(boolean visible) {
if (mStackView != null) {
// Hide the stack temporarily if the status bar has been made invisible, and the stack
// is collapsed. An expanded stack should remain visible until collapsed.
@@ -380,15 +401,13 @@
}
}
- @Override
- public void onZenStateChanged() {
+ private void onZenStateChanged() {
for (Bubble b : mBubbleData.getBubbles()) {
b.setShowDot(b.showInShade());
}
}
- @Override
- public void onStatusBarStateChanged(boolean isShade) {
+ private void onStatusBarStateChanged(boolean isShade) {
mIsStatusBarShade = isShade;
if (!mIsStatusBarShade) {
collapseStack();
@@ -402,8 +421,7 @@
updateStack();
}
- @Override
- public void onUserChanged(int newUserId) {
+ private void onUserChanged(int newUserId) {
saveBubbles(mCurrentUserId);
mBubbleData.dismissAll(DISMISS_USER_CHANGED);
restoreBubbles(newUserId);
@@ -442,7 +460,7 @@
return mBubblePositioner;
}
- SysuiProxy getSysuiProxy() {
+ Bubbles.SysuiProxy getSysuiProxy() {
return mSysuiProxy;
}
@@ -453,7 +471,8 @@
private void ensureStackViewCreated() {
if (mStackView == null) {
mStackView = new BubbleStackView(
- mContext, this, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator);
+ mContext, this, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
+ mMainExecutor);
mStackView.onOrientationChanged();
if (mExpandListener != null) {
mStackView.setExpandListener(mExpandListener);
@@ -576,8 +595,7 @@
mSavedBubbleKeysPerUser.remove(mCurrentUserId);
}
- @Override
- public void updateForThemeChanges() {
+ private void updateForThemeChanges() {
if (mStackView != null) {
mStackView.onThemeChanged();
}
@@ -593,8 +611,7 @@
}
}
- @Override
- public void onConfigChanged(Configuration newConfig) {
+ private void onConfigChanged(Configuration newConfig) {
if (mBubblePositioner != null) {
// This doesn't trigger any changes, always update it
mBubblePositioner.update(newConfig.orientation);
@@ -620,18 +637,19 @@
}
}
- @Override
- public void setBubbleScrim(View view) {
+ private void setBubbleScrim(View view, BiConsumer<Executor, Looper> callback) {
mBubbleScrim = view;
+ callback.accept(mMainExecutor, mMainExecutor.executeBlockingForResult(() -> {
+ return Looper.myLooper();
+ }, Looper.class));
}
- @Override
- public void setSysuiProxy(SysuiProxy proxy) {
+ private void setSysuiProxy(Bubbles.SysuiProxy proxy) {
mSysuiProxy = proxy;
}
- @Override
- public void setExpandListener(BubbleExpandListener listener) {
+ @VisibleForTesting
+ public void setExpandListener(Bubbles.BubbleExpandListener listener) {
mExpandListener = ((isExpanding, key) -> {
if (listener != null) {
listener.onBubbleExpandChanged(isExpanding, key);
@@ -654,17 +672,17 @@
return mBubbleData.hasBubbles() || mBubbleData.isShowingOverflow();
}
- @Override
+ @VisibleForTesting
public boolean isStackExpanded() {
return mBubbleData.isExpanded();
}
- @Override
+ @VisibleForTesting
public void collapseStack() {
mBubbleData.setExpanded(false /* expanded */);
}
- @Override
+ @VisibleForTesting
public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) {
boolean isSuppressedBubble = (mBubbleData.hasAnyBubbleWithKey(key)
&& !mBubbleData.getAnyBubbleWithkey(key).showInShade());
@@ -674,23 +692,19 @@
return (isSummary && isSuppressedSummary) || isSuppressedBubble;
}
- @Override
- public boolean isSummarySuppressed(String groupKey) {
- return mBubbleData.isSummarySuppressed(groupKey);
+ private void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback,
+ Executor callbackExecutor) {
+ if (mBubbleData.isSummarySuppressed(groupKey)) {
+ mBubbleData.removeSuppressedSummary(groupKey);
+ if (callback != null) {
+ callbackExecutor.execute(() -> {
+ callback.accept(mBubbleData.getSummaryKey(groupKey));
+ });
+ }
+ }
}
- @Override
- public void removeSuppressedSummary(String groupKey) {
- mBubbleData.removeSuppressedSummary(groupKey);
- }
-
- @Override
- public String getSummaryKey(String groupKey) {
- return mBubbleData.getSummaryKey(groupKey);
- }
-
- @Override
- public boolean isBubbleExpanded(String key) {
+ private boolean isBubbleExpanded(String key) {
return isStackExpanded() && mBubbleData != null && mBubbleData.getSelectedBubble() != null
&& mBubbleData.getSelectedBubble().getKey().equals(key);
}
@@ -704,7 +718,7 @@
setIsBubble(bubble, true /* isBubble */);
}
- @Override
+ @VisibleForTesting
public void expandStackAndSelectBubble(BubbleEntry entry) {
if (mIsStatusBarShade) {
mNotifEntryToExpandOnShadeUnlock = null;
@@ -809,15 +823,13 @@
}
}
- @Override
- public void onEntryAdded(BubbleEntry entry) {
+ private void onEntryAdded(BubbleEntry entry) {
if (canLaunchInActivityView(mContext, entry)) {
updateBubble(entry);
}
}
- @Override
- public void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp) {
+ private void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp) {
// shouldBubbleUp checks canBubble & for bubble metadata
boolean shouldBubble = shouldBubbleUp && canLaunchInActivityView(mContext, entry);
if (!shouldBubble && mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
@@ -828,8 +840,7 @@
}
}
- @Override
- public void onEntryRemoved(BubbleEntry entry) {
+ private void onEntryRemoved(BubbleEntry entry) {
if (isSummaryOfBubbles(entry)) {
final String groupKey = entry.getStatusBarNotification().getGroupKey();
mBubbleData.removeSuppressedSummary(groupKey);
@@ -844,8 +855,7 @@
}
}
- @Override
- public void onRankingUpdated(RankingMap rankingMap) {
+ private void onRankingUpdated(RankingMap rankingMap) {
if (mTmpRanking == null) {
mTmpRanking = new NotificationListenerService.Ranking();
}
@@ -882,6 +892,8 @@
return bubbleChildren;
}
for (Bubble bubble : mBubbleData.getActiveBubbles()) {
+ // TODO(178620678): Prevent calling into SysUI since this can be a part of a blocking
+ // call from SysUI to Shell
final BubbleEntry entry = mSysuiProxy.getPendingOrActiveEntry(bubble.getKey());
if (entry != null && groupKey.equals(entry.getStatusBarNotification().getGroupKey())) {
bubbleChildren.add(bubble);
@@ -951,7 +963,7 @@
ArrayList<Bubble> bubblesToBeRemovedFromRepository = new ArrayList<>();
for (Pair<Bubble, Integer> removed : removedBubbles) {
final Bubble bubble = removed.first;
- @DismissReason final int reason = removed.second;
+ @Bubbles.DismissReason final int reason = removed.second;
if (mStackView != null) {
mStackView.removeBubble(bubble);
@@ -1029,8 +1041,7 @@
}
};
- @Override
- public boolean handleDismissalInterception(BubbleEntry entry,
+ private boolean handleDismissalInterception(BubbleEntry entry,
@Nullable List<BubbleEntry> children, IntConsumer removeCallback) {
if (isSummaryOfBubbles(entry)) {
handleSummaryDismissalInterception(entry, children, removeCallback);
@@ -1137,8 +1148,7 @@
/**
* Description of current bubble state.
*/
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ private void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("BubbleController state:");
mBubbleData.dump(fd, pw, args);
pw.println();
@@ -1216,4 +1226,175 @@
}
}
}
+
+ private class BubblesImpl implements Bubbles {
+ @Override
+ public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return BubbleController.this.isBubbleNotificationSuppressedFromShade(key, groupKey);
+ }, Boolean.class);
+ }
+
+ @Override
+ public boolean isBubbleExpanded(String key) {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return BubbleController.this.isBubbleExpanded(key);
+ }, Boolean.class);
+ }
+
+ @Override
+ public boolean isStackExpanded() {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return BubbleController.this.isStackExpanded();
+ }, Boolean.class);
+ }
+
+ @Override
+ public void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback,
+ Executor callbackExecutor) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.removeSuppressedSummaryIfNecessary(groupKey, callback,
+ callbackExecutor);
+ });
+ }
+
+ @Override
+ public void collapseStack() {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.collapseStack();
+ });
+ }
+
+ @Override
+ public void updateForThemeChanges() {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.updateForThemeChanges();
+ });
+ }
+
+ @Override
+ public void expandStackAndSelectBubble(BubbleEntry entry) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.expandStackAndSelectBubble(entry);
+ });
+ }
+
+ @Override
+ public void onTaskbarChanged(Bundle b) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onTaskbarChanged(b);
+ });
+ }
+
+ @Override
+ public void openBubbleOverflow() {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.openBubbleOverflow();
+ });
+ }
+
+ @Override
+ public boolean handleDismissalInterception(BubbleEntry entry,
+ @Nullable List<BubbleEntry> children, IntConsumer removeCallback) {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return BubbleController.this.handleDismissalInterception(entry, children,
+ removeCallback);
+ }, Boolean.class);
+ }
+
+ @Override
+ public void setSysuiProxy(SysuiProxy proxy) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.setSysuiProxy(proxy);
+ });
+ }
+
+ @Override
+ public void setBubbleScrim(View view, BiConsumer<Executor, Looper> callback) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.setBubbleScrim(view, callback);
+ });
+ }
+
+ @Override
+ public void setExpandListener(BubbleExpandListener listener) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.setExpandListener(listener);
+ });
+ }
+
+ @Override
+ public void onEntryAdded(BubbleEntry entry) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onEntryAdded(entry);
+ });
+ }
+
+ @Override
+ public void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onEntryUpdated(entry, shouldBubbleUp);
+ });
+ }
+
+ @Override
+ public void onEntryRemoved(BubbleEntry entry) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onEntryRemoved(entry);
+ });
+ }
+
+ @Override
+ public void onRankingUpdated(RankingMap rankingMap) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onRankingUpdated(rankingMap);
+ });
+ }
+
+ @Override
+ public void onStatusBarVisibilityChanged(boolean visible) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onStatusBarVisibilityChanged(visible);
+ });
+ }
+
+ @Override
+ public void onZenStateChanged() {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onZenStateChanged();
+ });
+ }
+
+ @Override
+ public void onStatusBarStateChanged(boolean isShade) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onStatusBarStateChanged(isShade);
+ });
+ }
+
+ @Override
+ public void onUserChanged(int newUserId) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onUserChanged(newUserId);
+ });
+ }
+
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onConfigChanged(newConfig);
+ });
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ try {
+ mMainExecutor.executeBlocking(() -> {
+ BubbleController.this.dump(fd, pw, args);
+ });
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Failed to dump BubbleController in 2s");
+ }
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index e24ff06..9d196ba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -46,6 +46,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -117,6 +118,7 @@
private final Context mContext;
private final BubblePositioner mPositioner;
+ private final Executor mMainExecutor;
/** Bubbles that are actively in the stack. */
private final List<Bubble> mBubbles;
/** Bubbles that aged out to overflow. */
@@ -155,10 +157,12 @@
*/
private HashMap<String, String> mSuppressedGroupKeys = new HashMap<>();
- public BubbleData(Context context, BubbleLogger bubbleLogger, BubblePositioner positioner) {
+ public BubbleData(Context context, BubbleLogger bubbleLogger, BubblePositioner positioner,
+ Executor mainExecutor) {
mContext = context;
mLogger = bubbleLogger;
mPositioner = positioner;
+ mMainExecutor = mainExecutor;
mOverflow = new BubbleOverflow(context, positioner);
mBubbles = new ArrayList<>();
mOverflowBubbles = new ArrayList<>();
@@ -264,7 +268,8 @@
bubbleToReturn = mPendingBubbles.get(key);
} else if (entry != null) {
// New bubble
- bubbleToReturn = new Bubble(entry, mSuppressionListener, mCancelledListener);
+ bubbleToReturn = new Bubble(entry, mSuppressionListener, mCancelledListener,
+ mMainExecutor);
} else {
// Persisted bubble being promoted
bubbleToReturn = persistedBubble;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index fc565f1..3108b02 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -27,6 +27,8 @@
import com.android.wm.shell.bubbles.storage.BubbleEntity
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
import com.android.wm.shell.bubbles.storage.BubbleVolatileRepository
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.common.annotations.ExternalThread
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -34,12 +36,12 @@
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
-internal class BubbleDataRepository(context: Context, private val launcherApps: LauncherApps) {
+internal class BubbleDataRepository(context: Context, private val launcherApps: LauncherApps,
+ private val mainExecutor : ShellExecutor) {
private val volatileRepository = BubbleVolatileRepository(launcherApps)
private val persistentRepository = BubblePersistentRepository(context)
private val ioScope = CoroutineScope(Dispatchers.IO)
- private val uiScope = CoroutineScope(Dispatchers.Main)
private var job: Job? = null
/**
@@ -109,6 +111,8 @@
/**
* Load bubbles from disk.
+ * @param cb The callback to be run after the bubbles are loaded. This callback is always made
+ * on the main thread of the hosting process.
*/
@SuppressLint("WrongConstant")
fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch {
@@ -163,10 +167,11 @@
shortcutInfo,
entity.desiredHeight,
entity.desiredHeightResId,
- entity.title
+ entity.title,
+ mainExecutor
) }
}
- uiScope.launch { cb(bubbles) }
+ mainExecutor.execute { cb(bubbles) }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index fac3686..af421fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -79,6 +79,7 @@
import com.android.wm.shell.bubbles.animation.PhysicsAnimationLayout;
import com.android.wm.shell.bubbles.animation.StackAnimationController;
import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import java.io.FileDescriptor;
@@ -147,7 +148,7 @@
* Handler to use for all delayed animations - this way, we can easily cancel them before
* starting a new animation.
*/
- private final Handler mDelayedAnimationHandler = new Handler();
+ private final ShellExecutor mDelayedAnimationExecutor;
/**
* Interface to synchronize {@link View} state and the screen.
@@ -311,7 +312,7 @@
}
}
- private BubbleController.BubbleExpandListener mExpandListener;
+ private Bubbles.BubbleExpandListener mExpandListener;
/** Callback to run when we want to unbubble the given notification's conversation. */
private Consumer<String> mUnbubbleConversationCallback;
@@ -734,9 +735,11 @@
@SuppressLint("ClickableViewAccessibility")
public BubbleStackView(Context context, BubbleController bubbleController,
BubbleData data, @Nullable SurfaceSynchronizer synchronizer,
- FloatingContentCoordinator floatingContentCoordinator) {
+ FloatingContentCoordinator floatingContentCoordinator,
+ ShellExecutor mainExecutor) {
super(context);
+ mDelayedAnimationExecutor = mainExecutor;
mBubbleController = bubbleController;
mBubbleData = data;
@@ -1366,7 +1369,7 @@
/**
* Sets the listener to notify when the bubble stack is expanded.
*/
- public void setExpandListener(BubbleController.BubbleExpandListener listener) {
+ public void setExpandListener(Bubbles.BubbleExpandListener listener) {
mExpandListener = listener;
}
@@ -1734,7 +1737,7 @@
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
}
- mDelayedAnimationHandler.postDelayed(() -> {
+ mDelayedAnimationExecutor.executeDelayed(() -> {
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
.spring(AnimatableScaleMatrix.SCALE_X,
@@ -1791,10 +1794,12 @@
final long startDelay =
(long) (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION * 0.6f);
- mDelayedAnimationHandler.postDelayed(() -> mExpandedAnimationController.collapseBackToStack(
- mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
- /* collapseTo */,
- () -> mBubbleContainer.setActiveController(mStackAnimationController)), startDelay);
+ mDelayedAnimationExecutor.executeDelayed(() -> {
+ mExpandedAnimationController.collapseBackToStack(
+ mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
+ /* collapseTo */,
+ () -> mBubbleContainer.setActiveController(mStackAnimationController));
+ }, startDelay);
if (mTaskbarScrim.getVisibility() == VISIBLE) {
mTaskbarScrim.animate().alpha(0f).start();
@@ -1945,7 +1950,7 @@
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
- mDelayedAnimationHandler.postDelayed(() -> {
+ mDelayedAnimationExecutor.executeDelayed(() -> {
if (!mIsExpanded) {
mIsBubbleSwitchAnimating = false;
return;
@@ -1978,7 +1983,7 @@
* animating flags for those animations.
*/
private void cancelDelayedExpandCollapseSwitchAnimations() {
- mDelayedAnimationHandler.removeCallbacksAndMessages(null);
+ mDelayedAnimationExecutor.removeAllCallbacks();
mIsExpansionAnimating = false;
mIsBubbleSwitchAnimating = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index 0e7e92d..c5a712e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -46,6 +46,7 @@
import java.lang.ref.WeakReference;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* Simple task to inflate views & load necessary info to display a bubble.
@@ -71,6 +72,7 @@
private BubbleIconFactory mIconFactory;
private boolean mSkipInflation;
private Callback mCallback;
+ private Executor mMainExecutor;
/**
* Creates a task to load information for the provided {@link Bubble}. Once all info
@@ -82,7 +84,8 @@
BubbleStackView stackView,
BubbleIconFactory factory,
boolean skipInflation,
- Callback c) {
+ Callback c,
+ Executor mainExecutor) {
mBubble = b;
mContext = new WeakReference<>(context);
mController = new WeakReference<>(controller);
@@ -90,6 +93,7 @@
mIconFactory = factory;
mSkipInflation = skipInflation;
mCallback = c;
+ mMainExecutor = mainExecutor;
}
@Override
@@ -103,10 +107,12 @@
if (isCancelled() || viewInfo == null) {
return;
}
- mBubble.setViewInfo(viewInfo);
- if (mCallback != null) {
- mCallback.onBubbleViewsReady(mBubble);
- }
+ mMainExecutor.execute(() -> {
+ mBubble.setViewInfo(viewInfo);
+ if (mCallback != null) {
+ mCallback.onBubbleViewsReady(mBubble);
+ }
+ });
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index fa5ac44..6102147 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -23,6 +23,7 @@
import android.content.res.Configuration;
import android.os.Bundle;
+import android.os.Looper;
import android.service.notification.NotificationListenerService.RankingMap;
import android.util.ArraySet;
import android.view.View;
@@ -37,6 +38,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import java.util.function.IntConsumer;
/**
@@ -86,13 +90,14 @@
/** @return {@code true} if stack of bubbles is expanded or not. */
boolean isStackExpanded();
- /** @return {@code true} if the summary for the provided group key is suppressed. */
- boolean isSummarySuppressed(String groupKey);
-
/**
- * Removes a group key indicating that summary for this group should no longer be suppressed.
+ * Removes a group key indicating that the summary for this group should no longer be
+ * suppressed.
+ *
+ * @param callback If removed, this callback will be called with the summary key of the group
*/
- void removeSuppressedSummary(String groupKey);
+ void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback,
+ Executor callbackExecutor);
/** Tell the stack of bubbles to collapse. */
void collapseStack();
@@ -134,19 +139,16 @@
boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children,
IntConsumer removeCallback);
- /**
- * Retrieves the notif entry key of the summary associated with the provided group key.
- *
- * @param groupKey the group to look up
- * @return the key for the notification that is the summary of this group.
- */
- String getSummaryKey(String groupKey);
-
/** Set the proxy to commnuicate with SysUi side components. */
void setSysuiProxy(SysuiProxy proxy);
- /** Set the scrim view for bubbles. */
- void setBubbleScrim(View view);
+ /**
+ * Set the scrim view for bubbles.
+ *
+ * @param callback The callback made with the executor and the executor's looper that the view
+ * will be running on.
+ **/
+ void setBubbleScrim(View view, BiConsumer<Executor, Looper> callback);
/** Set a listener to be notified of bubble expand events. */
void setExpandListener(BubbleExpandListener listener);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
index a1b0dbe..cf0cefe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
@@ -91,7 +91,6 @@
private var touchSlop: Int = -1
private var movedEnough = false
- private val handler = Handler(Looper.myLooper()!!)
private var performedLongClick = false
@Suppress("UNCHECKED_CAST")
@@ -115,7 +114,7 @@
viewPositionOnTouchDown.set(v.translationX, v.translationY)
performedLongClick = false
- handler.postDelayed({
+ v.handler.postDelayed({
if (v.isLongClickable) {
performedLongClick = v.performLongClick()
}
@@ -125,7 +124,7 @@
MotionEvent.ACTION_MOVE -> {
if (!movedEnough && hypot(dx, dy) > touchSlop && !performedLongClick) {
movedEnough = true
- handler.removeCallbacksAndMessages(null)
+ v.handler.removeCallbacksAndMessages(null)
}
if (movedEnough) {
@@ -141,7 +140,7 @@
} else if (!performedLongClick) {
v.performClick()
} else {
- handler.removeCallbacksAndMessages(null)
+ v.handler.removeCallbacksAndMessages(null)
}
velocityTracker.clear()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
index b736fb0..6abc8f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
@@ -20,6 +20,7 @@
import android.os.SystemClock;
import android.os.Trace;
+import java.lang.reflect.Array;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -68,6 +69,26 @@
}
/**
+ * Convenience method to execute the blocking call with a default timeout and returns a value.
+ * Waits indefinitely for a typed result from a call.
+ */
+ default <T> T executeBlockingForResult(Supplier<T> runnable, Class clazz) {
+ final T[] result = (T[]) Array.newInstance(clazz, 1);
+ final CountDownLatch latch = new CountDownLatch(1);
+ execute(() -> {
+ result[0] = runnable.get();
+ latch.countDown();
+ });
+ try {
+ latch.await();
+ return result[0];
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
+
+
+ /**
* See {@link android.os.Handler#postDelayed(Runnable, long)}.
*/
void executeDelayed(Runnable runnable, long delayMillis);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index 7c9b9c3..d3a736e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -41,6 +41,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.bubbles.BubbleData.TimeSource;
+import com.android.wm.shell.common.ShellExecutor;
import com.google.common.collect.ImmutableList;
@@ -98,6 +99,8 @@
private PendingIntent mDeleteIntent;
@Mock
private BubbleLogger mBubbleLogger;
+ @Mock
+ private ShellExecutor mMainExecutor;
@Captor
private ArgumentCaptor<BubbleData.Update> mUpdateCaptor;
@@ -124,21 +127,31 @@
mock(NotificationListenerService.Ranking.class);
when(ranking.visuallyInterruptive()).thenReturn(true);
mEntryInterruptive = createBubbleEntry(1, "interruptive", "package.d", ranking);
- mBubbleInterruptive = new Bubble(mEntryInterruptive, mSuppressionListener, null);
+ mBubbleInterruptive = new Bubble(mEntryInterruptive, mSuppressionListener, null,
+ mMainExecutor);
mEntryDismissed = createBubbleEntry(1, "dismissed", "package.d", null);
- mBubbleDismissed = new Bubble(mEntryDismissed, mSuppressionListener, null);
+ mBubbleDismissed = new Bubble(mEntryDismissed, mSuppressionListener, null,
+ mMainExecutor);
- mBubbleA1 = new Bubble(mEntryA1, mSuppressionListener, mPendingIntentCanceledListener);
- mBubbleA2 = new Bubble(mEntryA2, mSuppressionListener, mPendingIntentCanceledListener);
- mBubbleA3 = new Bubble(mEntryA3, mSuppressionListener, mPendingIntentCanceledListener);
- mBubbleB1 = new Bubble(mEntryB1, mSuppressionListener, mPendingIntentCanceledListener);
- mBubbleB2 = new Bubble(mEntryB2, mSuppressionListener, mPendingIntentCanceledListener);
- mBubbleB3 = new Bubble(mEntryB3, mSuppressionListener, mPendingIntentCanceledListener);
- mBubbleC1 = new Bubble(mEntryC1, mSuppressionListener, mPendingIntentCanceledListener);
+ mBubbleA1 = new Bubble(mEntryA1, mSuppressionListener, mPendingIntentCanceledListener,
+ mMainExecutor);
+ mBubbleA2 = new Bubble(mEntryA2, mSuppressionListener, mPendingIntentCanceledListener,
+ mMainExecutor);
+ mBubbleA3 = new Bubble(mEntryA3, mSuppressionListener, mPendingIntentCanceledListener,
+ mMainExecutor);
+ mBubbleB1 = new Bubble(mEntryB1, mSuppressionListener, mPendingIntentCanceledListener,
+ mMainExecutor);
+ mBubbleB2 = new Bubble(mEntryB2, mSuppressionListener, mPendingIntentCanceledListener,
+ mMainExecutor);
+ mBubbleB3 = new Bubble(mEntryB3, mSuppressionListener, mPendingIntentCanceledListener,
+ mMainExecutor);
+ mBubbleC1 = new Bubble(mEntryC1, mSuppressionListener, mPendingIntentCanceledListener,
+ mMainExecutor);
TestableBubblePositioner positioner = new TestableBubblePositioner(mContext,
mock(WindowManager.class));
- mBubbleData = new BubbleData(getContext(), mBubbleLogger, positioner);
+ mBubbleData = new BubbleData(getContext(), mBubbleLogger, positioner,
+ mMainExecutor);
// Used by BubbleData to set lastAccessedTime
when(mTimeSource.currentTimeMillis()).thenReturn(1000L);
@@ -796,7 +809,7 @@
assertWithMessage("addedBubble").that(update.addedBubble).isEqualTo(expected);
}
- private void assertBubbleRemoved(Bubble expected, @BubbleController.DismissReason int reason) {
+ private void assertBubbleRemoved(Bubble expected, @Bubbles.DismissReason int reason) {
BubbleData.Update update = mUpdateCaptor.getValue();
assertWithMessage("removedBubbles").that(update.removedBubbles)
.isEqualTo(ImmutableList.of(Pair.create(expected, reason)));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
index bde04b6..fc828b3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
@@ -39,6 +39,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.ShellExecutor;
import org.junit.Before;
import org.junit.Test;
@@ -54,6 +55,8 @@
private Notification mNotif;
@Mock
private StatusBarNotification mSbn;
+ @Mock
+ private ShellExecutor mMainExecutor;
private BubbleEntry mBubbleEntry;
private Bundle mExtras;
@@ -78,7 +81,7 @@
when(mNotif.getBubbleMetadata()).thenReturn(metadata);
when(mSbn.getKey()).thenReturn("mock");
mBubbleEntry = new BubbleEntry(mSbn, null, true, false, false, false);
- mBubble = new Bubble(mBubbleEntry, mSuppressionListener, null);
+ mBubble = new Bubble(mBubbleEntry, mSuppressionListener, null, mMainExecutor);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
index 0d4d126..35656bd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
@@ -47,17 +47,17 @@
private PipTouchState mTouchState;
private CountDownLatch mDoubleTapCallbackTriggeredLatch;
private CountDownLatch mHoverExitCallbackTriggeredLatch;
- private TestShellExecutor mShellMainExecutor;
+ private TestShellExecutor mMainExecutor;
@Before
public void setUp() throws Exception {
- mShellMainExecutor = new TestShellExecutor();
+ mMainExecutor = new TestShellExecutor();
mDoubleTapCallbackTriggeredLatch = new CountDownLatch(1);
mHoverExitCallbackTriggeredLatch = new CountDownLatch(1);
mTouchState = new PipTouchState(ViewConfiguration.get(getContext()),
mDoubleTapCallbackTriggeredLatch::countDown,
mHoverExitCallbackTriggeredLatch::countDown,
- mShellMainExecutor);
+ mMainExecutor);
assertFalse(mTouchState.isDoubleTap());
assertFalse(mTouchState.isWaitingForDoubleTap());
}
@@ -87,7 +87,7 @@
assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == 10);
mTouchState.scheduleDoubleTapTimeoutCallback();
- mShellMainExecutor.flushAll();
+ mMainExecutor.flushAll();
assertTrue(mDoubleTapCallbackTriggeredLatch.getCount() == 0);
}
@@ -122,7 +122,7 @@
@Test
public void testHoverExitTimeout_timeoutCallbackCalled() throws Exception {
mTouchState.scheduleHoverExitTimeoutCallback();
- mShellMainExecutor.flushAll();
+ mMainExecutor.flushAll();
assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 0);
}
@@ -137,7 +137,7 @@
mTouchState.scheduleHoverExitTimeoutCallback();
mTouchState.onTouchEvent(createMotionEvent(ACTION_BUTTON_PRESS, SystemClock.uptimeMillis(),
0, 0));
- mShellMainExecutor.flushAll();
+ mMainExecutor.flushAll();
assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 1);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 4d69700..b0067cd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -29,6 +29,7 @@
import com.android.systemui.assist.AssistModule;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.controls.dagger.ControlsModule;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.dump.DumpManager;
@@ -75,6 +76,7 @@
import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
+import java.util.concurrent.Executor;
import dagger.Binds;
import dagger.BindsOptionalOf;
@@ -153,6 +155,7 @@
@Binds
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
+ // TODO: This should provided by the WM component
/** Provides Optional of BubbleManager */
@SysUISingleton
@Provides
@@ -166,11 +169,12 @@
ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager,
NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager,
NotifPipeline notifPipeline, SysUiState sysUiState, FeatureFlags featureFlags,
- DumpManager dumpManager) {
+ DumpManager dumpManager, @Main Executor sysuiMainExecutor) {
return Optional.ofNullable(BubblesManager.create(context, bubblesOptional,
notificationShadeWindowController, statusBarStateController, shadeController,
configurationController, statusBarService, notificationManager,
interruptionStateProvider, zenModeController, notifUserManager,
- groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager));
+ groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager,
+ sysuiMainExecutor));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 7f30009..6023b7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -26,25 +26,41 @@
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
import android.util.AttributeSet;
import android.view.View;
import androidx.core.graphics.ColorUtils;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.drawable.ScrimDrawable;
+import java.util.concurrent.Executor;
+
+
/**
- * A view which can draw a scrim
+ * A view which can draw a scrim. This view maybe be used in multiple windows running on different
+ * threads, but is controlled by {@link com.android.systemui.statusbar.phone.ScrimController} so we
+ * need to be careful to synchronize when necessary.
*/
public class ScrimView extends View {
+ private final Object mColorLock = new Object();
+
+ @GuardedBy("mColorLock")
private final ColorExtractor.GradientColors mColors;
+ // Used only for returning the colors
+ private final ColorExtractor.GradientColors mTmpColors = new ColorExtractor.GradientColors();
private float mViewAlpha = 1.0f;
private Drawable mDrawable;
private PorterDuffColorFilter mColorFilter;
private int mTintColor;
private Runnable mChangeRunnable;
+ private Executor mChangeRunnableExecutor;
+ private Executor mExecutor;
+ private Looper mExecutorLooper;
public ScrimView(Context context) {
this(context, null);
@@ -64,7 +80,16 @@
mDrawable = new ScrimDrawable();
mDrawable.setCallback(this);
mColors = new ColorExtractor.GradientColors();
- updateColorWithTint(false);
+ mExecutorLooper = Looper.myLooper();
+ mExecutor = Runnable::run;
+ executeOnExecutor(() -> {
+ updateColorWithTint(false);
+ });
+ }
+
+ public void setExecutor(Executor executor, Looper looper) {
+ mExecutor = executor;
+ mExecutorLooper = looper;
}
@Override
@@ -75,11 +100,13 @@
}
public void setDrawable(Drawable drawable) {
- mDrawable = drawable;
- mDrawable.setCallback(this);
- mDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom());
- mDrawable.setAlpha((int) (255 * mViewAlpha));
- invalidate();
+ executeOnExecutor(() -> {
+ mDrawable = drawable;
+ mDrawable.setCallback(this);
+ mDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom());
+ mDrawable.setAlpha((int) (255 * mViewAlpha));
+ invalidate();
+ });
}
@Override
@@ -99,6 +126,13 @@
}
}
+ @Override
+ public void setClickable(boolean clickable) {
+ executeOnExecutor(() -> {
+ super.setClickable(clickable);
+ });
+ }
+
public void setColors(@NonNull ColorExtractor.GradientColors colors) {
setColors(colors, false);
}
@@ -107,11 +141,15 @@
if (colors == null) {
throw new IllegalArgumentException("Colors cannot be null");
}
- if (mColors.equals(colors)) {
- return;
- }
- mColors.set(colors);
- updateColorWithTint(animated);
+ executeOnExecutor(() -> {
+ synchronized(mColorLock) {
+ if (mColors.equals(colors)) {
+ return;
+ }
+ mColors.set(colors);
+ }
+ updateColorWithTint(animated);
+ });
}
@VisibleForTesting
@@ -120,7 +158,10 @@
}
public ColorExtractor.GradientColors getColors() {
- return mColors;
+ synchronized(mColorLock) {
+ mTmpColors.set(mColors);
+ }
+ return mTmpColors;
}
public void setTint(int color) {
@@ -128,11 +169,13 @@
}
public void setTint(int color, boolean animated) {
- if (mTintColor == color) {
- return;
- }
- mTintColor = color;
- updateColorWithTint(animated);
+ executeOnExecutor(() -> {
+ if (mTintColor == color) {
+ return;
+ }
+ mTintColor = color;
+ updateColorWithTint(animated);
+ });
}
private void updateColorWithTint(boolean animated) {
@@ -160,7 +203,7 @@
}
if (mChangeRunnable != null) {
- mChangeRunnable.run();
+ mChangeRunnableExecutor.execute(mChangeRunnable);
}
}
@@ -184,26 +227,37 @@
if (isNaN(alpha)) {
throw new IllegalArgumentException("alpha cannot be NaN: " + alpha);
}
- if (alpha != mViewAlpha) {
- mViewAlpha = alpha;
+ executeOnExecutor(() -> {
+ if (alpha != mViewAlpha) {
+ mViewAlpha = alpha;
- mDrawable.setAlpha((int) (255 * alpha));
- if (mChangeRunnable != null) {
- mChangeRunnable.run();
+ mDrawable.setAlpha((int) (255 * alpha));
+ if (mChangeRunnable != null) {
+ mChangeRunnableExecutor.execute(mChangeRunnable);
+ }
}
- }
+ });
}
public float getViewAlpha() {
return mViewAlpha;
}
- public void setChangeRunnable(Runnable changeRunnable) {
+ public void setChangeRunnable(Runnable changeRunnable, Executor changeRunnableExecutor) {
mChangeRunnable = changeRunnable;
+ mChangeRunnableExecutor = changeRunnableExecutor;
}
@Override
protected boolean canReceivePointerEvents() {
return false;
}
+
+ private void executeOnExecutor(Runnable r) {
+ if (mExecutor == null || Looper.myLooper() == mExecutorLooper) {
+ r.run();
+ } else {
+ mExecutor.execute(r);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 19c0b6d..e39065b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -48,6 +48,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.FeatureFlags;
@@ -65,6 +66,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -150,6 +152,7 @@
private final AlarmTimeout mTimeTicker;
private final KeyguardVisibilityCallback mKeyguardVisibilityCallback;
private final Handler mHandler;
+ private final Executor mMainExecutor;
private final BlurUtils mBlurUtils;
private GradientColors mColors;
@@ -214,8 +217,7 @@
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
BlurUtils blurUtils, ConfigurationController configurationController,
- FeatureFlags featureFlags) {
-
+ FeatureFlags featureFlags, @Main Executor mainExecutor) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = featureFlags.isShadeOpaque() ? BUSY_SCRIM_ALPHA : GAR_SCRIM_ALPHA;
ScrimState.BUBBLE_EXPANDED.setBubbleAlpha(featureFlags.isShadeOpaque()
@@ -228,6 +230,7 @@
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardVisibilityCallback = new KeyguardVisibilityCallback();
mHandler = handler;
+ mMainExecutor = mainExecutor;
mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout,
"hide_aod_wallpaper", mHandler);
mWakeLock = delayedWakeLockBuilder.setHandler(mHandler).setTag("Scrims").build();
@@ -273,7 +276,7 @@
updateThemeColors();
if (mScrimBehindChangeRunnable != null) {
- mScrimBehind.setChangeRunnable(mScrimBehindChangeRunnable);
+ mScrimBehind.setChangeRunnable(mScrimBehindChangeRunnable, mMainExecutor);
mScrimBehindChangeRunnable = null;
}
@@ -1022,7 +1025,7 @@
if (mScrimBehind == null) {
mScrimBehindChangeRunnable = changeRunnable;
} else {
- mScrimBehind.setChangeRunnable(changeRunnable);
+ mScrimBehind.setChangeRunnable(changeRunnable, mMainExecutor);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index b20c457..e08224c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -841,8 +841,10 @@
mBubbleExpandListener =
(isExpanding, key) -> {
- mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
- updateScrimController();
+ mContext.getMainExecutor().execute(() -> {
+ mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
+ updateScrimController();
+ });
};
mActivityIntentHelper = new ActivityIntentHelper(mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index bf823b4..6e7aed0 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -38,6 +38,7 @@
import android.app.NotificationManager;
import android.content.Context;
import android.content.res.Configuration;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.service.notification.NotificationListenerService.RankingMap;
@@ -83,10 +84,14 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
import java.util.function.IntConsumer;
+import java.util.function.Supplier;
/**
* The SysUi side bubbles manager which communicate with other SysUi components.
@@ -106,8 +111,9 @@
private final NotificationGroupManagerLegacy mNotificationGroupManager;
private final NotificationEntryManager mNotificationEntryManager;
private final NotifPipeline mNotifPipeline;
+ private final Executor mSysuiMainExecutor;
- private final ScrimView mBubbleScrim;
+ private ScrimView mBubbleScrim;
private final Bubbles.SysuiProxy mSysuiProxy;
// TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
private final List<NotifCallback> mCallbacks = new ArrayList<>();
@@ -133,14 +139,15 @@
NotifPipeline notifPipeline,
SysUiState sysUiState,
FeatureFlags featureFlags,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ Executor sysuiMainExecutor) {
if (bubblesOptional.isPresent()) {
return new BubblesManager(context, bubblesOptional.get(),
notificationShadeWindowController, statusBarStateController, shadeController,
configurationController, statusBarService, notificationManager,
interruptionStateProvider, zenModeController, notifUserManager,
groupManager, entryManager, notifPipeline, sysUiState, featureFlags,
- dumpManager);
+ dumpManager, sysuiMainExecutor);
} else {
return null;
}
@@ -163,7 +170,8 @@
NotifPipeline notifPipeline,
SysUiState sysUiState,
FeatureFlags featureFlags,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ Executor sysuiMainExecutor) {
mContext = context;
mBubbles = bubbles;
mNotificationShadeWindowController = notificationShadeWindowController;
@@ -173,6 +181,7 @@
mNotificationGroupManager = groupManager;
mNotificationEntryManager = entryManager;
mNotifPipeline = notifPipeline;
+ mSysuiMainExecutor = sysuiMainExecutor;
mBarService = statusBarService == null
? IStatusBarService.Stub.asInterface(
@@ -181,7 +190,9 @@
mBubbleScrim = new ScrimView(mContext);
mBubbleScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
- mBubbles.setBubbleScrim(mBubbleScrim);
+ mBubbles.setBubbleScrim(mBubbleScrim, (executor, looper) -> {
+ mBubbleScrim.setExecutor(executor, looper);
+ });
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
setupNotifPipeline();
@@ -237,128 +248,177 @@
});
mSysuiProxy = new Bubbles.SysuiProxy() {
+ private <T> T executeBlockingForResult(Supplier<T> runnable, Executor executor,
+ Class clazz) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ return runnable.get();
+ }
+ final T[] result = (T[]) Array.newInstance(clazz, 1);
+ final CountDownLatch latch = new CountDownLatch(1);
+ executor.execute(() -> {
+ result[0] = runnable.get();
+ latch.countDown();
+ });
+ try {
+ latch.await();
+ return result[0];
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
+
@Override
@Nullable
public BubbleEntry getPendingOrActiveEntry(String key) {
- NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(key);
- return entry == null ? null : notifToBubbleEntry(entry);
+ return executeBlockingForResult(() -> {
+ NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ return entry == null ? null : notifToBubbleEntry(entry);
+ }, sysuiMainExecutor, BubbleEntry.class);
}
@Override
public List<BubbleEntry> getShouldRestoredEntries(ArraySet<String> savedBubbleKeys) {
- List<BubbleEntry> result = new ArrayList<>();
- List<NotificationEntry> activeEntries =
- mNotificationEntryManager.getActiveNotificationsForCurrentUser();
- for (int i = 0; i < activeEntries.size(); i++) {
- NotificationEntry entry = activeEntries.get(i);
- if (savedBubbleKeys.contains(entry.getKey())
- && mNotificationInterruptStateProvider.shouldBubbleUp(entry)
- && entry.isBubble()) {
- result.add(notifToBubbleEntry(entry));
+ return executeBlockingForResult(() -> {
+ List<BubbleEntry> result = new ArrayList<>();
+ List<NotificationEntry> activeEntries =
+ mNotificationEntryManager.getActiveNotificationsForCurrentUser();
+ for (int i = 0; i < activeEntries.size(); i++) {
+ NotificationEntry entry = activeEntries.get(i);
+ if (savedBubbleKeys.contains(entry.getKey())
+ && mNotificationInterruptStateProvider.shouldBubbleUp(entry)
+ && entry.isBubble()) {
+ result.add(notifToBubbleEntry(entry));
+ }
}
- }
- return result;
+ return result;
+ }, sysuiMainExecutor, List.class);
}
@Override
public boolean isNotificationShadeExpand() {
- return mNotificationShadeWindowController.getPanelExpanded();
+ return executeBlockingForResult(() -> {
+ return mNotificationShadeWindowController.getPanelExpanded();
+ }, sysuiMainExecutor, Boolean.class);
}
@Override
public boolean shouldBubbleUp(String key) {
- final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
- key);
- if (entry != null) {
- return mNotificationInterruptStateProvider.shouldBubbleUp(entry);
- }
- return false;
+ return executeBlockingForResult(() -> {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null) {
+ return mNotificationInterruptStateProvider.shouldBubbleUp(entry);
+ }
+ return false;
+ }, sysuiMainExecutor, Boolean.class);
}
@Override
public void setNotificationInterruption(String key) {
- final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
- key);
- if (entry != null && entry.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
- entry.setInterruption();
- }
+ sysuiMainExecutor.execute(() -> {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null
+ && entry.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
+ entry.setInterruption();
+ }
+ });
}
@Override
public void requestNotificationShadeTopUi(boolean requestTopUi, String componentTag) {
- mNotificationShadeWindowController.setRequestTopUi(requestTopUi, componentTag);
+ sysuiMainExecutor.execute(() -> {
+ mNotificationShadeWindowController.setRequestTopUi(requestTopUi, componentTag);
+ });
}
@Override
public void notifyRemoveNotification(String key, int reason) {
- final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
- key);
- if (entry != null) {
- for (NotifCallback cb : mCallbacks) {
- cb.removeNotification(entry, getDismissedByUserStats(entry, true), reason);
+ sysuiMainExecutor.execute(() -> {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null) {
+ for (NotifCallback cb : mCallbacks) {
+ cb.removeNotification(entry, getDismissedByUserStats(entry, true),
+ reason);
+ }
}
- }
+ });
}
@Override
public void notifyInvalidateNotifications(String reason) {
- for (NotifCallback cb : mCallbacks) {
- cb.invalidateNotifications(reason);
- }
+ sysuiMainExecutor.execute(() -> {
+ for (NotifCallback cb : mCallbacks) {
+ cb.invalidateNotifications(reason);
+ }
+ });
}
@Override
public void notifyMaybeCancelSummary(String key) {
- final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
- key);
- if (entry != null) {
- for (NotifCallback cb : mCallbacks) {
- cb.maybeCancelSummary(entry);
+ sysuiMainExecutor.execute(() -> {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null) {
+ for (NotifCallback cb : mCallbacks) {
+ cb.maybeCancelSummary(entry);
+ }
}
- }
+ });
}
@Override
public void removeNotificationEntry(String key) {
- final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
- key);
- if (entry != null) {
- mNotificationGroupManager.onEntryRemoved(entry);
- }
+ sysuiMainExecutor.execute(() -> {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null) {
+ mNotificationGroupManager.onEntryRemoved(entry);
+ }
+ });
}
@Override
public void updateNotificationBubbleButton(String key) {
- final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
- key);
- if (entry != null && entry.getRow() != null) {
- entry.getRow().updateBubbleButton();
- }
+ sysuiMainExecutor.execute(() -> {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null && entry.getRow() != null) {
+ entry.getRow().updateBubbleButton();
+ }
+ });
}
@Override
public void updateNotificationSuppression(String key) {
- final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
- key);
- if (entry != null) {
- mNotificationGroupManager.updateSuppression(entry);
- }
+ sysuiMainExecutor.execute(() -> {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null) {
+ mNotificationGroupManager.updateSuppression(entry);
+ }
+ });
}
@Override
public void onStackExpandChanged(boolean shouldExpand) {
- sysUiState
- .setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
- .commitUpdate(mContext.getDisplayId());
+ sysuiMainExecutor.execute(() -> {
+ sysUiState.setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
+ .commitUpdate(mContext.getDisplayId());
+ });
}
@Override
public void onUnbubbleConversation(String key) {
- final NotificationEntry entry =
- mNotificationEntryManager.getPendingOrActiveNotif(key);
- if (entry != null) {
- onUserChangedBubble(entry, false /* shouldBubble */);
- }
+ sysuiMainExecutor.execute(() -> {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null) {
+ onUserChangedBubble(entry, false /* shouldBubble */);
+ }
+ });
}
};
mBubbles.setSysuiProxy(mSysuiProxy);
@@ -424,9 +484,8 @@
final String groupKey = group.summary != null
? group.summary.getSbn().getGroupKey()
: null;
- if (!suppressed && groupKey != null
- && mBubbles.isSummarySuppressed(groupKey)) {
- mBubbles.removeSuppressedSummary(groupKey);
+ if (!suppressed && groupKey != null) {
+ mBubbles.removeSuppressedSummaryIfNecessary(groupKey, null, null);
}
}
});
@@ -449,19 +508,16 @@
// Check if removed bubble has an associated suppressed group summary that needs
// to be removed now.
final String groupKey = entry.getSbn().getGroupKey();
- if (mBubbles.isSummarySuppressed(groupKey)) {
- mBubbles.removeSuppressedSummary(groupKey);
-
+ mBubbles.removeSuppressedSummaryIfNecessary(groupKey, (summaryKey) -> {
final NotificationEntry summary =
- mNotificationEntryManager.getActiveNotificationUnfiltered(
- mBubbles.getSummaryKey(groupKey));
+ mNotificationEntryManager.getActiveNotificationUnfiltered(summaryKey);
if (summary != null) {
mNotificationEntryManager.performRemoveNotification(
summary.getSbn(),
getDismissedByUserStats(summary, false),
UNDEFINED_DISMISS_REASON);
}
- }
+ }, mSysuiMainExecutor);
// Check if we still need to remove the summary from NoManGroup because the summary
// may not be in the mBubbleData.mSuppressedGroupKeys list and removed above.
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 103e6bb..c2e4e14 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -331,6 +331,7 @@
@BindsOptionalOf
abstract AppPairs optionalAppPairs();
+ // Note: Handler needed for LauncherApps.register
@WMSingleton
@Provides
static Optional<Bubbles> provideBubbles(Context context,
@@ -341,11 +342,12 @@
LauncherApps launcherApps,
UiEventLogger uiEventLogger,
ShellTaskOrganizer organizer,
- @ShellMainThread ShellExecutor mainExecutor) {
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler mainHandler) {
return Optional.of(BubbleController.create(context, null /* synchronizer */,
floatingContentCoordinator, statusBarService, windowManager,
windowManagerShellWrapper, launcherApps, uiEventLogger, organizer,
- mainExecutor));
+ mainExecutor, mainHandler));
}
// Needs the shell main handler for ContentObserver callbacks
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 3b2e055..21368d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -54,6 +54,8 @@
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.DelayedWakeLock;
import com.android.systemui.utils.os.FakeHandler;
@@ -220,7 +222,8 @@
mScrimController = new ScrimController(mLightBarController,
mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
- mDockManager, mBlurUtils, mConfigurationController, mFeatureFlags);
+ mDockManager, mBlurUtils, mConfigurationController, mFeatureFlags,
+ new FakeExecutor(new FakeSystemClock()));
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mScrimInFront, mScrimForBubble);
mScrimController.setAnimatorListener(mAnimatorListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index ccc2eb3..76269dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -166,6 +166,7 @@
private ArgumentCaptor<NotificationRemoveInterceptor> mRemoveInterceptorCaptor;
private BubblesManager mBubblesManager;
+ // TODO(178618782): Move tests on the controller directly to the shell
private TestableBubbleController mBubbleController;
private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
private NotificationEntryListener mEntryListener;
@@ -221,6 +222,9 @@
mTestableLooper = TestableLooper.get(this);
+ // For the purposes of this test, just run everything synchronously
+ ShellExecutor syncExecutor = new SyncExecutor();
+
mContext.addMockSystemService(FaceManager.class, mFaceManager);
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
@@ -257,8 +261,9 @@
mSysUiStateBubblesExpanded =
(sysUiFlags & QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED) != 0);
+ // TODO: Fix
mPositioner = new TestableBubblePositioner(mContext, mWindowManager);
- mBubbleData = new BubbleData(mContext, mBubbleLogger, mPositioner);
+ mBubbleData = new BubbleData(mContext, mBubbleLogger, mPositioner, syncExecutor);
TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
@@ -273,7 +278,7 @@
);
when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
- when(mShellTaskOrganizer.getExecutor()).thenReturn(new FakeExecutor(new FakeSystemClock()));
+ when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
mBubbleController = new TestableBubbleController(
mContext,
mBubbleData,
@@ -286,12 +291,13 @@
mBubbleLogger,
mShellTaskOrganizer,
mPositioner,
- mock(ShellExecutor.class));
+ syncExecutor,
+ mock(Handler.class));
mBubbleController.setExpandListener(mBubbleExpandListener);
mBubblesManager = new BubblesManager(
mContext,
- mBubbleController,
+ mBubbleController.getImpl(),
mNotificationShadeWindowController,
mStatusBarStateController,
mShadeController,
@@ -306,7 +312,8 @@
mNotifPipeline,
mSysUiState,
mFeatureFlagsOldPipeline,
- mDumpManager);
+ mDumpManager,
+ syncExecutor);
// Get a reference to the BubbleController's entry listener
verify(mNotificationEntryManager, atLeastOnce())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index 00f4e3a..5340ff7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -83,8 +83,6 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.BubbleData;
@@ -203,6 +201,9 @@
mTestableLooper = TestableLooper.get(this);
+ // For the purposes of this test, just run everything synchronously
+ ShellExecutor syncExecutor = new SyncExecutor();
+
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext,
@@ -227,7 +228,7 @@
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
mPositioner = new TestableBubblePositioner(mContext, mWindowManager);
- mBubbleData = new BubbleData(mContext, mBubbleLogger, mPositioner);
+ mBubbleData = new BubbleData(mContext, mBubbleLogger, mPositioner, syncExecutor);
TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
@@ -241,7 +242,7 @@
mock(Handler.class)
);
when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
- when(mShellTaskOrganizer.getExecutor()).thenReturn(new FakeExecutor(new FakeSystemClock()));
+ when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
mBubbleController = new TestableBubbleController(
mContext,
mBubbleData,
@@ -254,12 +255,13 @@
mBubbleLogger,
mShellTaskOrganizer,
mPositioner,
- mock(ShellExecutor.class));
+ syncExecutor,
+ mock(Handler.class));
mBubbleController.setExpandListener(mBubbleExpandListener);
mBubblesManager = new BubblesManager(
mContext,
- mBubbleController,
+ mBubbleController.getImpl(),
mNotificationShadeWindowController,
mStatusBarStateController,
mShadeController,
@@ -274,7 +276,8 @@
mNotifPipeline,
mSysUiState,
mFeatureFlagsNewPipeline,
- mDumpManager);
+ mDumpManager,
+ syncExecutor);
mBubblesManager.addNotifCallback(mNotifCallback);
// Get a reference to the BubbleController's entry listener
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/SyncExecutor.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/SyncExecutor.java
new file mode 100644
index 0000000..d40eecf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/SyncExecutor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wmshell;
+
+import com.android.wm.shell.common.ShellExecutor;
+
+/**
+ * And executor that just executes everything synchronously. To be removed once we move the
+ * tests of shell behavior over to the shell.
+ */
+public class SyncExecutor implements ShellExecutor {
+ @Override
+ public void execute(Runnable runnable) {
+ runnable.run();
+ }
+
+ @Override
+ public void executeDelayed(Runnable runnable, long delayMillis) {
+ runnable.run();
+ }
+
+ @Override
+ public void removeAllCallbacks() {
+ }
+
+ @Override
+ public void removeCallbacks(Runnable runnable) {
+ }
+
+ @Override
+ public boolean hasCallback(Runnable runnable) {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index 3f918e8..cdf47b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -49,10 +49,11 @@
BubbleLogger bubbleLogger,
ShellTaskOrganizer shellTaskOrganizer,
BubblePositioner positioner,
- ShellExecutor shellMainExecutor) {
+ ShellExecutor shellMainExecutor,
+ Handler shellMainHandler) {
super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
- bubbleLogger, shellTaskOrganizer, positioner, shellMainExecutor);
+ bubbleLogger, shellTaskOrganizer, positioner, shellMainExecutor, shellMainHandler);
setInflateSynchronously(true);
}
}