Migrate Bubbles to wm-shell (4/n)
Move BubbleController sysui dependent code to new class
BubblesManager and remove using of Dependency of Bubbles.
TODO: Tests still need to be remain on sysui, find suitable
method to test both classes independently.
Bug: 161980186
Test: atest SystemUITests
Change-Id: I7be1dfb81f7ddfb5fc20b180fc5affb7a1d8e93c
This commit is contained in:
@@ -37,7 +37,6 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.systemui.appops.AppOpsController;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Background;
|
||||
@@ -308,7 +307,6 @@ public class Dependency {
|
||||
@Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
|
||||
@Inject Lazy<SmartReplyController> mSmartReplyController;
|
||||
@Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
|
||||
@Inject Lazy<Bubbles> mBubbles;
|
||||
@Inject Lazy<NotificationEntryManager> mNotificationEntryManager;
|
||||
@Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
|
||||
@Inject Lazy<AutoHideController> mAutoHideController;
|
||||
@@ -506,7 +504,6 @@ public class Dependency {
|
||||
mProviders.put(SmartReplyController.class, mSmartReplyController::get);
|
||||
mProviders.put(RemoteInputQuickSettingsDisabler.class,
|
||||
mRemoteInputQuickSettingsDisabler::get);
|
||||
mProviders.put(Bubbles.class, mBubbles::get);
|
||||
mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get);
|
||||
mProviders.put(ForegroundServiceNotificationListener.class,
|
||||
mForegroundServiceNotificationListener::get);
|
||||
|
||||
@@ -53,7 +53,8 @@ import java.util.Objects;
|
||||
/**
|
||||
* Encapsulates the data and UI elements of a bubble.
|
||||
*/
|
||||
class Bubble implements BubbleViewProvider {
|
||||
@VisibleForTesting
|
||||
public class Bubble implements BubbleViewProvider {
|
||||
private static final String TAG = "Bubble";
|
||||
|
||||
private final String mKey;
|
||||
@@ -62,7 +63,7 @@ class Bubble implements BubbleViewProvider {
|
||||
private long mLastAccessed;
|
||||
|
||||
@Nullable
|
||||
private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
|
||||
private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
|
||||
|
||||
/** Whether the bubble should show a dot for the notification indicating updated content. */
|
||||
private boolean mShowBubbleUpdateDot = true;
|
||||
@@ -173,8 +174,8 @@ class Bubble implements BubbleViewProvider {
|
||||
|
||||
@VisibleForTesting(visibility = PRIVATE)
|
||||
Bubble(@NonNull final BubbleEntry entry,
|
||||
@Nullable final BubbleController.NotificationSuppressionChangedListener listener,
|
||||
final BubbleController.PendingIntentCanceledListener intentCancelListener) {
|
||||
@Nullable final Bubbles.NotificationSuppressionChangedListener listener,
|
||||
final Bubbles.PendingIntentCanceledListener intentCancelListener) {
|
||||
mKey = entry.getKey();
|
||||
mSuppressionListener = listener;
|
||||
mIntentCancelListener = intent -> {
|
||||
@@ -309,11 +310,13 @@ class Bubble implements BubbleViewProvider {
|
||||
*
|
||||
* @param callback the callback to notify one the bubble is ready to be displayed.
|
||||
* @param context the context for the bubble.
|
||||
* @param controller
|
||||
* @param stackView the stackView the bubble is eventually added to.
|
||||
* @param iconFactory the iconfactory use to create badged images for the bubble.
|
||||
*/
|
||||
void inflate(BubbleViewInfoTask.Callback callback,
|
||||
Context context,
|
||||
BubbleController controller,
|
||||
BubbleStackView stackView,
|
||||
BubbleIconFactory iconFactory,
|
||||
boolean skipInflation) {
|
||||
@@ -322,6 +325,7 @@ class Bubble implements BubbleViewProvider {
|
||||
}
|
||||
mInflationTask = new BubbleViewInfoTask(this,
|
||||
context,
|
||||
controller,
|
||||
stackView,
|
||||
iconFactory,
|
||||
skipInflation,
|
||||
@@ -522,7 +526,8 @@ class Bubble implements BubbleViewProvider {
|
||||
/**
|
||||
* Sets whether this notification should be suppressed in the shade.
|
||||
*/
|
||||
void setSuppressNotification(boolean suppressNotification) {
|
||||
@VisibleForTesting
|
||||
public void setSuppressNotification(boolean suppressNotification) {
|
||||
boolean prevShowInShade = showInShade();
|
||||
if (suppressNotification) {
|
||||
mFlags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
|
||||
@@ -559,7 +564,8 @@ class Bubble implements BubbleViewProvider {
|
||||
/**
|
||||
* Whether the flyout for the bubble should be shown.
|
||||
*/
|
||||
boolean showFlyout() {
|
||||
@VisibleForTesting
|
||||
public boolean showFlyout() {
|
||||
return !mSuppressFlyout && !mShouldSuppressPeek
|
||||
&& !shouldSuppressNotification()
|
||||
&& !mShouldSuppressNotificationList;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,7 @@ import androidx.annotation.Nullable;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.bubbles.BubbleController.DismissReason;
|
||||
import com.android.systemui.bubbles.Bubbles.DismissReason;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -137,8 +137,8 @@ public class BubbleData {
|
||||
private Listener mListener;
|
||||
|
||||
@Nullable
|
||||
private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
|
||||
private BubbleController.PendingIntentCanceledListener mCancelledListener;
|
||||
private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
|
||||
private Bubbles.PendingIntentCanceledListener mCancelledListener;
|
||||
|
||||
/**
|
||||
* We track groups with summaries that aren't visibly displayed but still kept around because
|
||||
@@ -165,12 +165,12 @@ public class BubbleData {
|
||||
}
|
||||
|
||||
public void setSuppressionChangedListener(
|
||||
BubbleController.NotificationSuppressionChangedListener listener) {
|
||||
Bubbles.NotificationSuppressionChangedListener listener) {
|
||||
mSuppressionListener = listener;
|
||||
}
|
||||
|
||||
public void setPendingIntentCancelledListener(
|
||||
BubbleController.PendingIntentCanceledListener listener) {
|
||||
Bubbles.PendingIntentCanceledListener listener) {
|
||||
mCancelledListener = listener;
|
||||
}
|
||||
|
||||
@@ -344,7 +344,8 @@ public class BubbleData {
|
||||
/**
|
||||
* Whether the summary for the provided group key is suppressed.
|
||||
*/
|
||||
boolean isSummarySuppressed(String groupKey) {
|
||||
@VisibleForTesting
|
||||
public boolean isSummarySuppressed(String groupKey) {
|
||||
return mSuppressedGroupKeys.containsKey(groupKey);
|
||||
}
|
||||
|
||||
@@ -415,7 +416,7 @@ public class BubbleData {
|
||||
// skip the selected bubble
|
||||
.filter((b) -> !b.equals(mSelectedBubble))
|
||||
.findFirst()
|
||||
.ifPresent((b) -> doRemove(b.getKey(), BubbleController.DISMISS_AGED));
|
||||
.ifPresent((b) -> doRemove(b.getKey(), Bubbles.DISMISS_AGED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,12 +460,12 @@ public class BubbleData {
|
||||
int indexToRemove = indexForKey(key);
|
||||
if (indexToRemove == -1) {
|
||||
if (hasOverflowBubbleWithKey(key)
|
||||
&& (reason == BubbleController.DISMISS_NOTIF_CANCEL
|
||||
|| reason == BubbleController.DISMISS_GROUP_CANCELLED
|
||||
|| reason == BubbleController.DISMISS_NO_LONGER_BUBBLE
|
||||
|| reason == BubbleController.DISMISS_BLOCKED
|
||||
|| reason == BubbleController.DISMISS_SHORTCUT_REMOVED
|
||||
|| reason == BubbleController.DISMISS_PACKAGE_REMOVED)) {
|
||||
&& (reason == Bubbles.DISMISS_NOTIF_CANCEL
|
||||
|| reason == Bubbles.DISMISS_GROUP_CANCELLED
|
||||
|| reason == Bubbles.DISMISS_NO_LONGER_BUBBLE
|
||||
|| reason == Bubbles.DISMISS_BLOCKED
|
||||
|| reason == Bubbles.DISMISS_SHORTCUT_REMOVED
|
||||
|| reason == Bubbles.DISMISS_PACKAGE_REMOVED)) {
|
||||
|
||||
Bubble b = getOverflowBubbleWithKey(key);
|
||||
if (DEBUG_BUBBLE_DATA) {
|
||||
@@ -512,8 +513,8 @@ public class BubbleData {
|
||||
|
||||
void overflowBubble(@DismissReason int reason, Bubble bubble) {
|
||||
if (bubble.getPendingIntentCanceled()
|
||||
|| !(reason == BubbleController.DISMISS_AGED
|
||||
|| reason == BubbleController.DISMISS_USER_GESTURE)) {
|
||||
|| !(reason == Bubbles.DISMISS_AGED
|
||||
|| reason == Bubbles.DISMISS_USER_GESTURE)) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG_BUBBLE_DATA) {
|
||||
@@ -529,7 +530,7 @@ public class BubbleData {
|
||||
if (DEBUG_BUBBLE_DATA) {
|
||||
Log.d(TAG, "Overflow full. Remove: " + oldest);
|
||||
}
|
||||
mStateChange.bubbleRemoved(oldest, BubbleController.DISMISS_OVERFLOW_MAX_REACHED);
|
||||
mStateChange.bubbleRemoved(oldest, Bubbles.DISMISS_OVERFLOW_MAX_REACHED);
|
||||
mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_MAX_REACHED);
|
||||
mOverflowBubbles.remove(oldest);
|
||||
mStateChange.removedOverflowBubble = oldest;
|
||||
@@ -694,7 +695,7 @@ public class BubbleData {
|
||||
}
|
||||
|
||||
private void maybeSendDeleteIntent(@DismissReason int reason, @NonNull final Bubble bubble) {
|
||||
if (reason != BubbleController.DISMISS_USER_GESTURE) return;
|
||||
if (reason != Bubbles.DISMISS_USER_GESTURE) return;
|
||||
PendingIntent deleteIntent = bubble.getDeleteIntent();
|
||||
if (deleteIntent == null) return;
|
||||
try {
|
||||
@@ -726,7 +727,7 @@ public class BubbleData {
|
||||
* The set of bubbles in overflow.
|
||||
*/
|
||||
@VisibleForTesting(visibility = PRIVATE)
|
||||
List<Bubble> getOverflowBubbles() {
|
||||
public List<Bubble> getOverflowBubbles() {
|
||||
return Collections.unmodifiableList(mOverflowBubbles);
|
||||
}
|
||||
|
||||
@@ -742,7 +743,7 @@ public class BubbleData {
|
||||
|
||||
@VisibleForTesting(visibility = PRIVATE)
|
||||
@Nullable
|
||||
Bubble getBubbleInStackWithKey(String key) {
|
||||
public Bubble getBubbleInStackWithKey(String key) {
|
||||
for (int i = 0; i < mBubbles.size(); i++) {
|
||||
Bubble bubble = mBubbles.get(i);
|
||||
if (bubble.getKey().equals(key)) {
|
||||
@@ -764,7 +765,7 @@ public class BubbleData {
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = PRIVATE)
|
||||
Bubble getOverflowBubbleWithKey(String key) {
|
||||
public Bubble getOverflowBubbleWithKey(String key) {
|
||||
for (int i = 0; i < mOverflowBubbles.size(); i++) {
|
||||
Bubble bubble = mOverflowBubbles.get(i);
|
||||
if (bubble.getKey().equals(key)) {
|
||||
@@ -788,7 +789,7 @@ public class BubbleData {
|
||||
* This method should only be used in tests, not in production.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void setMaxOverflowBubbles(int maxOverflowBubbles) {
|
||||
public void setMaxOverflowBubbles(int maxOverflowBubbles) {
|
||||
mMaxOverflowBubbles = maxOverflowBubbles;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,10 +33,10 @@ public class BubbleDebugConfig {
|
||||
// to figure-out the origin of a log message while debugging the Bubbles a little painful. By
|
||||
// setting this constant to true, log messages from the Bubbles package will be tagged with
|
||||
// their class names instead fot the generic tag.
|
||||
static final boolean TAG_WITH_CLASS_NAME = false;
|
||||
public static final boolean TAG_WITH_CLASS_NAME = false;
|
||||
|
||||
// Default log tag for the Bubbles package.
|
||||
static final String TAG_BUBBLES = "Bubbles";
|
||||
public static final String TAG_BUBBLES = "Bubbles";
|
||||
|
||||
static final boolean DEBUG_BUBBLE_CONTROLLER = false;
|
||||
static final boolean DEBUG_BUBBLE_DATA = false;
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.systemui.bubbles;
|
||||
|
||||
import static android.app.Notification.FLAG_BUBBLE;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.Notification.BubbleMetadata;
|
||||
import android.app.NotificationManager.Policy;
|
||||
import android.service.notification.NotificationListenerService.Ranking;
|
||||
@@ -67,12 +70,45 @@ public class BubbleEntry {
|
||||
return mSbn.getKey();
|
||||
}
|
||||
|
||||
/** @return the group key in the {@link StatusBarNotification}. */
|
||||
public String getGroupKey() {
|
||||
return mSbn.getGroupKey();
|
||||
}
|
||||
|
||||
/** @return the {@link BubbleMetadata} in the {@link StatusBarNotification}. */
|
||||
@Nullable
|
||||
public BubbleMetadata getBubbleMetadata() {
|
||||
return getStatusBarNotification().getNotification().getBubbleMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the {@link Notification#FLAG_BUBBLE} flag on this notification to indicate
|
||||
* whether it is a bubble or not. If this entry is set to not bubble, or does not have
|
||||
* the required info to bubble, the flag cannot be set to true.
|
||||
*
|
||||
* @param shouldBubble whether this notification should be flagged as a bubble.
|
||||
* @return true if the value changed.
|
||||
*/
|
||||
public boolean setFlagBubble(boolean shouldBubble) {
|
||||
boolean wasBubble = isBubble();
|
||||
if (!shouldBubble) {
|
||||
mSbn.getNotification().flags &= ~FLAG_BUBBLE;
|
||||
} else if (getBubbleMetadata() != null && canBubble()) {
|
||||
// wants to be bubble & can bubble, set flag
|
||||
mSbn.getNotification().flags |= FLAG_BUBBLE;
|
||||
}
|
||||
return wasBubble != isBubble();
|
||||
}
|
||||
|
||||
public boolean isBubble() {
|
||||
return (mSbn.getNotification().flags & FLAG_BUBBLE) != 0;
|
||||
}
|
||||
|
||||
/** @see Ranking#canBubble() */
|
||||
public boolean canBubble() {
|
||||
return mRanking.canBubble();
|
||||
}
|
||||
|
||||
/** @return true if this notification is clearable. */
|
||||
public boolean isClearable() {
|
||||
return mIsClearable;
|
||||
|
||||
@@ -54,7 +54,6 @@ import android.widget.LinearLayout;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.policy.ScreenDecorationsUtils;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.TriangleShape;
|
||||
import com.android.systemui.statusbar.AlphaOptimizedButton;
|
||||
@@ -99,7 +98,7 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
// TODO(b/170891664): Don't use a flag, set the BubbleOverflow object instead
|
||||
private boolean mIsOverflow;
|
||||
|
||||
private Bubbles mBubbles = Dependency.get(Bubbles.class);
|
||||
private BubbleController mController;
|
||||
private BubbleStackView mStackView;
|
||||
private BubblePositioner mPositioner;
|
||||
|
||||
@@ -156,8 +155,7 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
// the bubble again so we'll just remove it.
|
||||
Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
|
||||
+ ", " + e.getMessage() + "; removing bubble");
|
||||
mBubbles.removeBubble(getBubbleKey(),
|
||||
BubbleController.DISMISS_INVALID_INTENT);
|
||||
mController.removeBubble(getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT);
|
||||
}
|
||||
});
|
||||
mInitialized = true;
|
||||
@@ -195,15 +193,15 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
}
|
||||
if (mBubble != null) {
|
||||
// Must post because this is called from a binder thread.
|
||||
post(() -> mBubbles.removeBubble(mBubble.getKey(),
|
||||
BubbleController.DISMISS_TASK_FINISHED));
|
||||
post(() -> mController.removeBubble(
|
||||
mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressedOnTaskRoot(int taskId) {
|
||||
if (mTaskId == taskId && mStackView.isExpanded()) {
|
||||
mBubbles.collapseStack();
|
||||
mController.collapseStack();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -250,9 +248,6 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
R.dimen.bubble_manage_button_height);
|
||||
mSettingsIcon = findViewById(R.id.settings_button);
|
||||
|
||||
mPositioner = mBubbles.getPositioner();
|
||||
|
||||
mTaskView = new TaskView(mContext, mBubbles.getTaskOrganizer());
|
||||
// Set ActivityView's alpha value as zero, since there is no view content to be shown.
|
||||
setContentVisibility(false);
|
||||
|
||||
@@ -263,7 +258,6 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
}
|
||||
});
|
||||
mExpandedViewContainer.setClipToOutline(true);
|
||||
mExpandedViewContainer.addView(mTaskView);
|
||||
mExpandedViewContainer.setLayoutParams(
|
||||
new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||
addView(mExpandedViewContainer);
|
||||
@@ -274,9 +268,7 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
// ==> expanded view
|
||||
// ==> activity view
|
||||
// ==> manage button
|
||||
bringChildToFront(mTaskView);
|
||||
bringChildToFront(mSettingsIcon);
|
||||
mTaskView.setListener(mTaskViewListener);
|
||||
|
||||
applyThemeAttrs();
|
||||
|
||||
@@ -314,6 +306,20 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
super.onAttachedToWindow();
|
||||
mTaskView.setExecutor(new HandlerExecutor(getHandler()));
|
||||
}
|
||||
/**
|
||||
* Initialize {@link BubbleController} and {@link BubbleStackView} here, this method must need
|
||||
* to be called after view inflate.
|
||||
*/
|
||||
void initialize(BubbleController controller, BubbleStackView stackView) {
|
||||
mController = controller;
|
||||
mStackView = stackView;
|
||||
|
||||
mTaskView = new TaskView(mContext, mController.getTaskOrganizer());
|
||||
mExpandedViewContainer.addView(mTaskView);
|
||||
bringChildToFront(mTaskView);
|
||||
mTaskView.setListener(mTaskViewListener);
|
||||
mPositioner = mController.getPositioner();
|
||||
}
|
||||
|
||||
void updateDimensions() {
|
||||
Resources res = getResources();
|
||||
@@ -464,16 +470,12 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
return mTaskId;
|
||||
}
|
||||
|
||||
void setStackView(BubbleStackView stackView) {
|
||||
mStackView = stackView;
|
||||
}
|
||||
|
||||
public void setOverflow(boolean overflow) {
|
||||
mIsOverflow = overflow;
|
||||
|
||||
Intent target = new Intent(mContext, BubbleOverflowActivity.class);
|
||||
Bundle extras = new Bundle();
|
||||
extras.putBinder(EXTRA_BUBBLE_CONTROLLER, ObjectWrapper.wrap(mBubbles));
|
||||
extras.putBinder(EXTRA_BUBBLE_CONTROLLER, ObjectWrapper.wrap(mController));
|
||||
target.putExtras(extras);
|
||||
mPendingIntent = PendingIntent.getActivity(mContext, 0 /* requestCode */,
|
||||
target, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
@@ -91,14 +91,14 @@ public class BubbleLogger {
|
||||
* @param b Bubble removed from overflow
|
||||
* @param r Reason that bubble was removed
|
||||
*/
|
||||
public void logOverflowRemove(Bubble b, @BubbleController.DismissReason int r) {
|
||||
if (r == BubbleController.DISMISS_NOTIF_CANCEL) {
|
||||
public void logOverflowRemove(Bubble b, @Bubbles.DismissReason int r) {
|
||||
if (r == Bubbles.DISMISS_NOTIF_CANCEL) {
|
||||
log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_CANCEL);
|
||||
} else if (r == BubbleController.DISMISS_GROUP_CANCELLED) {
|
||||
} else if (r == Bubbles.DISMISS_GROUP_CANCELLED) {
|
||||
log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_GROUP_CANCEL);
|
||||
} else if (r == BubbleController.DISMISS_NO_LONGER_BUBBLE) {
|
||||
} else if (r == Bubbles.DISMISS_NO_LONGER_BUBBLE) {
|
||||
log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_NO_LONGER_BUBBLE);
|
||||
} else if (r == BubbleController.DISMISS_BLOCKED) {
|
||||
} else if (r == Bubbles.DISMISS_BLOCKED) {
|
||||
log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BLOCKED);
|
||||
}
|
||||
}
|
||||
@@ -107,10 +107,10 @@ public class BubbleLogger {
|
||||
* @param b Bubble added to overflow
|
||||
* @param r Reason that bubble was added to overflow
|
||||
*/
|
||||
public void logOverflowAdd(Bubble b, @BubbleController.DismissReason int r) {
|
||||
if (r == BubbleController.DISMISS_AGED) {
|
||||
public void logOverflowAdd(Bubble b, @Bubbles.DismissReason int r) {
|
||||
if (r == Bubbles.DISMISS_AGED) {
|
||||
log(b, Event.BUBBLE_OVERFLOW_ADD_AGED);
|
||||
} else if (r == BubbleController.DISMISS_USER_GESTURE) {
|
||||
} else if (r == Bubbles.DISMISS_USER_GESTURE) {
|
||||
log(b, Event.BUBBLE_OVERFLOW_ADD_USER_GESTURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.android.systemui.R
|
||||
|
||||
class BubbleOverflow(
|
||||
private val context: Context,
|
||||
private val controller: BubbleController,
|
||||
private val stack: BubbleStackView
|
||||
) : BubbleViewProvider {
|
||||
|
||||
@@ -56,8 +57,8 @@ class BubbleOverflow(
|
||||
init {
|
||||
updateResources()
|
||||
with(expandedView) {
|
||||
initialize(controller, stack)
|
||||
setOverflow(true)
|
||||
setStackView(stack)
|
||||
applyThemeAttrs()
|
||||
}
|
||||
with(overflowBtn) {
|
||||
|
||||
@@ -63,7 +63,7 @@ public class BubbleOverflowActivity extends Activity {
|
||||
private TextView mEmptyStateTitle;
|
||||
private TextView mEmptyStateSubtitle;
|
||||
private ImageView mEmptyStateImage;
|
||||
private Bubbles mBubbles;
|
||||
private BubbleController mController;
|
||||
private BubbleOverflowAdapter mAdapter;
|
||||
private RecyclerView mRecyclerView;
|
||||
private List<Bubble> mOverflowBubbles = new ArrayList<>();
|
||||
@@ -111,7 +111,7 @@ public class BubbleOverflowActivity extends Activity {
|
||||
if (intent != null && intent.getExtras() != null) {
|
||||
IBinder binder = intent.getExtras().getBinder(EXTRA_BUBBLE_CONTROLLER);
|
||||
if (binder instanceof ObjectWrapper) {
|
||||
mBubbles = ((ObjectWrapper<Bubbles>) binder).get();
|
||||
mController = ((ObjectWrapper<BubbleController>) binder).get();
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "Bubble overflow activity created without bubble controller!");
|
||||
@@ -139,15 +139,15 @@ public class BubbleOverflowActivity extends Activity {
|
||||
final int viewHeight = recyclerViewHeight / rows;
|
||||
|
||||
mAdapter = new BubbleOverflowAdapter(getApplicationContext(), mOverflowBubbles,
|
||||
mBubbles::promoteBubbleFromOverflow, viewWidth, viewHeight);
|
||||
mController::promoteBubbleFromOverflow, viewWidth, viewHeight);
|
||||
mRecyclerView.setAdapter(mAdapter);
|
||||
|
||||
mOverflowBubbles.clear();
|
||||
mOverflowBubbles.addAll(mBubbles.getOverflowBubbles());
|
||||
mOverflowBubbles.addAll(mController.getOverflowBubbles());
|
||||
mAdapter.notifyDataSetChanged();
|
||||
updateEmptyStateVisibility();
|
||||
|
||||
mBubbles.setOverflowListener(mDataListener);
|
||||
mController.setOverflowListener(mDataListener);
|
||||
updateTheme();
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ public class BubbleOverflowActivity extends Activity {
|
||||
|
||||
if (DEBUG_OVERFLOW) {
|
||||
Log.d(TAG, BubbleDebugConfig.formatBubblesString(
|
||||
mBubbles.getOverflowBubbles(), null));
|
||||
mController.getOverflowBubbles(), null));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -155,7 +155,7 @@ public class BubbleStackView extends FrameLayout
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
interface SurfaceSynchronizer {
|
||||
public interface SurfaceSynchronizer {
|
||||
/**
|
||||
* Wait until requested change on a {@link View} is reflected on the screen.
|
||||
*
|
||||
@@ -186,7 +186,7 @@ public class BubbleStackView extends FrameLayout
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private final BubbleController mBubbleController;
|
||||
private final BubbleData mBubbleData;
|
||||
|
||||
private final ValueAnimator mDesaturateAndDarkenAnimator;
|
||||
@@ -383,22 +383,6 @@ public class BubbleStackView extends FrameLayout
|
||||
@NonNull
|
||||
private final SurfaceSynchronizer mSurfaceSynchronizer;
|
||||
|
||||
/**
|
||||
* Callback to run when the IME visibility changes - BubbleController uses this to update the
|
||||
* Bubbles window focusability flags with the WindowManager.
|
||||
*/
|
||||
public final Consumer<Boolean> mOnImeVisibilityChanged;
|
||||
|
||||
/**
|
||||
* Callback to run when the bubble expand status changes.
|
||||
*/
|
||||
private final Consumer<Boolean> mOnBubbleExpandChanged;
|
||||
|
||||
/**
|
||||
* Callback to run to ask BubbleController to hide the current IME.
|
||||
*/
|
||||
private final Runnable mHideCurrentInputMethodCallback;
|
||||
|
||||
/**
|
||||
* The currently magnetized object, which is being dragged and will be attracted to the magnetic
|
||||
* dismiss target.
|
||||
@@ -733,16 +717,12 @@ public class BubbleStackView extends FrameLayout
|
||||
private BubblePositioner mPositioner;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
public BubbleStackView(Context context, BubbleData data,
|
||||
@Nullable SurfaceSynchronizer synchronizer,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
Runnable allBubblesAnimatedOutAction,
|
||||
Consumer<Boolean> onImeVisibilityChanged,
|
||||
Runnable hideCurrentInputMethodCallback,
|
||||
Consumer<Boolean> onBubbleExpandChanged,
|
||||
BubblePositioner positioner) {
|
||||
public BubbleStackView(Context context, BubbleController bubbleController,
|
||||
BubbleData data, @Nullable SurfaceSynchronizer synchronizer,
|
||||
FloatingContentCoordinator floatingContentCoordinator) {
|
||||
super(context);
|
||||
|
||||
mBubbleController = bubbleController;
|
||||
mBubbleData = data;
|
||||
|
||||
Resources res = getResources();
|
||||
@@ -755,7 +735,7 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
|
||||
|
||||
mPositioner = positioner;
|
||||
mPositioner = mBubbleController.getPositioner();
|
||||
|
||||
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
|
||||
int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
|
||||
@@ -767,7 +747,7 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
final Runnable onBubbleAnimatedOut = () -> {
|
||||
if (getBubbleCount() == 0) {
|
||||
allBubblesAnimatedOutAction.run();
|
||||
mBubbleController.onAllBubblesAnimatedOut();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -839,7 +819,7 @@ public class BubbleStackView extends FrameLayout
|
||||
setFocusable(true);
|
||||
mBubbleContainer.bringToFront();
|
||||
|
||||
mBubbleOverflow = new BubbleOverflow(getContext(), this);
|
||||
mBubbleOverflow = new BubbleOverflow(getContext(), bubbleController, this);
|
||||
mBubbleContainer.addView(mBubbleOverflow.getIconView(),
|
||||
mBubbleContainer.getChildCount() /* index */,
|
||||
new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -850,12 +830,9 @@ public class BubbleStackView extends FrameLayout
|
||||
showManageMenu(false);
|
||||
});
|
||||
|
||||
mOnImeVisibilityChanged = onImeVisibilityChanged;
|
||||
mHideCurrentInputMethodCallback = hideCurrentInputMethodCallback;
|
||||
mOnBubbleExpandChanged = onBubbleExpandChanged;
|
||||
|
||||
setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
|
||||
onImeVisibilityChanged.accept(insets.getInsets(WindowInsets.Type.ime()).bottom > 0);
|
||||
mBubbleController.onImeVisibilityChanged(
|
||||
insets.getInsets(WindowInsets.Type.ime()).bottom > 0);
|
||||
if (!mIsExpanded || mIsExpansionAnimating) {
|
||||
return view.onApplyWindowInsets(insets);
|
||||
}
|
||||
@@ -1299,7 +1276,7 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
// R constants are not final so we cannot use switch-case here.
|
||||
if (action == AccessibilityNodeInfo.ACTION_DISMISS) {
|
||||
mBubbleData.dismissAll(BubbleController.DISMISS_ACCESSIBILITY_ACTION);
|
||||
mBubbleData.dismissAll(Bubbles.DISMISS_ACCESSIBILITY_ACTION);
|
||||
announceForAccessibility(
|
||||
getResources().getString(R.string.accessibility_bubble_dismissed));
|
||||
return true;
|
||||
@@ -1402,8 +1379,9 @@ public class BubbleStackView extends FrameLayout
|
||||
/**
|
||||
* The {@link Bubble} that is expanded, null if one does not exist.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
BubbleViewProvider getExpandedBubble() {
|
||||
public BubbleViewProvider getExpandedBubble() {
|
||||
return mExpandedBubble;
|
||||
}
|
||||
|
||||
@@ -1617,7 +1595,7 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
hideCurrentInputMethod();
|
||||
|
||||
mOnBubbleExpandChanged.accept(shouldExpand);
|
||||
mBubbleController.getSysuiProxy().onStackExpandChanged(shouldExpand);
|
||||
|
||||
if (mIsExpanded) {
|
||||
animateCollapse();
|
||||
@@ -1637,7 +1615,7 @@ public class BubbleStackView extends FrameLayout
|
||||
* not.
|
||||
*/
|
||||
void hideCurrentInputMethod() {
|
||||
mHideCurrentInputMethodCallback.run();
|
||||
mBubbleController.hideCurrentInputMethod();
|
||||
}
|
||||
|
||||
private void beforeExpandedViewAnimation() {
|
||||
@@ -2135,14 +2113,13 @@ public class BubbleStackView extends FrameLayout
|
||||
final View draggedOutBubbleView = (View) mMagnetizedObject.getUnderlyingObject();
|
||||
dismissBubbleIfExists(mBubbleData.getBubbleWithView(draggedOutBubbleView));
|
||||
} else {
|
||||
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
|
||||
}
|
||||
}
|
||||
|
||||
private void dismissBubbleIfExists(@Nullable Bubble bubble) {
|
||||
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
bubble.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(bubble.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
|
||||
private Bubble mBubble;
|
||||
private WeakReference<Context> mContext;
|
||||
private WeakReference<BubbleController> mController;
|
||||
private WeakReference<BubbleStackView> mStackView;
|
||||
private BubbleIconFactory mIconFactory;
|
||||
private boolean mSkipInflation;
|
||||
@@ -77,12 +78,14 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
*/
|
||||
BubbleViewInfoTask(Bubble b,
|
||||
Context context,
|
||||
BubbleController controller,
|
||||
BubbleStackView stackView,
|
||||
BubbleIconFactory factory,
|
||||
boolean skipInflation,
|
||||
Callback c) {
|
||||
mBubble = b;
|
||||
mContext = new WeakReference<>(context);
|
||||
mController = new WeakReference<>(controller);
|
||||
mStackView = new WeakReference<>(stackView);
|
||||
mIconFactory = factory;
|
||||
mSkipInflation = skipInflation;
|
||||
@@ -91,8 +94,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
|
||||
@Override
|
||||
protected BubbleViewInfo doInBackground(Void... voids) {
|
||||
return BubbleViewInfo.populate(mContext.get(), mStackView.get(), mIconFactory, mBubble,
|
||||
mSkipInflation);
|
||||
return BubbleViewInfo.populate(mContext.get(), mController.get(), mStackView.get(),
|
||||
mIconFactory, mBubble, mSkipInflation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -121,8 +124,9 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
Bubble.FlyoutMessage flyoutMessage;
|
||||
|
||||
@Nullable
|
||||
static BubbleViewInfo populate(Context c, BubbleStackView stackView,
|
||||
BubbleIconFactory iconFactory, Bubble b, boolean skipInflation) {
|
||||
static BubbleViewInfo populate(Context c, BubbleController controller,
|
||||
BubbleStackView stackView, BubbleIconFactory iconFactory, Bubble b,
|
||||
boolean skipInflation) {
|
||||
BubbleViewInfo info = new BubbleViewInfo();
|
||||
|
||||
// View inflation: only should do this once per bubble
|
||||
@@ -133,7 +137,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
|
||||
info.expandedView = (BubbleExpandedView) inflater.inflate(
|
||||
R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
|
||||
info.expandedView.setStackView(stackView);
|
||||
info.expandedView.initialize(controller, stackView);
|
||||
}
|
||||
|
||||
if (b.getShortcutInfo() != null) {
|
||||
|
||||
@@ -26,7 +26,7 @@ import androidx.annotation.Nullable;
|
||||
/**
|
||||
* Interface to represent actual Bubbles and UI elements that act like bubbles, like BubbleOverflow.
|
||||
*/
|
||||
interface BubbleViewProvider {
|
||||
public interface BubbleViewProvider {
|
||||
@Nullable BubbleExpandedView getExpandedView();
|
||||
|
||||
void setContentVisibility(boolean visible);
|
||||
|
||||
@@ -16,62 +16,93 @@
|
||||
|
||||
package com.android.systemui.bubbles;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import android.content.res.Configuration;
|
||||
import android.service.notification.NotificationListenerService.RankingMap;
|
||||
import android.util.ArraySet;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.systemui.statusbar.ScrimView;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.phone.ScrimController;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.List;
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
/**
|
||||
* Interface to engage bubbles feature.
|
||||
*/
|
||||
public interface Bubbles {
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
|
||||
DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
|
||||
DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
|
||||
DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
|
||||
DISMISS_NO_BUBBLE_UP})
|
||||
@Target({FIELD, LOCAL_VARIABLE, PARAMETER})
|
||||
@interface DismissReason {}
|
||||
|
||||
int DISMISS_USER_GESTURE = 1;
|
||||
int DISMISS_AGED = 2;
|
||||
int DISMISS_TASK_FINISHED = 3;
|
||||
int DISMISS_BLOCKED = 4;
|
||||
int DISMISS_NOTIF_CANCEL = 5;
|
||||
int DISMISS_ACCESSIBILITY_ACTION = 6;
|
||||
int DISMISS_NO_LONGER_BUBBLE = 7;
|
||||
int DISMISS_USER_CHANGED = 8;
|
||||
int DISMISS_GROUP_CANCELLED = 9;
|
||||
int DISMISS_INVALID_INTENT = 10;
|
||||
int DISMISS_OVERFLOW_MAX_REACHED = 11;
|
||||
int DISMISS_SHORTCUT_REMOVED = 12;
|
||||
int DISMISS_PACKAGE_REMOVED = 13;
|
||||
int DISMISS_NO_BUBBLE_UP = 14;
|
||||
|
||||
/**
|
||||
* @return {@code true} if there is a bubble associated with the provided key and if its
|
||||
* notification is hidden from the shade or there is a group summary associated with the
|
||||
* provided key that is hidden from the shade because it has been dismissed but still has child
|
||||
* bubbles active.
|
||||
*/
|
||||
boolean isBubbleNotificationSuppressedFromShade(NotificationEntry entry);
|
||||
boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey);
|
||||
|
||||
/**
|
||||
* @return {@code true} if the current notification entry same as selected bubble
|
||||
* notification entry and the stack is currently expanded.
|
||||
*/
|
||||
boolean isBubbleExpanded(NotificationEntry entry);
|
||||
boolean isBubbleExpanded(String key);
|
||||
|
||||
/** @return {@code true} if stack of bubbles is expanded or not. */
|
||||
boolean isStackExpanded();
|
||||
|
||||
/**
|
||||
* @return the {@link ScrimView} drawn behind the bubble stack. This is managed by
|
||||
* {@link ScrimController} since we want the scrim's appearance and behavior to be identical to
|
||||
* that of the notification shade scrim.
|
||||
*/
|
||||
ScrimView getScrimForBubble();
|
||||
/** @return {@code true} if the summary for the provided group key is suppressed. */
|
||||
boolean isSummarySuppressed(String groupKey);
|
||||
|
||||
/** @return Bubbles for updating overflow. */
|
||||
List<Bubble> getOverflowBubbles();
|
||||
/**
|
||||
* Removes a group key indicating that summary for this group should no longer be suppressed.
|
||||
*/
|
||||
void removeSuppressedSummary(String groupKey);
|
||||
|
||||
/** Tell the stack of bubbles to collapse. */
|
||||
void collapseStack();
|
||||
|
||||
/** Tell the controller need update its UI to fit theme. */
|
||||
void updateForThemeChanges();
|
||||
|
||||
/**
|
||||
* Request the stack expand if needed, then select the specified Bubble as current.
|
||||
* If no bubble exists for this entry, one is created.
|
||||
*
|
||||
* @param entry the notification for the bubble to be selected
|
||||
*/
|
||||
void expandStackAndSelectBubble(NotificationEntry entry);
|
||||
|
||||
/** Promote the provided bubbles when overflow view. */
|
||||
void promoteBubbleFromOverflow(Bubble bubble);
|
||||
void expandStackAndSelectBubble(BubbleEntry entry);
|
||||
|
||||
/**
|
||||
* We intercept notification entries (including group summaries) dismissed by the user when
|
||||
@@ -81,26 +112,65 @@ public interface Bubbles {
|
||||
* {@link Bubble#setSuppressNotification}. For the case of suppressed summaries, we also add
|
||||
* {@link BubbleData#addSummaryToSuppress}.
|
||||
*
|
||||
* @param entry the notification of the BubbleEntry should be removed.
|
||||
* @param children the list of child notification of the BubbleEntry from 1st param entry,
|
||||
* this will be null if entry does have no children.
|
||||
* @param removeCallback the remove callback for SystemUI side to remove notification, the int
|
||||
* number should be list position of children list and use -1 for
|
||||
* removing the parent notification.
|
||||
*
|
||||
* @return true if we want to intercept the dismissal of the entry, else false.
|
||||
*/
|
||||
boolean handleDismissalInterception(NotificationEntry entry);
|
||||
boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children,
|
||||
IntConsumer removeCallback);
|
||||
|
||||
/**
|
||||
* Removes the bubble with the given key.
|
||||
* <p>
|
||||
* Must be called from the main thread.
|
||||
*/
|
||||
@MainThread
|
||||
void removeBubble(String key, int reason);
|
||||
|
||||
|
||||
/**
|
||||
* When a notification is marked Priority, expand the stack if needed,
|
||||
* then (maybe create and) select the given bubble.
|
||||
* Retrieves the notif entry key of the summary associated with the provided group key.
|
||||
*
|
||||
* @param entry the notification for the bubble to show
|
||||
* @param groupKey the group to look up
|
||||
* @return the key for the notification that is the summary of this group.
|
||||
*/
|
||||
void onUserChangedImportance(NotificationEntry entry);
|
||||
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 a listener to be notified of bubble expand events. */
|
||||
void setExpandListener(BubbleExpandListener listener);
|
||||
|
||||
/**
|
||||
* Called when new notification entry added.
|
||||
*
|
||||
* @param entry the {@link BubbleEntry} by the notification.
|
||||
*/
|
||||
void onEntryAdded(BubbleEntry entry);
|
||||
|
||||
/**
|
||||
* Called when new notification entry updated.
|
||||
*
|
||||
* @param entry the {@link BubbleEntry} by the notification.
|
||||
* @param shouldBubbleUp {@code true} if this notification should bubble up.
|
||||
*/
|
||||
void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp);
|
||||
|
||||
/**
|
||||
* Called when new notification entry removed.
|
||||
*
|
||||
* @param entry the {@link BubbleEntry} by the notification.
|
||||
*/
|
||||
void onEntryRemoved(BubbleEntry entry);
|
||||
|
||||
/**
|
||||
* Called when NotificationListener has received adjusted notification rank and reapplied
|
||||
* filtering and sorting. This is used to dismiss or create bubbles based on changes in
|
||||
* permissions on the notification channel or the global setting.
|
||||
*
|
||||
* @param rankingMap the updated ranking map from NotificationListenerService
|
||||
*/
|
||||
void onRankingUpdated(RankingMap rankingMap);
|
||||
|
||||
/**
|
||||
* Called when the status bar has become visible or invisible (either permanently or
|
||||
@@ -108,30 +178,85 @@ public interface Bubbles {
|
||||
*/
|
||||
void onStatusBarVisibilityChanged(boolean visible);
|
||||
|
||||
/** Called when system zen mode state changed. */
|
||||
void onZenStateChanged();
|
||||
|
||||
/**
|
||||
* Called when a user has indicated that an active notification should be shown as a bubble.
|
||||
* <p>
|
||||
* This method will collapse the shade, create the bubble without a flyout or dot, and suppress
|
||||
* the notification from appearing in the shade.
|
||||
* Called when statusBar state changed.
|
||||
*
|
||||
* @param entry the notification to change bubble state for.
|
||||
* @param shouldBubble whether the notification should show as a bubble or not.
|
||||
* @param isShade {@code true} is state is SHADE.
|
||||
*/
|
||||
void onUserChangedBubble(@NonNull NotificationEntry entry, boolean shouldBubble);
|
||||
void onStatusBarStateChanged(boolean isShade);
|
||||
|
||||
/**
|
||||
* Called when the current user changed.
|
||||
*
|
||||
* @param newUserId the new user's id.
|
||||
*/
|
||||
void onUserChanged(int newUserId);
|
||||
|
||||
/** See {@link BubbleController.NotifCallback}. */
|
||||
void addNotifCallback(BubbleController.NotifCallback callback);
|
||||
/**
|
||||
* Called when config changed.
|
||||
*
|
||||
* @param newConfig the new config.
|
||||
*/
|
||||
void onConfigChanged(Configuration newConfig);
|
||||
|
||||
/** Set a listener to be notified of bubble expand events. */
|
||||
void setExpandListener(BubbleController.BubbleExpandListener listener);
|
||||
/** Description of current bubble state. */
|
||||
void dump(FileDescriptor fd, PrintWriter pw, String[] args);
|
||||
|
||||
/** Set a listener to be notified of when overflow view update. */
|
||||
void setOverflowListener(BubbleData.Listener listener);
|
||||
/** Listener to find out about stack expansion / collapse events. */
|
||||
interface BubbleExpandListener {
|
||||
/**
|
||||
* Called when the expansion state of the bubble stack changes.
|
||||
*
|
||||
* @param isExpanding whether it's expanding or collapsing
|
||||
* @param key the notification key associated with bubble being expanded
|
||||
*/
|
||||
void onBubbleExpandChanged(boolean isExpanding, String key);
|
||||
}
|
||||
|
||||
/** The task listener for events in bubble tasks. **/
|
||||
ShellTaskOrganizer getTaskOrganizer();
|
||||
/** Listener to be notified when a bubbles' notification suppression state changes.*/
|
||||
interface NotificationSuppressionChangedListener {
|
||||
/** Called when the notification suppression state of a bubble changes. */
|
||||
void onBubbleNotificationSuppressionChange(Bubble bubble);
|
||||
}
|
||||
|
||||
/** Contains information to help position things on the screen. */
|
||||
BubblePositioner getPositioner();
|
||||
/** Listener to be notified when a pending intent has been canceled for a bubble. */
|
||||
interface PendingIntentCanceledListener {
|
||||
/** Called when the pending intent for a bubble has been canceled. */
|
||||
void onPendingIntentCanceled(Bubble bubble);
|
||||
}
|
||||
|
||||
/** Callback to tell SysUi components execute some methods. */
|
||||
interface SysuiProxy {
|
||||
@Nullable
|
||||
BubbleEntry getPendingOrActiveEntry(String key);
|
||||
|
||||
List<BubbleEntry> getShouldRestoredEntries(ArraySet<String> savedBubbleKeys);
|
||||
|
||||
boolean isNotificationShadeExpand();
|
||||
|
||||
boolean shouldBubbleUp(String key);
|
||||
|
||||
void setNotificationInterruption(String key);
|
||||
|
||||
void requestNotificationShadeTopUi(boolean requestTopUi, String componentTag);
|
||||
|
||||
void notifyRemoveNotification(String key, int reason);
|
||||
|
||||
void notifyInvalidateNotifications(String reason);
|
||||
|
||||
void notifyMaybeCancelSummary(String key);
|
||||
|
||||
void removeNotificationEntry(String key);
|
||||
|
||||
void updateNotificationBubbleButton(String key);
|
||||
|
||||
void updateNotificationSuppression(String key);
|
||||
|
||||
void onStackExpandChanged(boolean shouldExpand);
|
||||
|
||||
void onUnbubbleConversation(String key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import android.content.pm.LauncherApps;
|
||||
import android.os.Handler;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.systemui.bubbles.BubbleController;
|
||||
@@ -41,10 +43,13 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@@ -56,23 +61,8 @@ public interface BubbleModule {
|
||||
*/
|
||||
@SysUISingleton
|
||||
@Provides
|
||||
static Bubbles newBubbleController(
|
||||
Context context,
|
||||
NotificationShadeWindowController notificationShadeWindowController,
|
||||
StatusBarStateController statusBarStateController,
|
||||
ShadeController shadeController,
|
||||
ConfigurationController configurationController,
|
||||
NotificationInterruptStateProvider interruptionStateProvider,
|
||||
ZenModeController zenModeController,
|
||||
NotificationLockscreenUserManager notifUserManager,
|
||||
NotificationGroupManagerLegacy groupManager,
|
||||
NotificationEntryManager entryManager,
|
||||
NotifPipeline notifPipeline,
|
||||
FeatureFlags featureFlags,
|
||||
DumpManager dumpManager,
|
||||
static Bubbles newBubbleController(Context context,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
SysUiState sysUiState,
|
||||
INotificationManager notifManager,
|
||||
IStatusBarService statusBarService,
|
||||
WindowManager windowManager,
|
||||
WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
@@ -80,30 +70,29 @@ public interface BubbleModule {
|
||||
UiEventLogger uiEventLogger,
|
||||
@Main Handler mainHandler,
|
||||
ShellTaskOrganizer organizer) {
|
||||
return BubbleController.create(
|
||||
context,
|
||||
notificationShadeWindowController,
|
||||
statusBarStateController,
|
||||
shadeController,
|
||||
null /* synchronizer */,
|
||||
configurationController,
|
||||
interruptionStateProvider,
|
||||
zenModeController,
|
||||
notifUserManager,
|
||||
groupManager,
|
||||
entryManager,
|
||||
notifPipeline,
|
||||
featureFlags,
|
||||
dumpManager,
|
||||
floatingContentCoordinator,
|
||||
sysUiState,
|
||||
notifManager,
|
||||
statusBarService,
|
||||
windowManager,
|
||||
windowManagerShellWrapper,
|
||||
launcherApps,
|
||||
uiEventLogger,
|
||||
mainHandler,
|
||||
organizer);
|
||||
return BubbleController.create(context, null /* synchronizer */, floatingContentCoordinator,
|
||||
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
|
||||
uiEventLogger, mainHandler, organizer);
|
||||
}
|
||||
|
||||
/** Provides Optional of BubbleManager */
|
||||
@SysUISingleton
|
||||
@Provides
|
||||
static Optional<BubblesManager> provideBubblesManager(Context context,
|
||||
Optional<Bubbles> bubblesOptional,
|
||||
NotificationShadeWindowController notificationShadeWindowController,
|
||||
StatusBarStateController statusBarStateController, ShadeController shadeController,
|
||||
ConfigurationController configurationController,
|
||||
@Nullable IStatusBarService statusBarService, INotificationManager notificationManager,
|
||||
NotificationInterruptStateProvider interruptionStateProvider,
|
||||
ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager,
|
||||
NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager,
|
||||
NotifPipeline notifPipeline, SysUiState sysUiState, FeatureFlags featureFlags,
|
||||
DumpManager dumpManager) {
|
||||
return Optional.ofNullable(BubblesManager.create(context, bubblesOptional,
|
||||
notificationShadeWindowController, statusBarStateController, shadeController,
|
||||
configurationController, statusBarService, notificationManager,
|
||||
interruptionStateProvider, zenModeController, notifUserManager,
|
||||
groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,8 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
|
||||
for (int i = 0; i < N; i++) {
|
||||
NotificationEntry ent = activeNotifications.get(i);
|
||||
final boolean isBubbleNotificationSuppressedFromShade = mBubblesOptional.isPresent()
|
||||
&& mBubblesOptional.get().isBubbleNotificationSuppressedFromShade(ent);
|
||||
&& mBubblesOptional.get().isBubbleNotificationSuppressedFromShade(
|
||||
ent.getKey(), ent.getSbn().getGroupKey());
|
||||
if (ent.isRowDismissed() || ent.isRowRemoved()
|
||||
|| isBubbleNotificationSuppressedFromShade
|
||||
|| mFgsSectionController.hasEntry(ent)) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
@@ -56,6 +57,7 @@ import javax.inject.Inject;
|
||||
public class BubbleCoordinator implements Coordinator {
|
||||
private static final String TAG = "BubbleCoordinator";
|
||||
|
||||
private final Optional<BubblesManager> mBubblesManagerOptional;
|
||||
private final Optional<Bubbles> mBubblesOptional;
|
||||
private final NotifCollection mNotifCollection;
|
||||
private final Set<String> mInterceptedDismissalEntries = new HashSet<>();
|
||||
@@ -64,8 +66,10 @@ public class BubbleCoordinator implements Coordinator {
|
||||
|
||||
@Inject
|
||||
public BubbleCoordinator(
|
||||
Optional<BubblesManager> bubblesManagerOptional,
|
||||
Optional<Bubbles> bubblesOptional,
|
||||
NotifCollection notifCollection) {
|
||||
mBubblesManagerOptional = bubblesManagerOptional;
|
||||
mBubblesOptional = bubblesOptional;
|
||||
mNotifCollection = notifCollection;
|
||||
}
|
||||
@@ -75,8 +79,8 @@ public class BubbleCoordinator implements Coordinator {
|
||||
mNotifPipeline = pipeline;
|
||||
mNotifPipeline.addNotificationDismissInterceptor(mDismissInterceptor);
|
||||
mNotifPipeline.addFinalizeFilter(mNotifFilter);
|
||||
if (mBubblesOptional.isPresent()) {
|
||||
mBubblesOptional.get().addNotifCallback(mNotifCallback);
|
||||
if (mBubblesManagerOptional.isPresent()) {
|
||||
mBubblesManagerOptional.get().addNotifCallback(mNotifCallback);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -85,7 +89,8 @@ public class BubbleCoordinator implements Coordinator {
|
||||
@Override
|
||||
public boolean shouldFilterOut(NotificationEntry entry, long now) {
|
||||
return mBubblesOptional.isPresent()
|
||||
&& mBubblesOptional.get().isBubbleNotificationSuppressedFromShade(entry);
|
||||
&& mBubblesOptional.get().isBubbleNotificationSuppressedFromShade(
|
||||
entry.getKey(), entry.getSbn().getGroupKey());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -102,9 +107,8 @@ public class BubbleCoordinator implements Coordinator {
|
||||
|
||||
@Override
|
||||
public boolean shouldInterceptDismissal(NotificationEntry entry) {
|
||||
// for experimental bubbles
|
||||
if (mBubblesOptional.isPresent()
|
||||
&& mBubblesOptional.get().handleDismissalInterception(entry)) {
|
||||
if (mBubblesManagerOptional.isPresent()
|
||||
&& mBubblesManagerOptional.get().handleDismissalInterception(entry)) {
|
||||
mInterceptedDismissalEntries.add(entry.getKey());
|
||||
return true;
|
||||
} else {
|
||||
@@ -119,8 +123,7 @@ public class BubbleCoordinator implements Coordinator {
|
||||
}
|
||||
};
|
||||
|
||||
private final BubbleController.NotifCallback mNotifCallback =
|
||||
new BubbleController.NotifCallback() {
|
||||
private final BubblesManager.NotifCallback mNotifCallback = new BubblesManager.NotifCallback() {
|
||||
@Override
|
||||
public void removeNotification(
|
||||
NotificationEntry entry,
|
||||
|
||||
@@ -64,7 +64,7 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,
|
||||
new ArraySet<>();
|
||||
private final ArraySet<OnGroupChangeListener> mGroupChangeListeners = new ArraySet<>();
|
||||
private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier;
|
||||
private final Optional<Lazy<Bubbles>> mBubblesOptional;
|
||||
private final Optional<Bubbles> mBubblesOptional;
|
||||
private int mBarState = -1;
|
||||
private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
|
||||
private HeadsUpManager mHeadsUpManager;
|
||||
@@ -74,7 +74,7 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,
|
||||
public NotificationGroupManagerLegacy(
|
||||
StatusBarStateController statusBarStateController,
|
||||
Lazy<PeopleNotificationIdentifier> peopleNotificationIdentifier,
|
||||
Optional<Lazy<Bubbles>> bubblesOptional) {
|
||||
Optional<Bubbles> bubblesOptional) {
|
||||
statusBarStateController.addCallback(this);
|
||||
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
|
||||
mBubblesOptional = bubblesOptional;
|
||||
@@ -242,8 +242,9 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,
|
||||
int childCount = 0;
|
||||
boolean hasBubbles = false;
|
||||
for (NotificationEntry entry : group.children.values()) {
|
||||
if (mBubblesOptional.isPresent() && !mBubblesOptional.get().get()
|
||||
.isBubbleNotificationSuppressedFromShade(entry)) {
|
||||
if (mBubblesOptional.isPresent() && !mBubblesOptional.get()
|
||||
.isBubbleNotificationSuppressedFromShade(
|
||||
entry.getKey(), entry.getSbn().getGroupKey())) {
|
||||
childCount++;
|
||||
} else {
|
||||
hasBubbles = true;
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.view.accessibility.AccessibilityManager;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Background;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
@@ -73,6 +72,7 @@ import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogC
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
||||
import com.android.systemui.util.leak.LeakDetector;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -133,7 +133,7 @@ public interface NotificationsModule {
|
||||
UserContextProvider contextTracker,
|
||||
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
|
||||
AssistantFeedbackController assistantFeedbackController,
|
||||
Optional<Bubbles> bubblesOptional,
|
||||
Optional<BubblesManager> bubblesManagerOptional,
|
||||
UiEventLogger uiEventLogger,
|
||||
OnUserInteractionCallback onUserInteractionCallback) {
|
||||
return new NotificationGutsManager(
|
||||
@@ -150,7 +150,7 @@ public interface NotificationsModule {
|
||||
contextTracker,
|
||||
builderProvider,
|
||||
assistantFeedbackController,
|
||||
bubblesOptional,
|
||||
bubblesManagerOptional,
|
||||
uiEventLogger,
|
||||
onUserInteractionCallback);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,6 @@ import com.android.internal.widget.CachingIconView;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.Interpolators;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.PluginListener;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
@@ -102,12 +101,14 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
||||
import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
@@ -147,6 +148,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
private LayoutListener mLayoutListener;
|
||||
private RowContentBindStage mRowContentBindStage;
|
||||
private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
|
||||
private Optional<BubblesManager> mBubblesManagerOptional;
|
||||
private int mIconTransformContentShift;
|
||||
private int mMaxHeadsUpHeightBeforeN;
|
||||
private int mMaxHeadsUpHeightBeforeP;
|
||||
@@ -1078,13 +1080,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
|
||||
/** The click listener for the bubble button. */
|
||||
public View.OnClickListener getBubbleClickListener() {
|
||||
return new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Dependency.get(Bubbles.class)
|
||||
.onUserChangedBubble(mEntry, !mEntry.isBubble() /* createBubble */);
|
||||
mHeadsUpManager.removeNotification(mEntry.getKey(), true /* releaseImmediately */);
|
||||
return v -> {
|
||||
if (mBubblesManagerOptional.isPresent()) {
|
||||
mBubblesManagerOptional.get()
|
||||
.onUserChangedBubble(mEntry, !mEntry.isBubble() /* createBubble */);
|
||||
}
|
||||
mHeadsUpManager.removeNotification(mEntry.getKey(), true /* releaseImmediately */);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1553,7 +1554,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
FalsingManager falsingManager,
|
||||
StatusBarStateController statusBarStateController,
|
||||
PeopleNotificationIdentifier peopleNotificationIdentifier,
|
||||
OnUserInteractionCallback onUserInteractionCallback) {
|
||||
OnUserInteractionCallback onUserInteractionCallback,
|
||||
Optional<BubblesManager> bubblesManagerOptional) {
|
||||
mEntry = entry;
|
||||
mAppName = appName;
|
||||
if (mMenuRow == null) {
|
||||
@@ -1581,6 +1583,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier);
|
||||
}
|
||||
mOnUserInteractionCallback = onUserInteractionCallback;
|
||||
mBubblesManagerOptional = bubblesManagerOptional;
|
||||
|
||||
cacheIsSystemNotification();
|
||||
}
|
||||
|
||||
@@ -43,8 +43,10 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
||||
import com.android.systemui.util.time.SystemClock;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
@@ -79,6 +81,7 @@ public class ExpandableNotificationRowController implements NodeController {
|
||||
private final FalsingManager mFalsingManager;
|
||||
private final boolean mAllowLongPress;
|
||||
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
|
||||
private final Optional<BubblesManager> mBubblesManagerOptional;
|
||||
|
||||
@Inject
|
||||
public ExpandableNotificationRowController(
|
||||
@@ -102,7 +105,8 @@ public class ExpandableNotificationRowController implements NodeController {
|
||||
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
|
||||
OnUserInteractionCallback onUserInteractionCallback,
|
||||
FalsingManager falsingManager,
|
||||
PeopleNotificationIdentifier peopleNotificationIdentifier) {
|
||||
PeopleNotificationIdentifier peopleNotificationIdentifier,
|
||||
Optional<BubblesManager> bubblesManagerOptional) {
|
||||
mView = view;
|
||||
mListContainer = listContainer;
|
||||
mActivatableNotificationViewController = activatableNotificationViewController;
|
||||
@@ -125,6 +129,7 @@ public class ExpandableNotificationRowController implements NodeController {
|
||||
mAllowLongPress = allowLongPress;
|
||||
mFalsingManager = falsingManager;
|
||||
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
|
||||
mBubblesManagerOptional = bubblesManagerOptional;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,8 +153,8 @@ public class ExpandableNotificationRowController implements NodeController {
|
||||
mFalsingManager,
|
||||
mStatusBarStateController,
|
||||
mPeopleNotificationIdentifier,
|
||||
mOnUserInteractionCallback
|
||||
|
||||
mOnUserInteractionCallback,
|
||||
mBubblesManagerOptional
|
||||
);
|
||||
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
|
||||
if (mAllowLongPress) {
|
||||
|
||||
@@ -67,12 +67,12 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settingslib.notification.ConversationIconFactory;
|
||||
import com.android.systemui.Prefs;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.dagger.qualifiers.Background;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.Optional;
|
||||
@@ -94,7 +94,7 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
private OnUserInteractionCallback mOnUserInteractionCallback;
|
||||
private Handler mMainHandler;
|
||||
private Handler mBgHandler;
|
||||
private Optional<Bubbles> mBubblesOptional;
|
||||
private Optional<BubblesManager> mBubblesManagerOptional;
|
||||
private String mPackageName;
|
||||
private String mAppName;
|
||||
private int mAppUid;
|
||||
@@ -223,7 +223,7 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
@Main Handler mainHandler,
|
||||
@Background Handler bgHandler,
|
||||
OnConversationSettingsClickListener onConversationSettingsClickListener,
|
||||
Optional<Bubbles> bubblesOptional) {
|
||||
Optional<BubblesManager> bubblesManagerOptional) {
|
||||
mSelectedAction = -1;
|
||||
mINotificationManager = iNotificationManager;
|
||||
mOnUserInteractionCallback = onUserInteractionCallback;
|
||||
@@ -242,7 +242,7 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
mIconFactory = conversationIconFactory;
|
||||
mUserContext = userContext;
|
||||
mBubbleMetadata = bubbleMetadata;
|
||||
mBubblesOptional = bubblesOptional;
|
||||
mBubblesManagerOptional = bubblesManagerOptional;
|
||||
mBuilderProvider = builderProvider;
|
||||
mMainHandler = mainHandler;
|
||||
mBgHandler = bgHandler;
|
||||
@@ -641,9 +641,9 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
mINotificationManager.setBubblesAllowed(mAppPkg, mAppUid,
|
||||
BUBBLE_PREFERENCE_SELECTED);
|
||||
}
|
||||
if (mBubblesOptional.isPresent()) {
|
||||
if (mBubblesManagerOptional.isPresent()) {
|
||||
post(() -> {
|
||||
mBubblesOptional.get().onUserChangedImportance(mEntry);
|
||||
mBubblesManagerOptional.get().onUserChangedImportance(mEntry);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ import com.android.settingslib.notification.ConversationIconFactory;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.dagger.qualifiers.Background;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
@@ -67,6 +66,7 @@ import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSav
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -117,7 +117,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
private final Lazy<StatusBar> mStatusBarLazy;
|
||||
private final Handler mMainHandler;
|
||||
private final Handler mBgHandler;
|
||||
private final Optional<Bubbles> mBubblesOptional;
|
||||
private final Optional<BubblesManager> mBubblesManagerOptional;
|
||||
private Runnable mOpenRunnable;
|
||||
private final INotificationManager mNotificationManager;
|
||||
private final LauncherApps mLauncherApps;
|
||||
@@ -142,7 +142,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
UserContextProvider contextTracker,
|
||||
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
|
||||
AssistantFeedbackController assistantFeedbackController,
|
||||
Optional<Bubbles> bubblesOptional,
|
||||
Optional<BubblesManager> bubblesManagerOptional,
|
||||
UiEventLogger uiEventLogger,
|
||||
OnUserInteractionCallback onUserInteractionCallback) {
|
||||
mContext = context;
|
||||
@@ -158,7 +158,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
mBuilderProvider = builderProvider;
|
||||
mChannelEditorDialogController = channelEditorDialogController;
|
||||
mAssistantFeedbackController = assistantFeedbackController;
|
||||
mBubblesOptional = bubblesOptional;
|
||||
mBubblesManagerOptional = bubblesManagerOptional;
|
||||
mUiEventLogger = uiEventLogger;
|
||||
mOnUserInteractionCallback = onUserInteractionCallback;
|
||||
}
|
||||
@@ -491,7 +491,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
mMainHandler,
|
||||
mBgHandler,
|
||||
onConversationSettingsListener,
|
||||
mBubblesOptional);
|
||||
mBubblesManagerOptional);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -306,7 +306,8 @@ public class NotificationIconAreaController implements
|
||||
|| !entry.isPulseSuppressed())) {
|
||||
return false;
|
||||
}
|
||||
if (mBubblesOptional.isPresent() && mBubblesOptional.get().isBubbleExpanded(entry)) {
|
||||
if (mBubblesOptional.isPresent()
|
||||
&& mBubblesOptional.get().isBubbleExpanded(entry.getKey())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -144,7 +144,6 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.SystemUI;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.bubbles.BubbleController;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.charging.WirelessChargingAnimation;
|
||||
import com.android.systemui.classifier.FalsingLog;
|
||||
@@ -229,6 +228,7 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
|
||||
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
|
||||
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||
import com.android.systemui.volume.VolumeComponent;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
@@ -648,8 +648,9 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
protected StatusBarNotificationPresenter mPresenter;
|
||||
private NotificationActivityStarter mNotificationActivityStarter;
|
||||
private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
|
||||
private final Optional<BubblesManager> mBubblesManagerOptional;
|
||||
private final Optional<Bubbles> mBubblesOptional;
|
||||
private final BubbleController.BubbleExpandListener mBubbleExpandListener;
|
||||
private final Bubbles.BubbleExpandListener mBubbleExpandListener;
|
||||
|
||||
private ActivityIntentHelper mActivityIntentHelper;
|
||||
private NotificationStackScrollLayoutController mStackScrollerController;
|
||||
@@ -697,6 +698,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
WakefulnessLifecycle wakefulnessLifecycle,
|
||||
SysuiStatusBarStateController statusBarStateController,
|
||||
VibratorHelper vibratorHelper,
|
||||
Optional<BubblesManager> bubblesManagerOptional,
|
||||
Optional<Bubbles> bubblesOptional,
|
||||
VisualStabilityManager visualStabilityManager,
|
||||
DeviceProvisionedController deviceProvisionedController,
|
||||
@@ -776,6 +778,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
mWakefulnessLifecycle = wakefulnessLifecycle;
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mVibratorHelper = vibratorHelper;
|
||||
mBubblesManagerOptional = bubblesManagerOptional;
|
||||
mBubblesOptional = bubblesOptional;
|
||||
mVisualStabilityManager = visualStabilityManager;
|
||||
mDeviceProvisionedController = deviceProvisionedController;
|
||||
@@ -1141,8 +1144,8 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
|
||||
ScrimView scrimBehind = mNotificationShadeWindowView.findViewById(R.id.scrim_behind);
|
||||
ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front);
|
||||
ScrimView scrimForBubble = mBubblesOptional.isPresent()
|
||||
? mBubblesOptional.get().getScrimForBubble() : null;
|
||||
ScrimView scrimForBubble = mBubblesManagerOptional.isPresent()
|
||||
? mBubblesManagerOptional.get().getScrimForBubble() : null;
|
||||
|
||||
mScrimController.setScrimVisibleListener(scrimsVisible -> {
|
||||
mNotificationShadeWindowController.setScrimsVisibility(scrimsVisible);
|
||||
|
||||
@@ -48,7 +48,6 @@ import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.systemui.ActivityIntentHelper;
|
||||
import com.android.systemui.EventLogTags;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.dagger.qualifiers.UiBackground;
|
||||
@@ -76,6 +75,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
|
||||
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpUtil;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -104,7 +104,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
||||
private final KeyguardManager mKeyguardManager;
|
||||
private final IDreamManager mDreamManager;
|
||||
private final Optional<Bubbles> mBubblesOptional;
|
||||
private final Optional<BubblesManager> mBubblesManagerOptional;
|
||||
private final Lazy<AssistManager> mAssistManagerLazy;
|
||||
private final NotificationRemoteInputManager mRemoteInputManager;
|
||||
private final GroupMembershipManager mGroupMembershipManager;
|
||||
@@ -142,7 +142,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
|
||||
KeyguardManager keyguardManager,
|
||||
IDreamManager dreamManager,
|
||||
Optional<Bubbles> bubblesOptional,
|
||||
Optional<BubblesManager> bubblesManagerOptional,
|
||||
Lazy<AssistManager> assistManagerLazy,
|
||||
NotificationRemoteInputManager remoteInputManager,
|
||||
GroupMembershipManager groupMembershipManager,
|
||||
@@ -176,7 +176,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
|
||||
mKeyguardManager = keyguardManager;
|
||||
mDreamManager = dreamManager;
|
||||
mBubblesOptional = bubblesOptional;
|
||||
mBubblesManagerOptional = bubblesManagerOptional;
|
||||
mAssistManagerLazy = assistManagerLazy;
|
||||
mRemoteInputManager = remoteInputManager;
|
||||
mGroupMembershipManager = groupMembershipManager;
|
||||
@@ -387,14 +387,15 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
}
|
||||
|
||||
private void expandBubbleStackOnMainThread(NotificationEntry entry) {
|
||||
if (!mBubblesOptional.isPresent()) {
|
||||
if (!mBubblesManagerOptional.isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Looper.getMainLooper().isCurrentThread()) {
|
||||
mBubblesOptional.get().expandStackAndSelectBubble(entry);
|
||||
mBubblesManagerOptional.get().expandStackAndSelectBubble(entry);
|
||||
} else {
|
||||
mMainThreadHandler.post(() -> mBubblesOptional.get().expandStackAndSelectBubble(entry));
|
||||
mMainThreadHandler.post(
|
||||
() -> mBubblesManagerOptional.get().expandStackAndSelectBubble(entry));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,7 +610,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
||||
private final KeyguardManager mKeyguardManager;
|
||||
private final IDreamManager mDreamManager;
|
||||
private final Optional<Bubbles> mBubblesOptional;
|
||||
private final Optional<BubblesManager> mBubblesManagerOptional;
|
||||
private final Lazy<AssistManager> mAssistManagerLazy;
|
||||
private final NotificationRemoteInputManager mRemoteInputManager;
|
||||
private final GroupMembershipManager mGroupMembershipManager;
|
||||
@@ -646,7 +647,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
|
||||
KeyguardManager keyguardManager,
|
||||
IDreamManager dreamManager,
|
||||
Optional<Bubbles> bubblesOptional,
|
||||
Optional<BubblesManager> bubblesManager,
|
||||
Lazy<AssistManager> assistManagerLazy,
|
||||
NotificationRemoteInputManager remoteInputManager,
|
||||
GroupMembershipManager groupMembershipManager,
|
||||
@@ -676,7 +677,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
|
||||
mKeyguardManager = keyguardManager;
|
||||
mDreamManager = dreamManager;
|
||||
mBubblesOptional = bubblesOptional;
|
||||
mBubblesManagerOptional = bubblesManager;
|
||||
mAssistManagerLazy = assistManagerLazy;
|
||||
mRemoteInputManager = remoteInputManager;
|
||||
mGroupMembershipManager = groupMembershipManager;
|
||||
@@ -732,7 +733,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
mStatusBarKeyguardViewManager,
|
||||
mKeyguardManager,
|
||||
mDreamManager,
|
||||
mBubblesOptional,
|
||||
mBubblesManagerOptional,
|
||||
mAssistManagerLazy,
|
||||
mRemoteInputManager,
|
||||
mGroupMembershipManager,
|
||||
|
||||
@@ -97,6 +97,7 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
|
||||
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
|
||||
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||
import com.android.systemui.volume.VolumeComponent;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -155,6 +156,7 @@ public interface StatusBarPhoneModule {
|
||||
WakefulnessLifecycle wakefulnessLifecycle,
|
||||
SysuiStatusBarStateController statusBarStateController,
|
||||
VibratorHelper vibratorHelper,
|
||||
Optional<BubblesManager> bubblesManagerOptional,
|
||||
Optional<Bubbles> bubblesOptional,
|
||||
VisualStabilityManager visualStabilityManager,
|
||||
DeviceProvisionedController deviceProvisionedController,
|
||||
@@ -233,6 +235,7 @@ public interface StatusBarPhoneModule {
|
||||
wakefulnessLifecycle,
|
||||
statusBarStateController,
|
||||
vibratorHelper,
|
||||
bubblesManagerOptional,
|
||||
bubblesOptional,
|
||||
visualStabilityManager,
|
||||
deviceProvisionedController,
|
||||
|
||||
@@ -0,0 +1,725 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
|
||||
import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
|
||||
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
|
||||
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
|
||||
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
|
||||
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
|
||||
import static android.service.notification.NotificationListenerService.REASON_CLICK;
|
||||
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
|
||||
import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
|
||||
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
|
||||
|
||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
|
||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
|
||||
import static com.android.systemui.statusbar.StatusBarState.SHADE;
|
||||
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.service.notification.NotificationListenerService.RankingMap;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.statusbar.NotificationVisibility;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.bubbles.BubbleEntry;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.model.SysUiState;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
import com.android.systemui.statusbar.FeatureFlags;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.NotificationShadeWindowController;
|
||||
import com.android.systemui.statusbar.ScrimView;
|
||||
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryListener;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifCollection;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.coordinator.BubbleCoordinator;
|
||||
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
|
||||
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
|
||||
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
|
||||
import com.android.systemui.statusbar.phone.ScrimController;
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
/**
|
||||
* The SysUi side bubbles manager which communicate with other SysUi components.
|
||||
*/
|
||||
@SysUISingleton
|
||||
public class BubblesManager implements Dumpable {
|
||||
|
||||
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubblesManager" : TAG_BUBBLES;
|
||||
|
||||
private final Context mContext;
|
||||
private final Bubbles mBubbles;
|
||||
private final NotificationShadeWindowController mNotificationShadeWindowController;
|
||||
private final ShadeController mShadeController;
|
||||
private final IStatusBarService mBarService;
|
||||
private final INotificationManager mNotificationManager;
|
||||
private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
|
||||
private final NotificationGroupManagerLegacy mNotificationGroupManager;
|
||||
private final NotificationEntryManager mNotificationEntryManager;
|
||||
private final NotifPipeline mNotifPipeline;
|
||||
|
||||
private final 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<>();
|
||||
|
||||
/**
|
||||
* Creates {@link BubblesManager}, returns {@code null} if Optional {@link Bubbles} not present
|
||||
* which means bubbles feature not support.
|
||||
*/
|
||||
@Nullable
|
||||
public static BubblesManager create(Context context,
|
||||
Optional<Bubbles> bubblesOptional,
|
||||
NotificationShadeWindowController notificationShadeWindowController,
|
||||
StatusBarStateController statusBarStateController,
|
||||
ShadeController shadeController,
|
||||
ConfigurationController configurationController,
|
||||
@Nullable IStatusBarService statusBarService,
|
||||
INotificationManager notificationManager,
|
||||
NotificationInterruptStateProvider interruptionStateProvider,
|
||||
ZenModeController zenModeController,
|
||||
NotificationLockscreenUserManager notifUserManager,
|
||||
NotificationGroupManagerLegacy groupManager,
|
||||
NotificationEntryManager entryManager,
|
||||
NotifPipeline notifPipeline,
|
||||
SysUiState sysUiState,
|
||||
FeatureFlags featureFlags,
|
||||
DumpManager dumpManager) {
|
||||
if (bubblesOptional.isPresent()) {
|
||||
return new BubblesManager(context, bubblesOptional.get(),
|
||||
notificationShadeWindowController, statusBarStateController, shadeController,
|
||||
configurationController, statusBarService, notificationManager,
|
||||
interruptionStateProvider, zenModeController, notifUserManager,
|
||||
groupManager, entryManager, notifPipeline, sysUiState, featureFlags,
|
||||
dumpManager);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
BubblesManager(Context context,
|
||||
Bubbles bubbles,
|
||||
NotificationShadeWindowController notificationShadeWindowController,
|
||||
StatusBarStateController statusBarStateController,
|
||||
ShadeController shadeController,
|
||||
ConfigurationController configurationController,
|
||||
@Nullable IStatusBarService statusBarService,
|
||||
INotificationManager notificationManager,
|
||||
NotificationInterruptStateProvider interruptionStateProvider,
|
||||
ZenModeController zenModeController,
|
||||
NotificationLockscreenUserManager notifUserManager,
|
||||
NotificationGroupManagerLegacy groupManager,
|
||||
NotificationEntryManager entryManager,
|
||||
NotifPipeline notifPipeline,
|
||||
SysUiState sysUiState,
|
||||
FeatureFlags featureFlags,
|
||||
DumpManager dumpManager) {
|
||||
mContext = context;
|
||||
mBubbles = bubbles;
|
||||
mNotificationShadeWindowController = notificationShadeWindowController;
|
||||
mShadeController = shadeController;
|
||||
mNotificationManager = notificationManager;
|
||||
mNotificationInterruptStateProvider = interruptionStateProvider;
|
||||
mNotificationGroupManager = groupManager;
|
||||
mNotificationEntryManager = entryManager;
|
||||
mNotifPipeline = notifPipeline;
|
||||
|
||||
mBarService = statusBarService == null
|
||||
? IStatusBarService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.STATUS_BAR_SERVICE))
|
||||
: statusBarService;
|
||||
|
||||
mBubbleScrim = new ScrimView(mContext);
|
||||
mBubbleScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||
mBubbles.setBubbleScrim(mBubbleScrim);
|
||||
|
||||
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||
setupNotifPipeline();
|
||||
} else {
|
||||
setupNEM();
|
||||
}
|
||||
|
||||
dumpManager.registerDumpable(TAG, this);
|
||||
|
||||
statusBarStateController.addCallback(new StatusBarStateController.StateListener() {
|
||||
@Override
|
||||
public void onStateChanged(int newState) {
|
||||
boolean isShade = newState == SHADE;
|
||||
bubbles.onStatusBarStateChanged(isShade);
|
||||
}
|
||||
});
|
||||
|
||||
configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
|
||||
@Override
|
||||
public void onConfigChanged(Configuration newConfig) {
|
||||
mBubbles.onConfigChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUiModeChanged() {
|
||||
mBubbles.updateForThemeChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onThemeChanged() {
|
||||
mBubbles.updateForThemeChanges();
|
||||
}
|
||||
});
|
||||
|
||||
zenModeController.addCallback(new ZenModeController.Callback() {
|
||||
@Override
|
||||
public void onZenChanged(int zen) {
|
||||
mBubbles.onZenStateChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigChanged(ZenModeConfig config) {
|
||||
mBubbles.onZenStateChanged();
|
||||
}
|
||||
});
|
||||
|
||||
notifUserManager.addUserChangedListener(
|
||||
new NotificationLockscreenUserManager.UserChangedListener() {
|
||||
@Override
|
||||
public void onUserChanged(int userId) {
|
||||
mBubbles.onUserChanged(userId);
|
||||
}
|
||||
});
|
||||
|
||||
mSysuiProxy = new Bubbles.SysuiProxy() {
|
||||
@Override
|
||||
@Nullable
|
||||
public BubbleEntry getPendingOrActiveEntry(String key) {
|
||||
NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(key);
|
||||
return entry == null ? null : notifToBubbleEntry(entry);
|
||||
}
|
||||
|
||||
@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 result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNotificationShadeExpand() {
|
||||
return mNotificationShadeWindowController.getPanelExpanded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldBubbleUp(String key) {
|
||||
final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
|
||||
key);
|
||||
if (entry != null) {
|
||||
return mNotificationInterruptStateProvider.shouldBubbleUp(entry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotificationInterruption(String key) {
|
||||
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);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyInvalidateNotifications(String reason) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationEntry(String key) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotificationSuppression(String key) {
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnbubbleConversation(String key) {
|
||||
final NotificationEntry entry =
|
||||
mNotificationEntryManager.getPendingOrActiveNotif(key);
|
||||
if (entry != null) {
|
||||
onUserChangedBubble(entry, false /* shouldBubble */);
|
||||
}
|
||||
}
|
||||
};
|
||||
mBubbles.setSysuiProxy(mSysuiProxy);
|
||||
}
|
||||
|
||||
private void setupNEM() {
|
||||
mNotificationEntryManager.addNotificationEntryListener(
|
||||
new NotificationEntryListener() {
|
||||
@Override
|
||||
public void onPendingEntryAdded(NotificationEntry entry) {
|
||||
BubblesManager.this.onEntryAdded(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreEntryUpdated(NotificationEntry entry) {
|
||||
BubblesManager.this.onEntryUpdated(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryRemoved(NotificationEntry entry,
|
||||
@Nullable NotificationVisibility visibility,
|
||||
boolean removedByUser, int reason) {
|
||||
BubblesManager.this.onEntryRemoved(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationRankingUpdated(RankingMap rankingMap) {
|
||||
BubblesManager.this.onRankingUpdate(rankingMap);
|
||||
}
|
||||
});
|
||||
|
||||
// The new pipeline takes care of this as a NotifDismissInterceptor BubbleCoordinator
|
||||
mNotificationEntryManager.addNotificationRemoveInterceptor(
|
||||
(key, entry, dismissReason) -> {
|
||||
final boolean isClearAll = dismissReason == REASON_CANCEL_ALL;
|
||||
final boolean isUserDismiss = dismissReason == REASON_CANCEL
|
||||
|| dismissReason == REASON_CLICK;
|
||||
final boolean isAppCancel = dismissReason == REASON_APP_CANCEL
|
||||
|| dismissReason == REASON_APP_CANCEL_ALL;
|
||||
final boolean isSummaryCancel =
|
||||
dismissReason == REASON_GROUP_SUMMARY_CANCELED;
|
||||
|
||||
// Need to check for !appCancel here because the notification may have
|
||||
// previously been dismissed & entry.isRowDismissed would still be true
|
||||
boolean userRemovedNotif =
|
||||
(entry != null && entry.isRowDismissed() && !isAppCancel)
|
||||
|| isClearAll || isUserDismiss || isSummaryCancel;
|
||||
|
||||
if (userRemovedNotif) {
|
||||
return handleDismissalInterception(entry);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
mNotificationGroupManager.registerGroupChangeListener(
|
||||
new NotificationGroupManagerLegacy.OnGroupChangeListener() {
|
||||
@Override
|
||||
public void onGroupSuppressionChanged(
|
||||
NotificationGroupManagerLegacy.NotificationGroup group,
|
||||
boolean suppressed) {
|
||||
// More notifications could be added causing summary to no longer
|
||||
// be suppressed -- in this case need to remove the key.
|
||||
final String groupKey = group.summary != null
|
||||
? group.summary.getSbn().getGroupKey()
|
||||
: null;
|
||||
if (!suppressed && groupKey != null
|
||||
&& mBubbles.isSummarySuppressed(groupKey)) {
|
||||
mBubbles.removeSuppressedSummary(groupKey);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
addNotifCallback(new NotifCallback() {
|
||||
@Override
|
||||
public void removeNotification(NotificationEntry entry,
|
||||
DismissedByUserStats dismissedByUserStats, int reason) {
|
||||
mNotificationEntryManager.performRemoveNotification(entry.getSbn(),
|
||||
dismissedByUserStats, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateNotifications(String reason) {
|
||||
mNotificationEntryManager.updateNotifications(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeCancelSummary(NotificationEntry entry) {
|
||||
// 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);
|
||||
|
||||
final NotificationEntry summary =
|
||||
mNotificationEntryManager.getActiveNotificationUnfiltered(
|
||||
mBubbles.getSummaryKey(groupKey));
|
||||
if (summary != null) {
|
||||
mNotificationEntryManager.performRemoveNotification(
|
||||
summary.getSbn(),
|
||||
getDismissedByUserStats(summary, false),
|
||||
UNDEFINED_DISMISS_REASON);
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
// For example:
|
||||
// 1. Bubbled notifications (group) is posted to shade and are visible bubbles
|
||||
// 2. User expands bubbles so now their respective notifications in the shade are
|
||||
// hidden, including the group summary
|
||||
// 3. User removes all bubbles
|
||||
// 4. We expect all the removed bubbles AND the summary (note: the summary was
|
||||
// never added to the suppressedSummary list in BubbleData, so we add this check)
|
||||
NotificationEntry summary = mNotificationGroupManager.getLogicalGroupSummary(entry);
|
||||
if (summary != null) {
|
||||
ArrayList<NotificationEntry> summaryChildren =
|
||||
mNotificationGroupManager.getLogicalChildren(summary.getSbn());
|
||||
boolean isSummaryThisNotif = summary.getKey().equals(entry.getKey());
|
||||
if (!isSummaryThisNotif && (summaryChildren == null
|
||||
|| summaryChildren.isEmpty())) {
|
||||
mNotificationEntryManager.performRemoveNotification(
|
||||
summary.getSbn(),
|
||||
getDismissedByUserStats(summary, false),
|
||||
UNDEFINED_DISMISS_REASON);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupNotifPipeline() {
|
||||
mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
|
||||
@Override
|
||||
public void onEntryAdded(NotificationEntry entry) {
|
||||
BubblesManager.this.onEntryAdded(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryUpdated(NotificationEntry entry) {
|
||||
BubblesManager.this.onEntryUpdated(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryRemoved(NotificationEntry entry,
|
||||
@NotifCollection.CancellationReason int reason) {
|
||||
BubblesManager.this.onEntryRemoved(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRankingUpdate(RankingMap rankingMap) {
|
||||
BubblesManager.this.onRankingUpdate(rankingMap);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void onEntryAdded(NotificationEntry entry) {
|
||||
if (mNotificationInterruptStateProvider.shouldBubbleUp(entry)
|
||||
&& entry.isBubble()) {
|
||||
mBubbles.onEntryAdded(notifToBubbleEntry(entry));
|
||||
}
|
||||
}
|
||||
|
||||
void onEntryUpdated(NotificationEntry entry) {
|
||||
mBubbles.onEntryUpdated(notifToBubbleEntry(entry),
|
||||
mNotificationInterruptStateProvider.shouldBubbleUp(entry));
|
||||
}
|
||||
|
||||
void onEntryRemoved(NotificationEntry entry) {
|
||||
mBubbles.onEntryRemoved(notifToBubbleEntry(entry));
|
||||
}
|
||||
|
||||
void onRankingUpdate(RankingMap rankingMap) {
|
||||
mBubbles.onRankingUpdated(rankingMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DismissedByUserStats used by {@link NotificationEntryManager}.
|
||||
* Will not be necessary when using the new notification pipeline's {@link NotifCollection}.
|
||||
* Instead, this is taken care of by {@link BubbleCoordinator}.
|
||||
*/
|
||||
private DismissedByUserStats getDismissedByUserStats(
|
||||
NotificationEntry entry,
|
||||
boolean isVisible) {
|
||||
return new DismissedByUserStats(
|
||||
DISMISSAL_BUBBLE,
|
||||
DISMISS_SENTIMENT_NEUTRAL,
|
||||
NotificationVisibility.obtain(
|
||||
entry.getKey(),
|
||||
entry.getRanking().getRank(),
|
||||
mNotificationEntryManager.getActiveNotificationsCount(),
|
||||
isVisible,
|
||||
NotificationLogger.getNotificationLocation(entry)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scrim drawn behind the bubble stack. This is managed by {@link ScrimController}
|
||||
* since we want the scrim's appearance and behavior to be identical to that of the notification
|
||||
* shade scrim.
|
||||
*/
|
||||
public ScrimView getScrimForBubble() {
|
||||
return mBubbleScrim;
|
||||
}
|
||||
|
||||
/**
|
||||
* We intercept notification entries (including group summaries) dismissed by the user when
|
||||
* there is an active bubble associated with it. We do this so that developers can still
|
||||
* cancel it (and hence the bubbles associated with it).
|
||||
*
|
||||
* @return true if we want to intercept the dismissal of the entry, else false.
|
||||
* @see Bubbles#handleDismissalInterception(BubbleEntry, List, IntConsumer)
|
||||
*/
|
||||
public boolean handleDismissalInterception(NotificationEntry entry) {
|
||||
if (entry == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<NotificationEntry> children = entry.getAttachedNotifChildren();
|
||||
List<BubbleEntry> bubbleChildren = null;
|
||||
if (children != null) {
|
||||
bubbleChildren = new ArrayList<>();
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
bubbleChildren.add(notifToBubbleEntry(children.get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
return mBubbles.handleDismissalInterception(notifToBubbleEntry(entry), bubbleChildren,
|
||||
// TODO : b/171847985 should re-work on notification side to make this more clear.
|
||||
(int i) -> {
|
||||
if (i >= 0) {
|
||||
for (NotifCallback cb : mCallbacks) {
|
||||
cb.removeNotification(children.get(i),
|
||||
getDismissedByUserStats(children.get(i), true),
|
||||
REASON_GROUP_SUMMARY_CANCELED);
|
||||
}
|
||||
} else {
|
||||
mNotificationGroupManager.onEntryRemoved(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the stack expand if needed, then select the specified Bubble as current.
|
||||
* If no bubble exists for this entry, one is created.
|
||||
*
|
||||
* @param entry the notification for the bubble to be selected
|
||||
*/
|
||||
public void expandStackAndSelectBubble(NotificationEntry entry) {
|
||||
mBubbles.expandStackAndSelectBubble(notifToBubbleEntry(entry));
|
||||
}
|
||||
|
||||
/** See {@link NotifCallback}. */
|
||||
public void addNotifCallback(NotifCallback callback) {
|
||||
mCallbacks.add(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a notification is marked Priority, expand the stack if needed,
|
||||
* then (maybe create and) select the given bubble.
|
||||
*
|
||||
* @param entry the notification for the bubble to show
|
||||
*/
|
||||
public void onUserChangedImportance(NotificationEntry entry) {
|
||||
try {
|
||||
int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
|
||||
flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
|
||||
mBarService.onNotificationBubbleChanged(entry.getKey(), true, flags);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
}
|
||||
mShadeController.collapsePanel(true);
|
||||
if (entry.getRow() != null) {
|
||||
entry.getRow().updateBubbleButton();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user has indicated that an active notification should be shown as a bubble.
|
||||
* <p>
|
||||
* This method will collapse the shade, create the bubble without a flyout or dot, and suppress
|
||||
* the notification from appearing in the shade.
|
||||
*
|
||||
* @param entry the notification to change bubble state for.
|
||||
* @param shouldBubble whether the notification should show as a bubble or not.
|
||||
*/
|
||||
public void onUserChangedBubble(@NonNull final NotificationEntry entry, boolean shouldBubble) {
|
||||
NotificationChannel channel = entry.getChannel();
|
||||
final String appPkg = entry.getSbn().getPackageName();
|
||||
final int appUid = entry.getSbn().getUid();
|
||||
if (channel == null || appPkg == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the state in NotificationManagerService
|
||||
try {
|
||||
int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
|
||||
flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
|
||||
mBarService.onNotificationBubbleChanged(entry.getKey(), shouldBubble, flags);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
|
||||
// Change the settings
|
||||
channel = NotificationChannelHelper.createConversationChannelIfNeeded(mContext,
|
||||
mNotificationManager, entry, channel);
|
||||
channel.setAllowBubbles(shouldBubble);
|
||||
try {
|
||||
int currentPref = mNotificationManager.getBubblePreferenceForPackage(appPkg, appUid);
|
||||
if (shouldBubble && currentPref == BUBBLE_PREFERENCE_NONE) {
|
||||
mNotificationManager.setBubblesAllowed(appPkg, appUid, BUBBLE_PREFERENCE_SELECTED);
|
||||
}
|
||||
mNotificationManager.updateNotificationChannelForPackage(appPkg, appUid, channel);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
}
|
||||
|
||||
if (shouldBubble) {
|
||||
mShadeController.collapsePanel(true);
|
||||
if (entry.getRow() != null) {
|
||||
entry.getRow().updateBubbleButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
|
||||
mBubbles.dump(fd, pw, args);
|
||||
}
|
||||
|
||||
static BubbleEntry notifToBubbleEntry(NotificationEntry e) {
|
||||
return new BubbleEntry(e.getSbn(), e.getRanking(), e.isClearable(),
|
||||
e.shouldSuppressNotificationDot(), e.shouldSuppressNotificationList(),
|
||||
e.shouldSuppressPeek());
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the BubbleController wants to interact with the notification pipeline to:
|
||||
* - Remove a previously bubbled notification
|
||||
* - Update the notification shade since bubbled notification should/shouldn't be showing
|
||||
*/
|
||||
public interface NotifCallback {
|
||||
/**
|
||||
* Called when a bubbled notification that was hidden from the shade is now being removed
|
||||
* This can happen when an app cancels a bubbled notification or when the user dismisses a
|
||||
* bubble.
|
||||
*/
|
||||
void removeNotification(@NonNull NotificationEntry entry,
|
||||
@NonNull DismissedByUserStats stats, int reason);
|
||||
|
||||
/**
|
||||
* Called when a bubbled notification has changed whether it should be
|
||||
* filtered from the shade.
|
||||
*/
|
||||
void invalidateNotifications(@NonNull String reason);
|
||||
|
||||
/**
|
||||
* Called on a bubbled entry that has been removed when there are no longer
|
||||
* bubbled entries in its group.
|
||||
*
|
||||
* Checks whether its group has any other (non-bubbled) children. If it doesn't,
|
||||
* removes all remnants of the group's summary from the notification pipeline.
|
||||
* TODO: (b/145659174) Only old pipeline needs this - delete post-migration.
|
||||
*/
|
||||
void maybeCancelSummary(@NonNull NotificationEntry entry);
|
||||
}
|
||||
}
|
||||
@@ -102,10 +102,10 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
private ArgumentCaptor<BubbleData.Update> mUpdateCaptor;
|
||||
|
||||
@Mock
|
||||
private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
|
||||
private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
|
||||
|
||||
@Mock
|
||||
private BubbleController.PendingIntentCanceledListener mPendingIntentCanceledListener;
|
||||
private Bubbles.PendingIntentCanceledListener mPendingIntentCanceledListener;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -171,12 +171,11 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.setListener(mListener);
|
||||
|
||||
// Test
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
|
||||
// Verify
|
||||
verifyUpdateReceived();
|
||||
assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_USER_GESTURE);
|
||||
assertBubbleRemoved(mBubbleA1, Bubbles.DISMISS_USER_GESTURE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -269,7 +268,7 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
|
||||
sendUpdatedEntryAtTime(mEntryC1, 6000);
|
||||
verifyUpdateReceived();
|
||||
assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_AGED);
|
||||
assertBubbleRemoved(mBubbleA1, Bubbles.DISMISS_AGED);
|
||||
assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
|
||||
|
||||
Bubble bubbleA1 = mBubbleData.getOrCreateBubble(mEntryA1, null /* persistedBubble */);
|
||||
@@ -277,7 +276,7 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.notificationEntryUpdated(bubbleA1, false /* suppressFlyout*/,
|
||||
true /* showInShade */);
|
||||
verifyUpdateReceived();
|
||||
assertBubbleRemoved(mBubbleA2, BubbleController.DISMISS_AGED);
|
||||
assertBubbleRemoved(mBubbleA2, Bubbles.DISMISS_AGED);
|
||||
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
|
||||
}
|
||||
|
||||
@@ -294,14 +293,12 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.setListener(mListener);
|
||||
|
||||
mBubbleData.setMaxOverflowBubbles(1);
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verifyUpdateReceived();
|
||||
assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
|
||||
|
||||
// Overflow max of 1 is reached; A1 is oldest, so it gets removed
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verifyUpdateReceived();
|
||||
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
|
||||
}
|
||||
@@ -322,14 +319,12 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.setListener(mListener);
|
||||
|
||||
// Test
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(),
|
||||
BubbleController.DISMISS_NOTIF_CANCEL);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
verifyUpdateReceived();
|
||||
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
|
||||
|
||||
// Test
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(),
|
||||
BubbleController.DISMISS_GROUP_CANCELLED);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_GROUP_CANCELLED);
|
||||
verifyUpdateReceived();
|
||||
assertOverflowChangedTo(ImmutableList.of());
|
||||
}
|
||||
@@ -409,8 +404,7 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.setListener(mListener);
|
||||
|
||||
// Test
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verifyUpdateReceived();
|
||||
// TODO: this should fail if things work as I expect them to?
|
||||
assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1);
|
||||
@@ -430,8 +424,7 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.setListener(mListener);
|
||||
|
||||
// Test
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verifyUpdateReceived();
|
||||
assertOrderNotChanged();
|
||||
}
|
||||
@@ -450,8 +443,7 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.setListener(mListener);
|
||||
|
||||
// Test
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryA2.getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
verifyUpdateReceived();
|
||||
assertSelectionChangedTo(mBubbleB2);
|
||||
}
|
||||
@@ -545,8 +537,7 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.setListener(mListener);
|
||||
|
||||
// Test
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
|
||||
// Verify the selection was cleared.
|
||||
verifyUpdateReceived();
|
||||
@@ -646,8 +637,7 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.setListener(mListener);
|
||||
|
||||
// Test
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryB2.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryB2.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verifyUpdateReceived();
|
||||
assertOrderChangedTo(mBubbleA2, mBubbleB1, mBubbleA1);
|
||||
}
|
||||
@@ -671,13 +661,11 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.setListener(mListener);
|
||||
|
||||
// Test
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA2.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verifyUpdateReceived();
|
||||
assertSelectionChangedTo(mBubbleB1);
|
||||
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryB1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryB1.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verifyUpdateReceived();
|
||||
assertSelectionChangedTo(mBubbleA1);
|
||||
}
|
||||
@@ -791,8 +779,7 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mBubbleData.setListener(mListener);
|
||||
|
||||
// Test
|
||||
mBubbleData.dismissBubbleWithKey(
|
||||
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verifyUpdateReceived();
|
||||
assertExpandedChangedTo(false);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class BubbleTest extends SysuiTestCase {
|
||||
private Bubble mBubble;
|
||||
|
||||
@Mock
|
||||
private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
|
||||
private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.bubbles;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.os.Handler;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.model.SysUiState;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.FeatureFlags;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.NotificationShadeWindowController;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
|
||||
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
|
||||
/**
|
||||
* Testable BubbleController subclass that immediately synchronizes surfaces.
|
||||
*/
|
||||
public class TestableBubbleController extends BubbleController {
|
||||
|
||||
// Let's assume surfaces can be synchronized immediately.
|
||||
TestableBubbleController(Context context,
|
||||
NotificationShadeWindowController notificationShadeWindowController,
|
||||
StatusBarStateController statusBarStateController,
|
||||
ShadeController shadeController,
|
||||
BubbleData data,
|
||||
ConfigurationController configurationController,
|
||||
NotificationInterruptStateProvider interruptionStateProvider,
|
||||
ZenModeController zenModeController,
|
||||
NotificationLockscreenUserManager lockscreenUserManager,
|
||||
NotificationGroupManagerLegacy groupManager,
|
||||
NotificationEntryManager entryManager,
|
||||
NotifPipeline notifPipeline,
|
||||
FeatureFlags featureFlags,
|
||||
DumpManager dumpManager,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
BubbleDataRepository dataRepository,
|
||||
SysUiState sysUiState,
|
||||
INotificationManager notificationManager,
|
||||
IStatusBarService statusBarService,
|
||||
WindowManager windowManager,
|
||||
WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
LauncherApps launcherApps,
|
||||
BubbleLogger bubbleLogger,
|
||||
Handler mainHandler,
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
BubblePositioner positioner) {
|
||||
super(context,
|
||||
notificationShadeWindowController, statusBarStateController, shadeController,
|
||||
data, Runnable::run, configurationController, interruptionStateProvider,
|
||||
zenModeController, lockscreenUserManager, groupManager, entryManager,
|
||||
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
|
||||
dataRepository, sysUiState, notificationManager, statusBarService,
|
||||
windowManager, windowManagerShellWrapper, launcherApps, bubbleLogger,
|
||||
mainHandler, shellTaskOrganizer, positioner);
|
||||
setInflateSynchronously(true);
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ public class NotificationFilterTest extends SysuiTestCase {
|
||||
new NotificationGroupManagerLegacy(
|
||||
mock(StatusBarStateController.class),
|
||||
() -> mock(PeopleNotificationIdentifier.class),
|
||||
Optional.of(() -> mock(Bubbles.class))));
|
||||
Optional.of(mock(Bubbles.class))));
|
||||
mDependency.injectMockDependency(ShadeController.class);
|
||||
mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
|
||||
mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
|
||||
|
||||
@@ -76,12 +76,12 @@ import com.android.settingslib.notification.ConversationIconFactory;
|
||||
import com.android.systemui.Prefs;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.bubbles.BubblesTestActivity;
|
||||
import com.android.systemui.statusbar.SbnBuilder;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
@@ -137,7 +137,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private OnUserInteractionCallback mOnUserInteractionCallback;
|
||||
@Mock
|
||||
private Bubbles mBubbles;
|
||||
private BubblesManager mBubblesManager;
|
||||
@Mock
|
||||
private LauncherApps mLauncherApps;
|
||||
@Mock
|
||||
@@ -255,7 +255,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon);
|
||||
assertEquals(mIconDrawable, view.getDrawable());
|
||||
}
|
||||
@@ -279,7 +279,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
|
||||
assertTrue(textView.getText().toString().contains("App Name"));
|
||||
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
|
||||
@@ -330,7 +330,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
|
||||
assertTrue(textView.getText().toString().contains(group.getName()));
|
||||
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
|
||||
@@ -355,7 +355,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
|
||||
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
|
||||
assertEquals(GONE, textView.getVisibility());
|
||||
@@ -379,7 +379,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
|
||||
assertEquals(GONE, nameView.getVisibility());
|
||||
}
|
||||
@@ -414,7 +414,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
|
||||
assertEquals(VISIBLE, nameView.getVisibility());
|
||||
assertTrue(nameView.getText().toString().contains("Proxied"));
|
||||
@@ -442,7 +442,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
|
||||
settingsButton.performClick();
|
||||
@@ -468,7 +468,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
|
||||
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
|
||||
}
|
||||
@@ -495,7 +495,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
false,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
|
||||
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
|
||||
}
|
||||
@@ -520,7 +520,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
View view = mNotificationInfo.findViewById(R.id.silence);
|
||||
assertThat(view.isSelected()).isTrue();
|
||||
}
|
||||
@@ -548,7 +548,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
View view = mNotificationInfo.findViewById(R.id.default_behavior);
|
||||
assertThat(view.isSelected()).isTrue();
|
||||
assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
|
||||
@@ -579,7 +579,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
View view = mNotificationInfo.findViewById(R.id.default_behavior);
|
||||
assertThat(view.isSelected()).isTrue();
|
||||
assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
|
||||
@@ -609,7 +609,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
View fave = mNotificationInfo.findViewById(R.id.priority);
|
||||
fave.performClick();
|
||||
@@ -653,7 +653,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
|
||||
mTestableLooper.processAllMessages();
|
||||
@@ -696,7 +696,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
View silence = mNotificationInfo.findViewById(R.id.silence);
|
||||
|
||||
@@ -740,7 +740,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
View fave = mNotificationInfo.findViewById(R.id.priority);
|
||||
fave.performClick();
|
||||
@@ -777,7 +777,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
View fave = mNotificationInfo.findViewById(R.id.priority);
|
||||
fave.performClick();
|
||||
@@ -813,7 +813,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
View fave = mNotificationInfo.findViewById(R.id.priority);
|
||||
fave.performClick();
|
||||
@@ -851,7 +851,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
|
||||
mNotificationInfo.findViewById(R.id.done).performClick();
|
||||
@@ -887,7 +887,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
|
||||
mNotificationInfo.findViewById(R.id.done).performClick();
|
||||
@@ -923,7 +923,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
|
||||
mNotificationInfo.findViewById(R.id.done).performClick();
|
||||
@@ -958,7 +958,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
View silence = mNotificationInfo.findViewById(R.id.silence);
|
||||
silence.performClick();
|
||||
@@ -992,7 +992,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage(
|
||||
anyString(), anyInt(), any(), eq(CONVERSATION_ID));
|
||||
@@ -1017,7 +1017,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
mBuilderProvider,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage(
|
||||
anyString(), anyInt(), any(), eq(CONVERSATION_ID));
|
||||
@@ -1052,7 +1052,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
() -> b,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
// WHEN user clicks "priority"
|
||||
mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
|
||||
@@ -1092,7 +1092,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
() -> b,
|
||||
true,
|
||||
mTestHandler,
|
||||
mTestHandler, null, Optional.of(mBubbles));
|
||||
mTestHandler, null, Optional.of(mBubblesManager));
|
||||
|
||||
// WHEN user clicks "priority"
|
||||
mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
|
||||
|
||||
@@ -84,6 +84,7 @@ import com.android.systemui.statusbar.policy.InflatedSmartReplies;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.leak.LeakDetector;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -96,6 +97,7 @@ import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
@@ -243,7 +245,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
|
||||
true,
|
||||
null,
|
||||
mFalsingManager,
|
||||
mPeopleNotificationIdentifier
|
||||
mPeopleNotificationIdentifier,
|
||||
Optional.of(mock(BubblesManager.class))
|
||||
));
|
||||
|
||||
when(mNotificationRowComponentBuilder.activatableNotificationView(any()))
|
||||
|
||||
@@ -67,7 +67,6 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.logging.testing.UiEventLoggerFake;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
import com.android.systemui.settings.UserContextProvider;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
@@ -81,6 +80,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager.O
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
@@ -131,7 +131,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
@Mock private ChannelEditorDialogController mChannelEditorDialogController;
|
||||
@Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
|
||||
@Mock private UserContextProvider mContextTracker;
|
||||
@Mock private Bubbles mBubbles;
|
||||
@Mock private BubblesManager mBubblesManager;
|
||||
@Mock(answer = Answers.RETURNS_SELF)
|
||||
private PriorityOnboardingDialogController.Builder mBuilder;
|
||||
private Provider<PriorityOnboardingDialogController.Builder> mProvider = () -> mBuilder;
|
||||
@@ -156,7 +156,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
() -> mStatusBar, mHandler, mHandler, mAccessibilityManager, mHighPriorityProvider,
|
||||
mINotificationManager, mLauncherApps, mShortcutManager,
|
||||
mChannelEditorDialogController, mContextTracker, mProvider,
|
||||
mAssistantFeedbackController, Optional.of(mBubbles),
|
||||
mAssistantFeedbackController, Optional.of(mBubblesManager),
|
||||
new UiEventLoggerFake(), mOnUserInteractionCallback);
|
||||
mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
|
||||
mCheckSaveListener, mOnSettingsClickListener);
|
||||
|
||||
@@ -70,6 +70,7 @@ import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
|
||||
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
||||
import com.android.systemui.statusbar.policy.InflatedSmartReplies;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
@@ -121,7 +122,7 @@ public class NotificationTestHelper {
|
||||
mGroupMembershipManager = new NotificationGroupManagerLegacy(
|
||||
mStatusBarStateController,
|
||||
() -> mock(PeopleNotificationIdentifier.class),
|
||||
Optional.of(() -> mock(Bubbles.class)));
|
||||
Optional.of((mock(Bubbles.class))));
|
||||
mGroupExpansionManager = mGroupMembershipManager;
|
||||
mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarStateController,
|
||||
mock(KeyguardBypassController.class), mock(NotificationGroupManagerLegacy.class),
|
||||
@@ -430,7 +431,8 @@ public class NotificationTestHelper {
|
||||
mock(FalsingManager.class),
|
||||
mStatusBarStateController,
|
||||
mPeopleNotificationIdentifier,
|
||||
mock(OnUserInteractionCallback.class));
|
||||
mock(OnUserInteractionCallback.class),
|
||||
Optional.of(mock(BubblesManager.class)));
|
||||
|
||||
row.setAboveShelfChangedListener(aboveShelf -> { });
|
||||
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
|
||||
|
||||
@@ -92,7 +92,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
|
||||
mGroupManager = new NotificationGroupManagerLegacy(
|
||||
mock(StatusBarStateController.class),
|
||||
() -> mock(PeopleNotificationIdentifier.class),
|
||||
Optional.of(() -> mock(Bubbles.class)));
|
||||
Optional.of(mock(Bubbles.class)));
|
||||
mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, mGroupManager);
|
||||
mGroupManager.setHeadsUpManager(mHeadsUpManager);
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ public class NotificationGroupManagerLegacyTest extends SysuiTestCase {
|
||||
mGroupManager = new NotificationGroupManagerLegacy(
|
||||
mock(StatusBarStateController.class),
|
||||
() -> mock(PeopleNotificationIdentifier.class),
|
||||
Optional.of(() -> mock(Bubbles.class)));
|
||||
Optional.of(mock(Bubbles.class)));
|
||||
mGroupManager.setHeadsUpManager(mHeadsUpManager);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.systemui.ActivityIntentHelper;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
@@ -77,6 +76,7 @@ import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback
|
||||
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.wmshell.BubblesManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -116,7 +116,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private Handler mHandler;
|
||||
@Mock
|
||||
private Bubbles mBubbles;
|
||||
private BubblesManager mBubblesManager;
|
||||
@Mock
|
||||
private ShadeControllerImpl mShadeController;
|
||||
@Mock
|
||||
@@ -193,7 +193,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
mStatusBarKeyguardViewManager,
|
||||
mock(KeyguardManager.class),
|
||||
mock(IDreamManager.class),
|
||||
Optional.of(mBubbles),
|
||||
Optional.of(mBubblesManager),
|
||||
() -> mAssistManager,
|
||||
mRemoteInputManager,
|
||||
mock(NotificationGroupManagerLegacy.class),
|
||||
@@ -280,7 +280,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
|
||||
|
||||
// Then
|
||||
verify(mBubbles).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry()));
|
||||
verify(mBubblesManager).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry()));
|
||||
|
||||
// This is called regardless, and simply short circuits when there is nothing to do.
|
||||
verify(mShadeController, atLeastOnce()).collapsePanel();
|
||||
@@ -312,7 +312,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
|
||||
|
||||
// Then
|
||||
verify(mBubbles).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry());
|
||||
verify(mBubblesManager).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry()));
|
||||
|
||||
verify(mShadeController, atLeastOnce()).collapsePanel();
|
||||
|
||||
@@ -342,7 +342,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
|
||||
|
||||
// Then
|
||||
verify(mBubbles).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry());
|
||||
verify(mBubblesManager).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry());
|
||||
|
||||
verify(mShadeController, atLeastOnce()).collapsePanel();
|
||||
|
||||
|
||||
@@ -145,6 +145,7 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
import com.android.systemui.volume.VolumeComponent;
|
||||
import com.android.systemui.wmshell.BubblesManager;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -223,6 +224,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
@Mock private UserSwitcherController mUserSwitcherController;
|
||||
@Mock private NetworkController mNetworkController;
|
||||
@Mock private VibratorHelper mVibratorHelper;
|
||||
@Mock private BubblesManager mBubblesManager;
|
||||
@Mock private Bubbles mBubbles;
|
||||
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
|
||||
@Mock private NotificationIconAreaController mNotificationIconAreaController;
|
||||
@@ -377,6 +379,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
wakefulnessLifecycle,
|
||||
mStatusBarStateController,
|
||||
mVibratorHelper,
|
||||
Optional.of(mBubblesManager),
|
||||
Optional.of(mBubbles),
|
||||
mVisualStabilityManager,
|
||||
mDeviceProvisionedController,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.bubbles;
|
||||
package com.android.systemui.wmshell;
|
||||
|
||||
import static android.app.Notification.FLAG_BUBBLE;
|
||||
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
|
||||
@@ -64,6 +64,14 @@ import androidx.test.filters.SmallTest;
|
||||
import com.android.internal.colorextraction.ColorExtractor;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.bubbles.Bubble;
|
||||
import com.android.systemui.bubbles.BubbleData;
|
||||
import com.android.systemui.bubbles.BubbleDataRepository;
|
||||
import com.android.systemui.bubbles.BubbleEntry;
|
||||
import com.android.systemui.bubbles.BubbleLogger;
|
||||
import com.android.systemui.bubbles.BubblePositioner;
|
||||
import com.android.systemui.bubbles.BubbleStackView;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
@@ -112,12 +120,12 @@ import java.util.List;
|
||||
/**
|
||||
* Tests the NotificationEntryManager setup with BubbleController.
|
||||
* The {@link NotifPipeline} setup with BubbleController is tested in
|
||||
* {@link NewNotifPipelineBubbleControllerTest}.
|
||||
* {@link NewNotifPipelineBubblesTest}.
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
public class BubbleControllerTest extends SysuiTestCase {
|
||||
public class BubblesTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private NotificationEntryManager mNotificationEntryManager;
|
||||
@Mock
|
||||
@@ -157,6 +165,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
@Captor
|
||||
private ArgumentCaptor<NotificationRemoveInterceptor> mRemoveInterceptorCaptor;
|
||||
|
||||
private BubblesManager mBubblesManager;
|
||||
private TestableBubbleController mBubbleController;
|
||||
private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
|
||||
private NotificationEntryListener mEntryListener;
|
||||
@@ -167,9 +176,12 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
private ExpandableNotificationRow mRow2;
|
||||
private ExpandableNotificationRow mRow3;
|
||||
private ExpandableNotificationRow mNonBubbleNotifRow;
|
||||
private BubbleEntry mBubbleEntry;
|
||||
private BubbleEntry mBubbleEntry2;
|
||||
private BubbleEntry mBubbleEntry3;
|
||||
|
||||
@Mock
|
||||
private BubbleController.BubbleExpandListener mBubbleExpandListener;
|
||||
private Bubbles.BubbleExpandListener mBubbleExpandListener;
|
||||
@Mock
|
||||
private PendingIntent mDeleteIntent;
|
||||
@Mock
|
||||
@@ -226,6 +238,9 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
|
||||
mRow3 = mNotificationTestHelper.createBubble(mDeleteIntent);
|
||||
mNonBubbleNotifRow = mNotificationTestHelper.createRow();
|
||||
mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow.getEntry());
|
||||
mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2.getEntry());
|
||||
mBubbleEntry3 = BubblesManager.notifToBubbleEntry(mRow3.getEntry());
|
||||
|
||||
// Return non-null notification data from the NEM
|
||||
when(mNotificationEntryManager
|
||||
@@ -258,26 +273,13 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
mock(HeadsUpManager.class),
|
||||
mock(Handler.class)
|
||||
);
|
||||
|
||||
when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
|
||||
mBubbleController = new TestableBubbleController(
|
||||
mContext,
|
||||
mNotificationShadeWindowController,
|
||||
mStatusBarStateController,
|
||||
mShadeController,
|
||||
mBubbleData,
|
||||
mConfigurationController,
|
||||
interruptionStateProvider,
|
||||
mZenModeController,
|
||||
mLockscreenUserManager,
|
||||
mNotificationGroupManager,
|
||||
mNotificationEntryManager,
|
||||
mNotifPipeline,
|
||||
mFeatureFlagsOldPipeline,
|
||||
mDumpManager,
|
||||
mFloatingContentCoordinator,
|
||||
mDataRepository,
|
||||
mSysUiState,
|
||||
mock(INotificationManager.class),
|
||||
mStatusBarService,
|
||||
mWindowManager,
|
||||
mWindowManagerShellWrapper,
|
||||
@@ -288,6 +290,25 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
mPositioner);
|
||||
mBubbleController.setExpandListener(mBubbleExpandListener);
|
||||
|
||||
mBubblesManager = new BubblesManager(
|
||||
mContext,
|
||||
mBubbleController,
|
||||
mNotificationShadeWindowController,
|
||||
mStatusBarStateController,
|
||||
mShadeController,
|
||||
mConfigurationController,
|
||||
mStatusBarService,
|
||||
mock(INotificationManager.class),
|
||||
interruptionStateProvider,
|
||||
mZenModeController,
|
||||
mLockscreenUserManager,
|
||||
mNotificationGroupManager,
|
||||
mNotificationEntryManager,
|
||||
mNotifPipeline,
|
||||
mSysUiState,
|
||||
mFeatureFlagsOldPipeline,
|
||||
mDumpManager);
|
||||
|
||||
// Get a reference to the BubbleController's entry listener
|
||||
verify(mNotificationEntryManager, atLeastOnce())
|
||||
.addNotificationEntryListener(mEntryListenerCaptor.capture());
|
||||
@@ -300,7 +321,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testAddBubble() {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
assertFalse(mSysUiStateBubblesExpanded);
|
||||
@@ -309,20 +330,20 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testHasBubbles() {
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mSysUiStateBubblesExpanded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveBubble() {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mBubbleEntry.getKey()));
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
verify(mNotificationEntryManager).updateNotifications(any());
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
|
||||
|
||||
@@ -331,14 +352,14 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testPromoteBubble_autoExpand() throws Exception {
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
|
||||
.thenReturn(mRow.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
|
||||
.thenReturn(mRow2.getEntry());
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
|
||||
Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
|
||||
assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
|
||||
@@ -361,18 +382,18 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testCancelOverflowBubble() {
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry(), /* suppressFlyout */
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
mBubbleController.updateBubble(mBubbleEntry, /* suppressFlyout */
|
||||
false, /* showInShade */ true);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
|
||||
.thenReturn(mRow.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
|
||||
.thenReturn(mRow2.getEntry());
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
|
||||
eq(mRow.getEntry().getSbn()), any(), anyInt());
|
||||
assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
|
||||
@@ -381,11 +402,11 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testUserChange_doesNotRemoveNotif() {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_CHANGED);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_CHANGED);
|
||||
verify(mNotificationEntryManager, never()).performRemoveNotification(
|
||||
eq(mRow.getEntry().getSbn()), any(), anyInt());
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
@@ -395,15 +416,15 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testDismissStack() {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
verify(mNotificationEntryManager, times(1)).updateNotifications(any());
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
verify(mNotificationEntryManager, times(2)).updateNotifications(any());
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mNotificationEntryManager, times(3)).updateNotifications(any());
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
|
||||
@@ -417,12 +438,12 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Expand the stack
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
@@ -434,7 +455,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Make sure the notif is suppressed
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Collapse
|
||||
mBubbleController.collapseStack();
|
||||
@@ -450,15 +471,15 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow2.getEntry()));
|
||||
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
|
||||
|
||||
// Expand
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
@@ -472,7 +493,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
// Last added is the one that is expanded
|
||||
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow2.getEntry()));
|
||||
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
|
||||
|
||||
// Switch which bubble is expanded
|
||||
mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(
|
||||
@@ -481,7 +502,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// collapse for previous bubble
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
@@ -501,12 +522,12 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
public void testExpansionRemovesShowInShadeAndDot() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
@@ -520,7 +541,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Notif is suppressed after expansion
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
}
|
||||
@@ -529,12 +550,12 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
@@ -548,7 +569,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Notif is suppressed after expansion
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
|
||||
@@ -558,7 +579,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
// Nothing should have changed
|
||||
// Notif is suppressed after expansion
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
}
|
||||
@@ -568,8 +589,8 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
|
||||
// Expand
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
@@ -584,13 +605,13 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow2.getEntry()));
|
||||
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
|
||||
|
||||
// Dismiss currently expanded
|
||||
mBubbleController.removeBubble(
|
||||
mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey(),
|
||||
BubbleController.DISMISS_USER_GESTURE);
|
||||
Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
|
||||
|
||||
// Make sure first bubble is selected
|
||||
@@ -602,7 +623,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
mBubbleController.removeBubble(
|
||||
mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey(),
|
||||
BubbleController.DISMISS_USER_GESTURE);
|
||||
Bubbles.DISMISS_USER_GESTURE);
|
||||
|
||||
// Make sure state changes and collapse happens
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
|
||||
@@ -619,7 +640,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Add the auto expand bubble
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Expansion shouldn't change
|
||||
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
|
||||
@@ -636,7 +657,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Add the auto expand bubble
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Expansion should change
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
|
||||
@@ -653,11 +674,11 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Add the suppress notif bubble
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Notif should be suppressed because we were foreground
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Dot + flyout is hidden because notif is suppressed
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
|
||||
@@ -667,22 +688,22 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testSuppressNotif_onUpdateNotif() {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Should not be suppressed
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Should show dot
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
|
||||
// Update to suppress notif
|
||||
setMetadataFlags(mRow.getEntry(),
|
||||
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Notif should be suppressed
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Dot + flyout is hidden because notif is suppressed
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
|
||||
@@ -695,13 +716,13 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
final String key = mRow.getEntry().getKey();
|
||||
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Simulate notification cancellation.
|
||||
mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_APP_CANCEL);
|
||||
|
||||
mBubbleController.expandStackAndSelectBubble(mRow.getEntry());
|
||||
mBubbleController.expandStackAndSelectBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mSysUiStateBubblesExpanded);
|
||||
}
|
||||
@@ -710,7 +731,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
public void testMarkNewNotificationAsShowInShade() {
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
@@ -726,31 +747,31 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_AGED);
|
||||
verify(mDeleteIntent, never()).send();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mDeleteIntent, times(1)).send();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mDeleteIntent, times(2)).send();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveBubble_noLongerBubbleAfterUpdate()
|
||||
throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
|
||||
@@ -766,7 +787,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testRemoveBubble_succeeds_appCancel() {
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
@@ -780,7 +801,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testRemoveBubble_entryListenerRemove() {
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
@@ -792,11 +813,11 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void removeBubble_clearAllIntercepted() {
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL_ALL);
|
||||
@@ -805,17 +826,17 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
assertTrue(intercepted);
|
||||
// Should update show in shade state
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeBubble_userDismissNotifIntercepted() {
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
|
||||
@@ -824,21 +845,21 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
assertTrue(intercepted);
|
||||
// Should update show in shade state
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeNotif_inOverflow_intercepted() {
|
||||
// Get bubble with notif in shade.
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Dismiss the bubble into overflow.
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
|
||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
@@ -852,14 +873,14 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
public void removeNotif_notInOverflow_notIntercepted() {
|
||||
// Get bubble with notif in shade.
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_NO_LONGER_BUBBLE);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_NO_LONGER_BUBBLE);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
|
||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
@@ -872,11 +893,11 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testOverflowBubble_maxReached_notInShade_bubbleRemoved() {
|
||||
mBubbleController.updateBubble(
|
||||
mRow.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
|
||||
mBubbleEntry, /* suppressFlyout */ false, /* showInShade */ false);
|
||||
mBubbleController.updateBubble(
|
||||
mRow2.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
|
||||
mBubbleEntry2, /* suppressFlyout */ false, /* showInShade */ false);
|
||||
mBubbleController.updateBubble(
|
||||
mRow3.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
|
||||
mBubbleEntry3, /* suppressFlyout */ false, /* showInShade */ false);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
|
||||
.thenReturn(mRow.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
|
||||
@@ -887,12 +908,12 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
mBubbleData.setMaxOverflowBubbles(1);
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertEquals(mBubbleData.getBubbles().size(), 2);
|
||||
assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow2.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mRow2.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
// Overflow max of 1 is reached; mRow is oldest, so it gets removed
|
||||
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
|
||||
eq(mRow.getEntry().getSbn()), any(), eq(REASON_CANCEL));
|
||||
@@ -902,22 +923,22 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testNotifyShadeSuppressionChange_notificationDismiss() {
|
||||
BubbleController.NotificationSuppressionChangedListener listener =
|
||||
mock(BubbleController.NotificationSuppressionChangedListener.class);
|
||||
Bubbles.NotificationSuppressionChangedListener listener =
|
||||
mock(Bubbles.NotificationSuppressionChangedListener.class);
|
||||
mBubbleData.setSuppressionChangedListener(listener);
|
||||
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
|
||||
|
||||
// Should update show in shade state
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Should notify delegate that shade state changed
|
||||
verify(listener).onBubbleNotificationSuppressionChange(
|
||||
@@ -926,21 +947,21 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testNotifyShadeSuppressionChange_bubbleExpanded() {
|
||||
BubbleController.NotificationSuppressionChangedListener listener =
|
||||
mock(BubbleController.NotificationSuppressionChangedListener.class);
|
||||
Bubbles.NotificationSuppressionChangedListener listener =
|
||||
mock(Bubbles.NotificationSuppressionChangedListener.class);
|
||||
mBubbleData.setSuppressionChangedListener(listener);
|
||||
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mBubbleData.setExpanded(true);
|
||||
|
||||
// Once a bubble is expanded the notif is suppressed
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Should notify delegate that shade state changed
|
||||
verify(listener).onBubbleNotificationSuppressionChange(
|
||||
@@ -959,11 +980,11 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
|
||||
|
||||
// WHEN the summary is dismissed
|
||||
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
|
||||
mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
|
||||
|
||||
// THEN the summary and bubbled child are suppressed from the shade
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
groupedBubble.getEntry()));
|
||||
groupedBubble.getEntry().getKey(), groupSummary.getEntry().getSbn().getGroupKey()));
|
||||
assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey()));
|
||||
}
|
||||
|
||||
@@ -979,7 +1000,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
|
||||
|
||||
// GIVEN the summary is dismissed
|
||||
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
|
||||
mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
|
||||
|
||||
// WHEN the summary is cancelled by the app
|
||||
mEntryListener.onEntryRemoved(groupSummary.getEntry(), null, false, REASON_APP_CANCEL);
|
||||
@@ -1002,7 +1023,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
groupSummary.addChildNotification(groupedBubble);
|
||||
|
||||
// WHEN the summary is dismissed
|
||||
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
|
||||
mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
|
||||
|
||||
// THEN only the NON-bubble children are dismissed
|
||||
List<ExpandableNotificationRow> childrenRows = groupSummary.getAttachedChildren();
|
||||
@@ -1017,7 +1038,8 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// THEN the bubble child is suppressed from the shade
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
groupedBubble.getEntry()));
|
||||
groupedBubble.getEntry().getKey(),
|
||||
groupedBubble.getEntry().getSbn().getGroupKey()));
|
||||
|
||||
// THEN the summary is removed from GroupManager
|
||||
verify(mNotificationGroupManager, times(1)).onEntryRemoved(groupSummary.getEntry());
|
||||
@@ -1031,18 +1053,18 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void test_notVisuallyInterruptive_updateOverflowBubble_notAdded() {
|
||||
// Setup
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
// Overflow it
|
||||
mBubbleData.dismissBubbleWithKey(mRow.getEntry().getKey(),
|
||||
BubbleController.DISMISS_USER_GESTURE);
|
||||
Bubbles.DISMISS_USER_GESTURE);
|
||||
assertThat(mBubbleData.hasBubbleInStackWithKey(mRow.getEntry().getKey())).isFalse();
|
||||
assertThat(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey())).isTrue();
|
||||
|
||||
// Test
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertThat(mBubbleData.hasBubbleInStackWithKey(mRow.getEntry().getKey())).isFalse();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.bubbles;
|
||||
package com.android.systemui.wmshell;
|
||||
|
||||
import static android.app.Notification.FLAG_BUBBLE;
|
||||
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
|
||||
@@ -46,7 +46,6 @@ import android.content.res.Configuration;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.service.dreams.IDreamManager;
|
||||
@@ -60,8 +59,14 @@ import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.colorextraction.ColorExtractor;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.systemui.SystemUIFactory;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.bubbles.BubbleData;
|
||||
import com.android.systemui.bubbles.BubbleDataRepository;
|
||||
import com.android.systemui.bubbles.BubbleEntry;
|
||||
import com.android.systemui.bubbles.BubbleLogger;
|
||||
import com.android.systemui.bubbles.BubblePositioner;
|
||||
import com.android.systemui.bubbles.BubbleStackView;
|
||||
import com.android.systemui.bubbles.Bubbles;
|
||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
@@ -69,9 +74,7 @@ import com.android.systemui.model.SysUiState;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.FeatureFlags;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.NotificationShelf;
|
||||
import com.android.systemui.statusbar.RankingBuilder;
|
||||
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
|
||||
import com.android.systemui.statusbar.SysuiStatusBarStateController;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.NotificationFilter;
|
||||
@@ -81,10 +84,8 @@ import com.android.systemui.statusbar.notification.collection.legacy.Notificatio
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
|
||||
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
|
||||
import com.android.systemui.statusbar.phone.DozeParameters;
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
||||
import com.android.systemui.statusbar.phone.LockscreenLockIconController;
|
||||
import com.android.systemui.statusbar.phone.NotificationShadeWindowControllerImpl;
|
||||
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
@@ -92,7 +93,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.InjectionInflationController;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
@@ -111,18 +111,18 @@ import java.util.List;
|
||||
/**
|
||||
* Tests the NotifPipeline setup with BubbleController.
|
||||
* The NotificationEntryManager setup with BubbleController is tested in
|
||||
* {@link BubbleControllerTest}.
|
||||
* {@link BubblesTest}.
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private NotificationEntryManager mNotificationEntryManager;
|
||||
@Mock
|
||||
private NotificationGroupManagerLegacy mNotificationGroupManager;
|
||||
@Mock
|
||||
private BubbleController.NotifCallback mNotifCallback;
|
||||
private BubblesManager.NotifCallback mNotifCallback;
|
||||
@Mock
|
||||
private WindowManager mWindowManager;
|
||||
@Mock
|
||||
@@ -136,8 +136,6 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private ZenModeConfig mZenModeConfig;
|
||||
@Mock
|
||||
private FaceManager mFaceManager;
|
||||
@Mock
|
||||
private NotificationLockscreenUserManager mLockscreenUserManager;
|
||||
@Mock
|
||||
private SysuiStatusBarStateController mStatusBarStateController;
|
||||
@@ -156,6 +154,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
|
||||
private BubblesManager mBubblesManager;
|
||||
private TestableBubbleController mBubbleController;
|
||||
private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
|
||||
private NotifCollectionListener mEntryListener;
|
||||
@@ -163,8 +162,10 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
private ExpandableNotificationRow mRow;
|
||||
private ExpandableNotificationRow mRow2;
|
||||
private ExpandableNotificationRow mNonBubbleNotifRow;
|
||||
private BubbleEntry mBubbleEntry;
|
||||
private BubbleEntry mBubbleEntry2;
|
||||
@Mock
|
||||
private BubbleController.BubbleExpandListener mBubbleExpandListener;
|
||||
private Bubbles.BubbleExpandListener mBubbleExpandListener;
|
||||
@Mock
|
||||
private PendingIntent mDeleteIntent;
|
||||
@Mock
|
||||
@@ -174,16 +175,12 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private ShadeController mShadeController;
|
||||
@Mock
|
||||
private NotificationShelfComponent mNotificationShelfComponent;
|
||||
@Mock
|
||||
private NotifPipeline mNotifPipeline;
|
||||
@Mock
|
||||
private FeatureFlags mFeatureFlagsNewPipeline;
|
||||
@Mock
|
||||
private DumpManager mDumpManager;
|
||||
@Mock
|
||||
private LockscreenLockIconController mLockIconController;
|
||||
@Mock
|
||||
private IStatusBarService mStatusBarService;
|
||||
@Mock
|
||||
private LauncherApps mLauncherApps;
|
||||
@@ -197,7 +194,6 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
private BubbleData mBubbleData;
|
||||
|
||||
private TestableLooper mTestableLooper;
|
||||
private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -205,26 +201,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
mTestableLooper = TestableLooper.get(this);
|
||||
|
||||
mContext.addMockSystemService(FaceManager.class, mFaceManager);
|
||||
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
|
||||
|
||||
mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext,
|
||||
new InjectionInflationController(SystemUIFactory.getInstance().getSysUIComponent()
|
||||
.createViewInstanceCreatorFactory()),
|
||||
new NotificationShelfComponent.Builder() {
|
||||
@Override
|
||||
public NotificationShelfComponent.Builder notificationShelf(
|
||||
NotificationShelf view) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationShelfComponent build() {
|
||||
return mNotificationShelfComponent;
|
||||
}
|
||||
},
|
||||
mLockIconController);
|
||||
|
||||
mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext,
|
||||
mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
|
||||
mConfigurationController, mKeyguardViewMediator, mKeyguardBypassController,
|
||||
@@ -240,6 +218,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
|
||||
mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
|
||||
mNonBubbleNotifRow = mNotificationTestHelper.createRow();
|
||||
mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow.getEntry());
|
||||
mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2.getEntry());
|
||||
|
||||
mZenModeConfig.suppressedVisualEffects = 0;
|
||||
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
|
||||
@@ -265,23 +245,9 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
|
||||
mBubbleController = new TestableBubbleController(
|
||||
mContext,
|
||||
mNotificationShadeWindowController,
|
||||
mStatusBarStateController,
|
||||
mShadeController,
|
||||
mBubbleData,
|
||||
mConfigurationController,
|
||||
interruptionStateProvider,
|
||||
mZenModeController,
|
||||
mLockscreenUserManager,
|
||||
mNotificationGroupManager,
|
||||
mNotificationEntryManager,
|
||||
mNotifPipeline,
|
||||
mFeatureFlagsNewPipeline,
|
||||
mDumpManager,
|
||||
mFloatingContentCoordinator,
|
||||
mDataRepository,
|
||||
mSysUiState,
|
||||
mock(INotificationManager.class),
|
||||
mStatusBarService,
|
||||
mWindowManager,
|
||||
mWindowManagerShellWrapper,
|
||||
@@ -290,9 +256,28 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
mock(Handler.class),
|
||||
mock(ShellTaskOrganizer.class),
|
||||
mPositioner);
|
||||
mBubbleController.addNotifCallback(mNotifCallback);
|
||||
mBubbleController.setExpandListener(mBubbleExpandListener);
|
||||
|
||||
mBubblesManager = new BubblesManager(
|
||||
mContext,
|
||||
mBubbleController,
|
||||
mNotificationShadeWindowController,
|
||||
mStatusBarStateController,
|
||||
mShadeController,
|
||||
mConfigurationController,
|
||||
mStatusBarService,
|
||||
mock(INotificationManager.class),
|
||||
interruptionStateProvider,
|
||||
mZenModeController,
|
||||
mLockscreenUserManager,
|
||||
mNotificationGroupManager,
|
||||
mNotificationEntryManager,
|
||||
mNotifPipeline,
|
||||
mSysUiState,
|
||||
mFeatureFlagsNewPipeline,
|
||||
mDumpManager);
|
||||
mBubblesManager.addNotifCallback(mNotifCallback);
|
||||
|
||||
// Get a reference to the BubbleController's entry listener
|
||||
verify(mNotifPipeline, atLeastOnce())
|
||||
.addCollectionListener(mNotifListenerCaptor.capture());
|
||||
@@ -301,26 +286,26 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testAddBubble() {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasBubbles() {
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveBubble() {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
|
||||
}
|
||||
@@ -328,17 +313,18 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testRemoveBubble_withDismissedNotif_inOverflow() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Make it look like dismissed notif
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
|
||||
|
||||
// Now remove the bubble
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
|
||||
|
||||
// We don't remove the notification since the bubble is still in overflow.
|
||||
@@ -349,19 +335,20 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testRemoveBubble_withDismissedNotif_notInOverflow() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
|
||||
.thenReturn(mRow.getEntry());
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Make it look like dismissed notif
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
|
||||
|
||||
// Now remove the bubble
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
|
||||
|
||||
// Since the notif is dismissed and not in overflow, once the bubble is removed,
|
||||
@@ -373,15 +360,15 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testDismissStack() {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
|
||||
@@ -393,12 +380,12 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Expand the stack
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
@@ -407,7 +394,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
|
||||
// Make sure the notif is suppressed
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Collapse
|
||||
mBubbleController.collapseStack();
|
||||
@@ -421,15 +409,15 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow2.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Expand
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
@@ -440,15 +428,17 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Last added is the one that is expanded
|
||||
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry()));
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
|
||||
|
||||
// Switch which bubble is expanded
|
||||
mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(
|
||||
mRow.getEntry().getKey()));
|
||||
mBubbleData.setExpanded(true);
|
||||
assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// collapse for previous bubble
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
@@ -467,11 +457,12 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
public void testExpansionRemovesShowInShadeAndDot() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
@@ -483,7 +474,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Notif is suppressed after expansion
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
}
|
||||
@@ -492,12 +483,12 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
@@ -509,7 +500,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Notif is suppressed after expansion
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
|
||||
@@ -519,7 +510,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
// Nothing should have changed
|
||||
// Notif is suppressed after expansion
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
}
|
||||
@@ -529,8 +520,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
|
||||
// Expand
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
@@ -543,13 +534,13 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow2.getEntry()));
|
||||
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
|
||||
|
||||
// Dismiss currently expanded
|
||||
mBubbleController.removeBubble(
|
||||
mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey(),
|
||||
BubbleController.DISMISS_USER_GESTURE);
|
||||
Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
|
||||
|
||||
// Make sure first bubble is selected
|
||||
@@ -561,7 +552,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
mBubbleController.removeBubble(
|
||||
mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey(),
|
||||
BubbleController.DISMISS_USER_GESTURE);
|
||||
Bubbles.DISMISS_USER_GESTURE);
|
||||
|
||||
// Make sure state changes and collapse happens
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
|
||||
@@ -576,7 +567,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Add the auto expand bubble
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Expansion shouldn't change
|
||||
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
|
||||
@@ -591,7 +582,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Add the auto expand bubble
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Expansion should change
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
|
||||
@@ -606,11 +597,11 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
// Add the suppress notif bubble
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Notif should be suppressed because we were foreground
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Dot + flyout is hidden because notif is suppressed
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
|
||||
@@ -618,22 +609,22 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testSuppressNotif_onUpdateNotif() {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Should not be suppressed
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Should show dot
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
|
||||
// Update to suppress notif
|
||||
setMetadataFlags(mRow.getEntry(),
|
||||
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Notif should be suppressed
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Dot + flyout is hidden because notif is suppressed
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
|
||||
@@ -643,7 +634,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
public void testMarkNewNotificationAsShowInShade() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
@@ -659,31 +650,31 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_AGED);
|
||||
verify(mDeleteIntent, never()).send();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mDeleteIntent, times(1)).send();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow2.getEntry());
|
||||
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mDeleteIntent, times(2)).send();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveBubble_noLongerBubbleAfterUpdate()
|
||||
throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
|
||||
@@ -699,7 +690,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testRemoveBubble_entryListenerRemove() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
@@ -711,36 +702,36 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void removeBubble_intercepted() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
|
||||
boolean intercepted = mBubblesManager.handleDismissalInterception(mRow.getEntry());
|
||||
|
||||
// Intercept!
|
||||
assertTrue(intercepted);
|
||||
// Should update show in shade state
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeBubble_dismissIntoOverflow_intercepted() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Dismiss the bubble
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||
mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
|
||||
// Dismiss the notification
|
||||
boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
|
||||
boolean intercepted = mBubblesManager.handleDismissalInterception(mRow.getEntry());
|
||||
|
||||
// Intercept dismissal since bubble is going into overflow
|
||||
assertTrue(intercepted);
|
||||
@@ -749,19 +740,18 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void removeBubble_notIntercepted() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mRow.getEntry());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Dismiss the bubble
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
|
||||
mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
|
||||
// Dismiss the notification
|
||||
boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
|
||||
boolean intercepted = mBubblesManager.handleDismissalInterception(mRow.getEntry());
|
||||
|
||||
// Not a bubble anymore so we don't intercept dismissal.
|
||||
assertFalse(intercepted);
|
||||
@@ -769,21 +759,21 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testNotifyShadeSuppressionChange_notificationDismiss() {
|
||||
BubbleController.NotificationSuppressionChangedListener listener =
|
||||
mock(BubbleController.NotificationSuppressionChangedListener.class);
|
||||
Bubbles.NotificationSuppressionChangedListener listener =
|
||||
mock(Bubbles.NotificationSuppressionChangedListener.class);
|
||||
mBubbleData.setSuppressionChangedListener(listener);
|
||||
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mBubbleController.handleDismissalInterception(mRow.getEntry());
|
||||
mBubblesManager.handleDismissalInterception(mRow.getEntry());
|
||||
|
||||
// Should update show in shade state
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Should notify delegate that shade state changed
|
||||
verify(listener).onBubbleNotificationSuppressionChange(
|
||||
@@ -792,21 +782,21 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testNotifyShadeSuppressionChange_bubbleExpanded() {
|
||||
BubbleController.NotificationSuppressionChangedListener listener =
|
||||
mock(BubbleController.NotificationSuppressionChangedListener.class);
|
||||
Bubbles.NotificationSuppressionChangedListener listener =
|
||||
mock(Bubbles.NotificationSuppressionChangedListener.class);
|
||||
mBubbleData.setSuppressionChangedListener(listener);
|
||||
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mBubbleData.setExpanded(true);
|
||||
|
||||
// Once a bubble is expanded the notif is suppressed
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mRow.getEntry()));
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Should notify delegate that shade state changed
|
||||
verify(listener).onBubbleNotificationSuppressionChange(
|
||||
@@ -825,11 +815,12 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
|
||||
|
||||
// WHEN the summary is dismissed
|
||||
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
|
||||
mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
|
||||
|
||||
// THEN the summary and bubbled child are suppressed from the shade
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
groupedBubble.getEntry()));
|
||||
groupedBubble.getEntry().getKey(),
|
||||
groupedBubble.getEntry().getSbn().getGroupKey()));
|
||||
assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey()));
|
||||
}
|
||||
|
||||
@@ -845,7 +836,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
|
||||
|
||||
// GIVEN the summary is dismissed
|
||||
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
|
||||
mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
|
||||
|
||||
// WHEN the summary is cancelled by the app
|
||||
mEntryListener.onEntryRemoved(groupSummary.getEntry(), 0);
|
||||
@@ -868,7 +859,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
groupSummary.addChildNotification(groupedBubble);
|
||||
|
||||
// WHEN the summary is dismissed
|
||||
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
|
||||
mBubblesManager.handleDismissalInterception(groupSummary.getEntry());
|
||||
|
||||
// THEN only the NON-bubble children are dismissed
|
||||
List<ExpandableNotificationRow> childrenRows = groupSummary.getAttachedChildren();
|
||||
@@ -882,11 +873,13 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
// THEN the bubble child still exists as a bubble and is suppressed from the shade
|
||||
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
groupedBubble.getEntry()));
|
||||
groupedBubble.getEntry().getKey(),
|
||||
groupedBubble.getEntry().getSbn().getGroupKey()));
|
||||
|
||||
// THEN the summary is also suppressed from the shade
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
groupSummary.getEntry()));
|
||||
groupSummary.getEntry().getKey(),
|
||||
groupSummary.getEntry().getSbn().getGroupKey()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 android.content.Context;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.os.Handler;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.systemui.bubbles.BubbleController;
|
||||
import com.android.systemui.bubbles.BubbleData;
|
||||
import com.android.systemui.bubbles.BubbleDataRepository;
|
||||
import com.android.systemui.bubbles.BubbleLogger;
|
||||
import com.android.systemui.bubbles.BubblePositioner;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
|
||||
/**
|
||||
* Testable BubbleController subclass that immediately synchronizes surfaces.
|
||||
*/
|
||||
public class TestableBubbleController extends BubbleController {
|
||||
|
||||
// Let's assume surfaces can be synchronized immediately.
|
||||
TestableBubbleController(Context context,
|
||||
BubbleData data,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
BubbleDataRepository dataRepository,
|
||||
IStatusBarService statusBarService,
|
||||
WindowManager windowManager,
|
||||
WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
LauncherApps launcherApps,
|
||||
BubbleLogger bubbleLogger,
|
||||
Handler mainHandler,
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
BubblePositioner positioner) {
|
||||
super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
|
||||
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
|
||||
bubbleLogger, mainHandler, shellTaskOrganizer, positioner);
|
||||
setInflateSynchronously(true);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.bubbles;
|
||||
package com.android.systemui.wmshell;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
Reference in New Issue
Block a user