Merge "8/ Updating bubbles to run on shell thread" into sc-dev
This commit is contained in:
@@ -49,6 +49,7 @@ import java.io.FileDescriptor;
|
||||
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 @@ public class Bubble implements BubbleViewProvider {
|
||||
private static final String TAG = "Bubble";
|
||||
|
||||
private final String mKey;
|
||||
private final Executor mMainExecutor;
|
||||
|
||||
private long mLastUpdated;
|
||||
private long mLastAccessed;
|
||||
@@ -156,7 +158,8 @@ public class Bubble implements BubbleViewProvider {
|
||||
* 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 @@ public class Bubble implements BubbleViewProvider {
|
||||
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 @@ public class Bubble implements BubbleViewProvider {
|
||||
stackView,
|
||||
iconFactory,
|
||||
skipInflation,
|
||||
callback);
|
||||
callback,
|
||||
mMainExecutor);
|
||||
if (mInflateSynchronously) {
|
||||
mInflationTask.onPostExecute(mInflationTask.doInBackground());
|
||||
} else {
|
||||
|
||||
@@ -28,6 +28,16 @@ import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_BOT
|
||||
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.PixelFormat;
|
||||
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.service.notification.NotificationListenerService.RankingMap;
|
||||
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.io.PrintWriter;
|
||||
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 @@ import java.util.function.IntConsumer;
|
||||
*
|
||||
* 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 class BubbleController implements Bubbles {
|
||||
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 @@ public class BubbleController implements Bubbles {
|
||||
@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 @@ public class BubbleController implements Bubbles {
|
||||
/**
|
||||
* 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 @@ public class BubbleController implements Bubbles {
|
||||
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 @@ public class BubbleController implements Bubbles {
|
||||
BubbleLogger bubbleLogger,
|
||||
ShellTaskOrganizer organizer,
|
||||
BubblePositioner positioner,
|
||||
ShellExecutor mainExecutor) {
|
||||
ShellExecutor mainExecutor,
|
||||
Handler mainHandler) {
|
||||
mContext = context;
|
||||
mFloatingContentCoordinator = floatingContentCoordinator;
|
||||
mDataRepository = dataRepository;
|
||||
@@ -299,7 +318,12 @@ public class BubbleController implements Bubbles {
|
||||
mBubbleData.removeBubblesWithInvalidShortcuts(
|
||||
packageName, validShortcuts, DISMISS_SHORTCUT_REMOVED);
|
||||
}
|
||||
});
|
||||
}, mainHandler);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Bubbles getImpl() {
|
||||
return mImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -313,8 +337,7 @@ public class BubbleController implements Bubbles {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openBubbleOverflow() {
|
||||
private void openBubbleOverflow() {
|
||||
ensureStackViewCreated();
|
||||
mBubbleData.setShowingOverflow(true);
|
||||
mBubbleData.setSelectedBubble(mBubbleData.getOverflow());
|
||||
@@ -322,8 +345,7 @@ public class BubbleController implements Bubbles {
|
||||
}
|
||||
|
||||
/** 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 @@ public class BubbleController implements Bubbles {
|
||||
* 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 @@ public class BubbleController implements Bubbles {
|
||||
}
|
||||
}
|
||||
|
||||
@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 @@ public class BubbleController implements Bubbles {
|
||||
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 @@ public class BubbleController implements Bubbles {
|
||||
return mBubblePositioner;
|
||||
}
|
||||
|
||||
SysuiProxy getSysuiProxy() {
|
||||
Bubbles.SysuiProxy getSysuiProxy() {
|
||||
return mSysuiProxy;
|
||||
}
|
||||
|
||||
@@ -453,7 +471,8 @@ public class BubbleController implements Bubbles {
|
||||
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 @@ public class BubbleController implements Bubbles {
|
||||
mSavedBubbleKeysPerUser.remove(mCurrentUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateForThemeChanges() {
|
||||
private void updateForThemeChanges() {
|
||||
if (mStackView != null) {
|
||||
mStackView.onThemeChanged();
|
||||
}
|
||||
@@ -593,8 +611,7 @@ public class BubbleController implements Bubbles {
|
||||
}
|
||||
}
|
||||
|
||||
@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 @@ public class BubbleController implements Bubbles {
|
||||
}
|
||||
}
|
||||
|
||||
@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 @@ public class BubbleController implements Bubbles {
|
||||
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 @@ public class BubbleController implements Bubbles {
|
||||
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 @@ public class BubbleController implements Bubbles {
|
||||
setIsBubble(bubble, true /* isBubble */);
|
||||
}
|
||||
|
||||
@Override
|
||||
@VisibleForTesting
|
||||
public void expandStackAndSelectBubble(BubbleEntry entry) {
|
||||
if (mIsStatusBarShade) {
|
||||
mNotifEntryToExpandOnShadeUnlock = null;
|
||||
@@ -809,15 +823,13 @@ public class BubbleController implements Bubbles {
|
||||
}
|
||||
}
|
||||
|
||||
@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 @@ public class BubbleController implements Bubbles {
|
||||
}
|
||||
}
|
||||
|
||||
@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 @@ public class BubbleController implements Bubbles {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRankingUpdated(RankingMap rankingMap) {
|
||||
private void onRankingUpdated(RankingMap rankingMap) {
|
||||
if (mTmpRanking == null) {
|
||||
mTmpRanking = new NotificationListenerService.Ranking();
|
||||
}
|
||||
@@ -882,6 +892,8 @@ public class BubbleController implements Bubbles {
|
||||
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 @@ public class BubbleController implements Bubbles {
|
||||
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 @@ public class BubbleController implements Bubbles {
|
||||
}
|
||||
};
|
||||
|
||||
@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 @@ public class BubbleController implements Bubbles {
|
||||
/**
|
||||
* 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 @@ public class BubbleController implements Bubbles {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import java.util.HashSet;
|
||||
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 @@ public class BubbleData {
|
||||
|
||||
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 @@ public class BubbleData {
|
||||
*/
|
||||
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 @@ public class BubbleData {
|
||||
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;
|
||||
|
||||
@@ -27,6 +27,8 @@ import android.util.Log
|
||||
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.cancelAndJoin
|
||||
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 @@ internal class BubbleDataRepository(context: Context, private val launcherApps:
|
||||
|
||||
/**
|
||||
* 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 @@ internal class BubbleDataRepository(context: Context, private val launcherApps:
|
||||
shortcutInfo,
|
||||
entity.desiredHeight,
|
||||
entity.desiredHeightResId,
|
||||
entity.title
|
||||
entity.title,
|
||||
mainExecutor
|
||||
) }
|
||||
}
|
||||
uiScope.launch { cb(bubbles) }
|
||||
mainExecutor.execute { cb(bubbles) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ import com.android.wm.shell.bubbles.animation.ExpandedAnimationController;
|
||||
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 @@ public class BubbleStackView extends FrameLayout
|
||||
* 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 @@ public class BubbleStackView extends FrameLayout
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class BubbleStackView extends FrameLayout
|
||||
@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 @@ public class BubbleStackView extends FrameLayout
|
||||
/**
|
||||
* 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 @@ public class BubbleStackView extends FrameLayout
|
||||
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
|
||||
}
|
||||
|
||||
mDelayedAnimationHandler.postDelayed(() -> {
|
||||
mDelayedAnimationExecutor.executeDelayed(() -> {
|
||||
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
|
||||
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
|
||||
.spring(AnimatableScaleMatrix.SCALE_X,
|
||||
@@ -1791,10 +1794,12 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
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 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
|
||||
|
||||
mDelayedAnimationHandler.postDelayed(() -> {
|
||||
mDelayedAnimationExecutor.executeDelayed(() -> {
|
||||
if (!mIsExpanded) {
|
||||
mIsBubbleSwitchAnimating = false;
|
||||
return;
|
||||
@@ -1978,7 +1983,7 @@ public class BubbleStackView extends FrameLayout
|
||||
* animating flags for those animations.
|
||||
*/
|
||||
private void cancelDelayedExpandCollapseSwitchAnimations() {
|
||||
mDelayedAnimationHandler.removeCallbacksAndMessages(null);
|
||||
mDelayedAnimationExecutor.removeAllCallbacks();
|
||||
|
||||
mIsExpansionAnimating = false;
|
||||
mIsBubbleSwitchAnimating = false;
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.android.wm.shell.R;
|
||||
|
||||
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 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
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 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
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 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
mIconFactory = factory;
|
||||
mSkipInflation = skipInflation;
|
||||
mCallback = c;
|
||||
mMainExecutor = mainExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,10 +107,12 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,6 +23,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
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.io.PrintWriter;
|
||||
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 @@ public interface Bubbles {
|
||||
/** @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 @@ public interface Bubbles {
|
||||
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);
|
||||
|
||||
@@ -91,7 +91,6 @@ abstract class RelativeTouchListener : View.OnTouchListener {
|
||||
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 @@ abstract class RelativeTouchListener : View.OnTouchListener {
|
||||
viewPositionOnTouchDown.set(v.translationX, v.translationY)
|
||||
|
||||
performedLongClick = false
|
||||
handler.postDelayed({
|
||||
v.handler.postDelayed({
|
||||
if (v.isLongClickable) {
|
||||
performedLongClick = v.performLongClick()
|
||||
}
|
||||
@@ -125,7 +124,7 @@ abstract class RelativeTouchListener : View.OnTouchListener {
|
||||
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 @@ abstract class RelativeTouchListener : View.OnTouchListener {
|
||||
} else if (!performedLongClick) {
|
||||
v.performClick()
|
||||
} else {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
v.handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
velocityTracker.clear()
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.os.Looper;
|
||||
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;
|
||||
@@ -67,6 +68,26 @@ public interface ShellExecutor extends Executor {
|
||||
executeBlocking(runnable, 2, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)}.
|
||||
*/
|
||||
|
||||
@@ -41,6 +41,7 @@ import androidx.test.filters.SmallTest;
|
||||
|
||||
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 @@ public class BubbleDataTest extends ShellTestCase {
|
||||
private PendingIntent mDeleteIntent;
|
||||
@Mock
|
||||
private BubbleLogger mBubbleLogger;
|
||||
@Mock
|
||||
private ShellExecutor mMainExecutor;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<BubbleData.Update> mUpdateCaptor;
|
||||
@@ -124,21 +127,31 @@ public class BubbleDataTest extends ShellTestCase {
|
||||
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 @@ public class BubbleDataTest extends ShellTestCase {
|
||||
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)));
|
||||
|
||||
@@ -39,6 +39,7 @@ import androidx.test.filters.SmallTest;
|
||||
|
||||
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 @@ public class BubbleTest extends ShellTestCase {
|
||||
private Notification mNotif;
|
||||
@Mock
|
||||
private StatusBarNotification mSbn;
|
||||
@Mock
|
||||
private ShellExecutor mMainExecutor;
|
||||
|
||||
private BubbleEntry mBubbleEntry;
|
||||
private Bundle mExtras;
|
||||
@@ -78,7 +81,7 @@ public class BubbleTest extends ShellTestCase {
|
||||
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
|
||||
|
||||
@@ -47,17 +47,17 @@ public class PipTouchStateTest extends ShellTestCase {
|
||||
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 @@ public class PipTouchStateTest extends ShellTestCase {
|
||||
assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == 10);
|
||||
mTouchState.scheduleDoubleTapTimeoutCallback();
|
||||
|
||||
mShellMainExecutor.flushAll();
|
||||
mMainExecutor.flushAll();
|
||||
assertTrue(mDoubleTapCallbackTriggeredLatch.getCount() == 0);
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ public class PipTouchStateTest extends ShellTestCase {
|
||||
@Test
|
||||
public void testHoverExitTimeout_timeoutCallbackCalled() throws Exception {
|
||||
mTouchState.scheduleHoverExitTimeoutCallback();
|
||||
mShellMainExecutor.flushAll();
|
||||
mMainExecutor.flushAll();
|
||||
assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 0);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ public class PipTouchStateTest extends ShellTestCase {
|
||||
mTouchState.scheduleHoverExitTimeoutCallback();
|
||||
mTouchState.onTouchEvent(createMotionEvent(ACTION_BUTTON_PRESS, SystemClock.uptimeMillis(),
|
||||
0, 0));
|
||||
mShellMainExecutor.flushAll();
|
||||
mMainExecutor.flushAll();
|
||||
assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.android.systemui.appops.dagger.AppOpsModule;
|
||||
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.systemui.wmshell.BubblesManager;
|
||||
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 @@ public abstract class SystemUIModule {
|
||||
@Binds
|
||||
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
|
||||
|
||||
// TODO: This should provided by the WM component
|
||||
/** Provides Optional of BubbleManager */
|
||||
@SysUISingleton
|
||||
@Provides
|
||||
@@ -166,11 +169,12 @@ public abstract class SystemUIModule {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,25 +26,41 @@ import android.graphics.PorterDuff;
|
||||
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 @@ public class ScrimView extends View {
|
||||
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 class ScrimView extends View {
|
||||
}
|
||||
|
||||
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 @@ public class ScrimView extends View {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClickable(boolean clickable) {
|
||||
executeOnExecutor(() -> {
|
||||
super.setClickable(clickable);
|
||||
});
|
||||
}
|
||||
|
||||
public void setColors(@NonNull ColorExtractor.GradientColors colors) {
|
||||
setColors(colors, false);
|
||||
}
|
||||
@@ -107,11 +141,15 @@ public class ScrimView extends View {
|
||||
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 class ScrimView extends View {
|
||||
}
|
||||
|
||||
public ColorExtractor.GradientColors getColors() {
|
||||
return mColors;
|
||||
synchronized(mColorLock) {
|
||||
mTmpColors.set(mColors);
|
||||
}
|
||||
return mTmpColors;
|
||||
}
|
||||
|
||||
public void setTint(int color) {
|
||||
@@ -128,11 +169,13 @@ public class ScrimView extends View {
|
||||
}
|
||||
|
||||
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 @@ public class ScrimView extends View {
|
||||
}
|
||||
|
||||
if (mChangeRunnable != null) {
|
||||
mChangeRunnable.run();
|
||||
mChangeRunnableExecutor.execute(mChangeRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,26 +227,37 @@ public class ScrimView extends View {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ import com.android.systemui.DejankUtils;
|
||||
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.Retention;
|
||||
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 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
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 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
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 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
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 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
updateThemeColors();
|
||||
|
||||
if (mScrimBehindChangeRunnable != null) {
|
||||
mScrimBehind.setChangeRunnable(mScrimBehindChangeRunnable);
|
||||
mScrimBehind.setChangeRunnable(mScrimBehindChangeRunnable, mMainExecutor);
|
||||
mScrimBehindChangeRunnable = null;
|
||||
}
|
||||
|
||||
@@ -1022,7 +1025,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
if (mScrimBehind == null) {
|
||||
mScrimBehindChangeRunnable = changeRunnable;
|
||||
} else {
|
||||
mScrimBehind.setChangeRunnable(changeRunnable);
|
||||
mScrimBehind.setChangeRunnable(changeRunnable, mMainExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -841,8 +841,10 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
|
||||
mBubbleExpandListener =
|
||||
(isExpanding, key) -> {
|
||||
mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
|
||||
updateScrimController();
|
||||
mContext.getMainExecutor().execute(() -> {
|
||||
mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
|
||||
updateScrimController();
|
||||
});
|
||||
};
|
||||
|
||||
mActivityIntentHelper = new ActivityIntentHelper(mContext);
|
||||
|
||||
@@ -38,6 +38,7 @@ import android.app.NotificationChannel;
|
||||
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 com.android.wm.shell.bubbles.Bubbles;
|
||||
|
||||
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 @@ public class BubblesManager implements Dumpable {
|
||||
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 @@ public class BubblesManager implements Dumpable {
|
||||
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 @@ public class BubblesManager implements Dumpable {
|
||||
NotifPipeline notifPipeline,
|
||||
SysUiState sysUiState,
|
||||
FeatureFlags featureFlags,
|
||||
DumpManager dumpManager) {
|
||||
DumpManager dumpManager,
|
||||
Executor sysuiMainExecutor) {
|
||||
mContext = context;
|
||||
mBubbles = bubbles;
|
||||
mNotificationShadeWindowController = notificationShadeWindowController;
|
||||
@@ -173,6 +181,7 @@ public class BubblesManager implements Dumpable {
|
||||
mNotificationGroupManager = groupManager;
|
||||
mNotificationEntryManager = entryManager;
|
||||
mNotifPipeline = notifPipeline;
|
||||
mSysuiMainExecutor = sysuiMainExecutor;
|
||||
|
||||
mBarService = statusBarService == null
|
||||
? IStatusBarService.Stub.asInterface(
|
||||
@@ -181,7 +190,9 @@ public class BubblesManager implements Dumpable {
|
||||
|
||||
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 @@ public class BubblesManager implements Dumpable {
|
||||
});
|
||||
|
||||
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 @@ public class BubblesManager implements Dumpable {
|
||||
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 @@ public class BubblesManager implements Dumpable {
|
||||
// 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.
|
||||
|
||||
@@ -331,6 +331,7 @@ public abstract class WMShellBaseModule {
|
||||
@BindsOptionalOf
|
||||
abstract AppPairs optionalAppPairs();
|
||||
|
||||
// Note: Handler needed for LauncherApps.register
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Optional<Bubbles> provideBubbles(Context context,
|
||||
@@ -341,11 +342,12 @@ public abstract class WMShellBaseModule {
|
||||
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
|
||||
|
||||
@@ -54,6 +54,8 @@ import com.android.systemui.statusbar.FeatureFlags;
|
||||
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 @@ public class ScrimControllerTest extends SysuiTestCase {
|
||||
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);
|
||||
|
||||
@@ -166,6 +166,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
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 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
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 @@ public class BubblesTest extends SysuiTestCase {
|
||||
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 @@ public class BubblesTest extends SysuiTestCase {
|
||||
);
|
||||
|
||||
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 @@ public class BubblesTest extends SysuiTestCase {
|
||||
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 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mNotifPipeline,
|
||||
mSysUiState,
|
||||
mFeatureFlagsOldPipeline,
|
||||
mDumpManager);
|
||||
mDumpManager,
|
||||
syncExecutor);
|
||||
|
||||
// Get a reference to the BubbleController's entry listener
|
||||
verify(mNotificationEntryManager, atLeastOnce())
|
||||
|
||||
@@ -83,8 +83,6 @@ import com.android.systemui.statusbar.policy.BatteryController;
|
||||
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 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
|
||||
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 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
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 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
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 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
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 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mNotifPipeline,
|
||||
mSysUiState,
|
||||
mFeatureFlagsNewPipeline,
|
||||
mDumpManager);
|
||||
mDumpManager,
|
||||
syncExecutor);
|
||||
mBubblesManager.addNotifCallback(mNotifCallback);
|
||||
|
||||
// Get a reference to the BubbleController's entry listener
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -49,10 +49,11 @@ public class TestableBubbleController extends BubbleController {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user