Add NotifCollection dismiss methods
Now NotifCollection has three methods for sending dismissals to system server: 1. dismissNotification - dismisses a single notification - use case: when user swipes away a single notification - ends up calling IStatusBarService#onNotificationClear to update system server 2. dismissNotifications - dismisses multiple notifications it's passed. - use case: user dismisses all 'gentle/silent' notifications - ends up calling dismissNotification (#1) multiple times 3. dismissAllNotification - dismisses all clearable notifications associated with a given userId - use case: user clicks on "clear all" to clear all their notifications - ends up calling IStatusBarService#onClearAllNotifications to update system server Test: atest NotifCollectionTest Test: atest SystemUITests Change-Id: I1fdf38fd192824b1dfc45dd3a5e1fea0a51e2e75 Fixes: 149241859
This commit is contained in:
@@ -44,12 +44,16 @@ import static java.util.Objects.requireNonNull;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.MainThread;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.Notification;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.NotificationListenerService.Ranking;
|
||||
import android.service.notification.NotificationListenerService.RankingMap;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
@@ -191,59 +195,121 @@ public class NotifCollection implements Dumpable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss a notification on behalf of the user.
|
||||
* Dismisses multiple notifications on behalf of the user.
|
||||
*/
|
||||
public void dismissNotification(NotificationEntry entry, @NonNull DismissedByUserStats stats) {
|
||||
public void dismissNotifications(
|
||||
List<Pair<NotificationEntry, DismissedByUserStats>> entriesToDismiss) {
|
||||
Assert.isMainThread();
|
||||
requireNonNull(stats);
|
||||
checkForReentrantCall();
|
||||
|
||||
if (entry != mNotificationSet.get(entry.getKey())) {
|
||||
throw new IllegalStateException("Invalid entry: " + entry.getKey());
|
||||
}
|
||||
final List<NotificationEntry> entriesToLocallyDismiss = new ArrayList<>();
|
||||
for (int i = 0; i < entriesToDismiss.size(); i++) {
|
||||
NotificationEntry entry = entriesToDismiss.get(i).first;
|
||||
DismissedByUserStats stats = entriesToDismiss.get(i).second;
|
||||
|
||||
if (entry.getDismissState() == DISMISSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateDismissInterceptors(entry);
|
||||
if (isDismissIntercepted(entry)) {
|
||||
mLogger.logNotifDismissedIntercepted(entry.getKey());
|
||||
return;
|
||||
}
|
||||
|
||||
// Optimistically mark the notification as dismissed -- we'll wait for the signal from
|
||||
// system server before removing it from our notification set.
|
||||
entry.setDismissState(DISMISSED);
|
||||
mLogger.logNotifDismissed(entry.getKey());
|
||||
|
||||
List<NotificationEntry> canceledEntries = new ArrayList<>();
|
||||
|
||||
if (isCanceled(entry)) {
|
||||
canceledEntries.add(entry);
|
||||
} else {
|
||||
// Ask system server to remove it for us
|
||||
try {
|
||||
mStatusBarService.onNotificationClear(
|
||||
entry.getSbn().getPackageName(),
|
||||
entry.getSbn().getTag(),
|
||||
entry.getSbn().getId(),
|
||||
entry.getSbn().getUser().getIdentifier(),
|
||||
entry.getSbn().getKey(),
|
||||
stats.dismissalSurface,
|
||||
stats.dismissalSentiment,
|
||||
stats.notificationVisibility);
|
||||
} catch (RemoteException e) {
|
||||
// system process is dead if we're here.
|
||||
requireNonNull(stats);
|
||||
if (entry != mNotificationSet.get(entry.getKey())) {
|
||||
throw new IllegalStateException("Invalid entry: " + entry.getKey());
|
||||
}
|
||||
|
||||
// Also mark any children as dismissed as system server will auto-dismiss them as well
|
||||
if (entry.getSbn().getNotification().isGroupSummary()) {
|
||||
for (NotificationEntry otherEntry : mNotificationSet.values()) {
|
||||
if (shouldAutoDismiss(otherEntry, entry.getSbn().getGroupKey())) {
|
||||
otherEntry.setDismissState(PARENT_DISMISSED);
|
||||
if (isCanceled(otherEntry)) {
|
||||
canceledEntries.add(otherEntry);
|
||||
if (entry.getDismissState() == DISMISSED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
updateDismissInterceptors(entry);
|
||||
if (isDismissIntercepted(entry)) {
|
||||
mLogger.logNotifDismissedIntercepted(entry.getKey());
|
||||
continue;
|
||||
}
|
||||
|
||||
entriesToLocallyDismiss.add(entry);
|
||||
if (!isCanceled(entry)) {
|
||||
// send message to system server if this notification hasn't already been cancelled
|
||||
try {
|
||||
mStatusBarService.onNotificationClear(
|
||||
entry.getSbn().getPackageName(),
|
||||
entry.getSbn().getTag(),
|
||||
entry.getSbn().getId(),
|
||||
entry.getSbn().getUser().getIdentifier(),
|
||||
entry.getSbn().getKey(),
|
||||
stats.dismissalSurface,
|
||||
stats.dismissalSentiment,
|
||||
stats.notificationVisibility);
|
||||
} catch (RemoteException e) {
|
||||
// system process is dead if we're here.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locallyDismissNotifications(entriesToLocallyDismiss);
|
||||
rebuildList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses a single notification on behalf of the user.
|
||||
*/
|
||||
public void dismissNotification(
|
||||
NotificationEntry entry,
|
||||
@NonNull DismissedByUserStats stats) {
|
||||
dismissNotifications(List.of(
|
||||
new Pair<NotificationEntry, DismissedByUserStats>(entry, stats)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses all clearable notifications for a given userid on behalf of the user.
|
||||
*/
|
||||
public void dismissAllNotifications(@UserIdInt int userId) {
|
||||
Assert.isMainThread();
|
||||
checkForReentrantCall();
|
||||
|
||||
try {
|
||||
mStatusBarService.onClearAllNotifications(userId);
|
||||
} catch (RemoteException e) {
|
||||
// system process is dead if we're here.
|
||||
}
|
||||
|
||||
final List<NotificationEntry> entries = new ArrayList(getActiveNotifs());
|
||||
for (int i = entries.size() - 1; i >= 0; i--) {
|
||||
NotificationEntry entry = entries.get(i);
|
||||
if (!shouldDismissOnClearAll(entry, userId)) {
|
||||
// system server won't be removing these notifications, but we still give dismiss
|
||||
// interceptors the chance to filter the notification
|
||||
updateDismissInterceptors(entry);
|
||||
if (isDismissIntercepted(entry)) {
|
||||
mLogger.logNotifClearAllDismissalIntercepted(entry.getKey());
|
||||
}
|
||||
entries.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
locallyDismissNotifications(entries);
|
||||
rebuildList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimistically marks the given notifications as dismissed -- we'll wait for the signal
|
||||
* from system server before removing it from our notification set.
|
||||
*/
|
||||
private void locallyDismissNotifications(List<NotificationEntry> entries) {
|
||||
final List<NotificationEntry> canceledEntries = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
NotificationEntry entry = entries.get(i);
|
||||
|
||||
entry.setDismissState(DISMISSED);
|
||||
mLogger.logNotifDismissed(entry.getKey());
|
||||
|
||||
if (isCanceled(entry)) {
|
||||
canceledEntries.add(entry);
|
||||
} else {
|
||||
// Mark any children as dismissed as system server will auto-dismiss them as well
|
||||
if (entry.getSbn().getNotification().isGroupSummary()) {
|
||||
for (NotificationEntry otherEntry : mNotificationSet.values()) {
|
||||
if (shouldAutoDismissChildren(otherEntry, entry.getSbn().getGroupKey())) {
|
||||
otherEntry.setDismissState(PARENT_DISMISSED);
|
||||
if (isCanceled(otherEntry)) {
|
||||
canceledEntries.add(otherEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,7 +321,6 @@ public class NotifCollection implements Dumpable {
|
||||
for (NotificationEntry canceledEntry : canceledEntries) {
|
||||
tryRemoveNotification(canceledEntry);
|
||||
}
|
||||
rebuildList();
|
||||
}
|
||||
|
||||
private void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
|
||||
@@ -552,7 +617,7 @@ public class NotifCollection implements Dumpable {
|
||||
*
|
||||
* See NotificationManager.cancelGroupChildrenByListLocked() for corresponding code.
|
||||
*/
|
||||
private static boolean shouldAutoDismiss(
|
||||
private static boolean shouldAutoDismissChildren(
|
||||
NotificationEntry entry,
|
||||
String dismissedGroupKey) {
|
||||
return entry.getSbn().getGroupKey().equals(dismissedGroupKey)
|
||||
@@ -562,10 +627,39 @@ public class NotifCollection implements Dumpable {
|
||||
&& entry.getDismissState() != DISMISSED;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user 'clears all notifications' through SystemUI, NotificationManager will not
|
||||
* dismiss unclearable notifications.
|
||||
* @return true if we think NotificationManager will dismiss the entry when asked to
|
||||
* cancel this notification with {@link NotificationListenerService#REASON_CANCEL_ALL}
|
||||
*
|
||||
* See NotificationManager.cancelAllLocked for corresponding code.
|
||||
*/
|
||||
private static boolean shouldDismissOnClearAll(
|
||||
NotificationEntry entry,
|
||||
@UserIdInt int userId) {
|
||||
// TODO: (b/149396544) add FLAG_BUBBLE check here + in NoManService
|
||||
return userIdMatches(entry, userId)
|
||||
&& entry.isClearable()
|
||||
&& entry.getDismissState() != DISMISSED;
|
||||
}
|
||||
|
||||
private static boolean hasFlag(NotificationEntry entry, int flag) {
|
||||
return (entry.getSbn().getNotification().flags & flag) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the userId applies to the notification in question, either because
|
||||
* they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
|
||||
*
|
||||
* See NotificationManager#notificationMatchesUserId
|
||||
*/
|
||||
private static boolean userIdMatches(NotificationEntry entry, int userId) {
|
||||
return userId == UserHandle.USER_ALL
|
||||
|| entry.getSbn().getUser().getIdentifier() == UserHandle.USER_ALL
|
||||
|| entry.getSbn().getUser().getIdentifier() == userId;
|
||||
}
|
||||
|
||||
private void dispatchOnEntryInit(NotificationEntry entry) {
|
||||
mAmDispatchingToOtherCode = true;
|
||||
for (NotifCollectionListener listener : mNotifCollectionListeners) {
|
||||
@@ -613,6 +707,7 @@ public class NotifCollection implements Dumpable {
|
||||
}
|
||||
mAmDispatchingToOtherCode = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull FileDescriptor fd, PrintWriter pw, @NonNull String[] args) {
|
||||
final List<NotificationEntry> entries = new ArrayList<>(getActiveNotifs());
|
||||
|
||||
@@ -44,6 +44,7 @@ public class NotifInflaterImpl implements NotifInflater {
|
||||
private final IStatusBarService mStatusBarService;
|
||||
private final NotifCollection mNotifCollection;
|
||||
private final NotifInflationErrorManager mNotifErrorManager;
|
||||
private final NotifPipeline mNotifPipeline;
|
||||
|
||||
private NotificationRowBinderImpl mNotificationRowBinder;
|
||||
private InflationCallback mExternalInflationCallback;
|
||||
@@ -52,10 +53,12 @@ public class NotifInflaterImpl implements NotifInflater {
|
||||
public NotifInflaterImpl(
|
||||
IStatusBarService statusBarService,
|
||||
NotifCollection notifCollection,
|
||||
NotifInflationErrorManager errorManager) {
|
||||
NotifInflationErrorManager errorManager,
|
||||
NotifPipeline notifPipeline) {
|
||||
mStatusBarService = statusBarService;
|
||||
mNotifCollection = notifCollection;
|
||||
mNotifErrorManager = errorManager;
|
||||
mNotifPipeline = notifPipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,7 +113,7 @@ public class NotifInflaterImpl implements NotifInflater {
|
||||
DISMISS_SENTIMENT_NEUTRAL,
|
||||
NotificationVisibility.obtain(entry.getKey(),
|
||||
entry.getRanking().getRank(),
|
||||
mNotifCollection.getActiveNotifs().size(),
|
||||
mNotifPipeline.getShadeListCount(),
|
||||
true,
|
||||
NotificationLogger.getNotificationLocation(entry))
|
||||
));
|
||||
|
||||
@@ -195,4 +195,27 @@ public class NotifPipeline implements CommonNotifCollection {
|
||||
public List<ListEntry> getShadeList() {
|
||||
return mShadeListBuilder.getShadeList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of notifications currently shown in the shade. This includes all
|
||||
* children and summary notifications. If this method is called during pipeline execution it
|
||||
* will return the number of notifications in its current state, which will likely be only
|
||||
* partially-generated.
|
||||
*/
|
||||
public int getShadeListCount() {
|
||||
final List<ListEntry> entries = getShadeList();
|
||||
int numNotifs = 0;
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
final ListEntry entry = entries.get(i);
|
||||
if (entry instanceof GroupEntry) {
|
||||
final GroupEntry parentEntry = (GroupEntry) entry;
|
||||
numNotifs++; // include the summary in the count
|
||||
numNotifs += parentEntry.getChildren().size();
|
||||
} else {
|
||||
numNotifs++;
|
||||
}
|
||||
}
|
||||
|
||||
return numNotifs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.android.systemui.statusbar.notification.collection.coordinator;
|
||||
|
||||
import static android.service.notification.NotificationStats.DISMISSAL_OTHER;
|
||||
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_UNKNOWN;
|
||||
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
|
||||
|
||||
import com.android.internal.statusbar.NotificationVisibility;
|
||||
import com.android.systemui.bubbles.BubbleController;
|
||||
@@ -153,10 +153,10 @@ public class BubbleCoordinator implements Coordinator {
|
||||
private DismissedByUserStats createDismissedByUserStats(NotificationEntry entry) {
|
||||
return new DismissedByUserStats(
|
||||
DISMISSAL_OTHER,
|
||||
DISMISS_SENTIMENT_UNKNOWN,
|
||||
DISMISS_SENTIMENT_NEUTRAL,
|
||||
NotificationVisibility.obtain(entry.getKey(),
|
||||
entry.getRanking().getRank(),
|
||||
mNotifPipeline.getActiveNotifs().size(),
|
||||
mNotifPipeline.getShadeListCount(),
|
||||
true, // was visible as a bubble
|
||||
NotificationLogger.getNotificationLocation(entry))
|
||||
);
|
||||
|
||||
@@ -77,6 +77,14 @@ class NotifCollectionLogger @Inject constructor(
|
||||
})
|
||||
}
|
||||
|
||||
fun logNotifClearAllDismissalIntercepted(key: String) {
|
||||
buffer.log(TAG, INFO, {
|
||||
str1 = key
|
||||
}, {
|
||||
"CLEAR ALL DISMISSAL INTERCEPTED $str1"
|
||||
})
|
||||
}
|
||||
|
||||
fun logRankingMissing(key: String, rankingMap: RankingMap) {
|
||||
buffer.log(TAG, WARNING, { str1 = key }, { "Ranking update is missing ranking for $str1" })
|
||||
buffer.log(TAG, DEBUG, {}, { "Ranking map contents:" })
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.systemui.statusbar.notification.stack;
|
||||
|
||||
import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
|
||||
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
|
||||
|
||||
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
|
||||
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
|
||||
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
|
||||
@@ -79,6 +82,7 @@ import com.android.internal.graphics.ColorUtils;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.statusbar.NotificationVisibility;
|
||||
import com.android.keyguard.KeyguardSliceView;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.systemui.Dependency;
|
||||
@@ -98,6 +102,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController.StateList
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
|
||||
import com.android.systemui.statusbar.EmptyShadeView;
|
||||
import com.android.systemui.statusbar.FeatureFlags;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||
@@ -114,7 +119,11 @@ import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
|
||||
import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
|
||||
import com.android.systemui.statusbar.notification.VisualStabilityManager;
|
||||
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.notifcollection.DismissedByUserStats;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
|
||||
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
|
||||
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
@@ -484,8 +493,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
private NotificationIconAreaController mIconAreaController;
|
||||
private final NotificationLockscreenUserManager mLockscreenUserManager;
|
||||
private final Rect mTmpRect = new Rect();
|
||||
private final NotificationEntryManager mEntryManager =
|
||||
Dependency.get(NotificationEntryManager.class);
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
private final NotifPipeline mNotifPipeline;
|
||||
private final NotifCollection mNotifCollection;
|
||||
private final NotificationEntryManager mEntryManager;
|
||||
private final IStatusBarService mBarService = IStatusBarService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
|
||||
@VisibleForTesting
|
||||
@@ -529,7 +540,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
ZenModeController zenController,
|
||||
NotificationSectionsManager notificationSectionsManager,
|
||||
ForegroundServiceSectionController fgsSectionController,
|
||||
ForegroundServiceDismissalFeatureController fgsFeatureController
|
||||
ForegroundServiceDismissalFeatureController fgsFeatureController,
|
||||
FeatureFlags featureFlags,
|
||||
NotifPipeline notifPipeline,
|
||||
NotificationEntryManager entryManager,
|
||||
NotifCollection notifCollection
|
||||
) {
|
||||
super(context, attrs, 0, 0);
|
||||
Resources res = getResources();
|
||||
@@ -607,16 +622,26 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
}
|
||||
}, HIGH_PRIORITY, Settings.Secure.NOTIFICATION_DISMISS_RTL);
|
||||
|
||||
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
|
||||
@Override
|
||||
public void onPreEntryUpdated(NotificationEntry entry) {
|
||||
if (entry.rowExists() && !entry.getSbn().isClearable()) {
|
||||
// If the row already exists, the user may have performed a dismiss action on
|
||||
// the notification. Since it's not clearable we should snap it back.
|
||||
snapViewIfNeeded(entry);
|
||||
mFeatureFlags = featureFlags;
|
||||
mNotifPipeline = notifPipeline;
|
||||
mEntryManager = entryManager;
|
||||
mNotifCollection = notifCollection;
|
||||
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||
mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
|
||||
@Override
|
||||
public void onEntryUpdated(NotificationEntry entry) {
|
||||
NotificationStackScrollLayout.this.onEntryUpdated(entry);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
|
||||
@Override
|
||||
public void onPreEntryUpdated(NotificationEntry entry) {
|
||||
NotificationStackScrollLayout.this.onEntryUpdated(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dynamicPrivacyController.addListener(this);
|
||||
mDynamicPrivacyController = dynamicPrivacyController;
|
||||
mStatusbarStateController = statusBarStateController;
|
||||
@@ -708,7 +733,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
||||
public void updateFooter() {
|
||||
boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL);
|
||||
boolean showFooterView = (showDismissView || mEntryManager.hasActiveNotifications())
|
||||
boolean showFooterView = (showDismissView || hasActiveNotifications())
|
||||
&& mStatusBarState != StatusBarState.KEYGUARD
|
||||
&& !mRemoteInputManager.getController().isRemoteInputActive();
|
||||
|
||||
@@ -5537,32 +5562,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
return;
|
||||
}
|
||||
|
||||
performDismissAllAnimations(viewsToHide, closeShade, () -> {
|
||||
for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
|
||||
if (canChildBeDismissed(rowToRemove)) {
|
||||
if (selection == ROWS_ALL) {
|
||||
// TODO: This is a listener method; we shouldn't be calling it. Can we just
|
||||
// call performRemoveNotification as below?
|
||||
mEntryManager.removeNotification(
|
||||
rowToRemove.getEntry().getKey(),
|
||||
null /* ranking */,
|
||||
NotificationListenerService.REASON_CANCEL_ALL);
|
||||
} else {
|
||||
mEntryManager.performRemoveNotification(
|
||||
rowToRemove.getEntry().getSbn(),
|
||||
NotificationListenerService.REASON_CANCEL_ALL);
|
||||
}
|
||||
} else {
|
||||
rowToRemove.resetTranslation();
|
||||
}
|
||||
}
|
||||
if (selection == ROWS_ALL) {
|
||||
try {
|
||||
mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
});
|
||||
performDismissAllAnimations(
|
||||
viewsToHide,
|
||||
closeShade,
|
||||
() -> onDismissAllAnimationsEnd(viewsToRemove, selection));
|
||||
}
|
||||
|
||||
private boolean includeChildInDismissAll(
|
||||
@@ -6407,6 +6410,83 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------- NotificationEntryManager/NotifPipeline methods ------------------------
|
||||
|
||||
private void onEntryUpdated(NotificationEntry entry) {
|
||||
// If the row already exists, the user may have performed a dismiss action on the
|
||||
// notification. Since it's not clearable we should snap it back.
|
||||
if (entry.rowExists() && !entry.getSbn().isClearable()) {
|
||||
snapViewIfNeeded(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasActiveNotifications() {
|
||||
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||
return mNotifPipeline.getShadeList().isEmpty();
|
||||
} else {
|
||||
return mEntryManager.hasActiveNotifications();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the animations for a "clear all notifications" action has ended.
|
||||
*/
|
||||
private void onDismissAllAnimationsEnd(
|
||||
List<ExpandableNotificationRow> viewsToRemove,
|
||||
@SelectedRows int selectedRows) {
|
||||
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||
if (selectedRows == ROWS_ALL) {
|
||||
mNotifCollection.dismissAllNotifications(mLockscreenUserManager.getCurrentUserId());
|
||||
} else {
|
||||
final List<Pair<NotificationEntry, DismissedByUserStats>>
|
||||
entriesWithRowsDismissedFromShade = new ArrayList<>();
|
||||
final List<DismissedByUserStats> dismissalUserStats = new ArrayList<>();
|
||||
final int numVisibleEntries = mNotifPipeline.getShadeListCount();
|
||||
for (int i = 0; i < viewsToRemove.size(); i++) {
|
||||
final NotificationEntry entry = viewsToRemove.get(i).getEntry();
|
||||
final DismissedByUserStats stats =
|
||||
new DismissedByUserStats(
|
||||
DISMISSAL_SHADE,
|
||||
DISMISS_SENTIMENT_NEUTRAL,
|
||||
NotificationVisibility.obtain(
|
||||
entry.getKey(),
|
||||
entry.getRanking().getRank(),
|
||||
numVisibleEntries,
|
||||
true,
|
||||
NotificationLogger.getNotificationLocation(entry)));
|
||||
entriesWithRowsDismissedFromShade.add(
|
||||
new Pair<NotificationEntry, DismissedByUserStats>(entry, stats));
|
||||
}
|
||||
mNotifCollection.dismissNotifications(entriesWithRowsDismissedFromShade);
|
||||
}
|
||||
} else {
|
||||
for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
|
||||
if (canChildBeDismissed(rowToRemove)) {
|
||||
if (selectedRows == ROWS_ALL) {
|
||||
// TODO: This is a listener method; we shouldn't be calling it. Can we just
|
||||
// call performRemoveNotification as below?
|
||||
mEntryManager.removeNotification(
|
||||
rowToRemove.getEntry().getKey(),
|
||||
null /* ranking */,
|
||||
NotificationListenerService.REASON_CANCEL_ALL);
|
||||
} else {
|
||||
mEntryManager.performRemoveNotification(
|
||||
rowToRemove.getEntry().getSbn(),
|
||||
NotificationListenerService.REASON_CANCEL_ALL);
|
||||
}
|
||||
} else {
|
||||
rowToRemove.resetTranslation();
|
||||
}
|
||||
}
|
||||
if (selectedRows == ROWS_ALL) {
|
||||
try {
|
||||
mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
|
||||
|
||||
@ShadeViewRefactor(RefactorComponent.INPUT)
|
||||
@@ -6415,8 +6495,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
|
||||
/* Only ever called as a consequence of a lockscreen expansion gesture. */
|
||||
@Override
|
||||
public boolean onDraggedDown(View startingChild, int dragLengthY) {
|
||||
if (mStatusBarState == StatusBarState.KEYGUARD
|
||||
&& mEntryManager.hasActiveNotifications()) {
|
||||
if (mStatusBarState == StatusBarState.KEYGUARD && hasActiveNotifications()) {
|
||||
mLockscreenGestureLogger.write(
|
||||
MetricsEvent.ACTION_LS_SHADE,
|
||||
(int) (dragLengthY / mDisplayMetrics.density),
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.systemui.statusbar.phone;
|
||||
|
||||
import static android.service.notification.NotificationListenerService.REASON_CLICK;
|
||||
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
|
||||
|
||||
import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions;
|
||||
|
||||
@@ -35,6 +36,7 @@ import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.service.dreams.IDreamManager;
|
||||
import android.service.notification.NotificationStats;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.text.TextUtils;
|
||||
import android.util.EventLog;
|
||||
@@ -56,6 +58,7 @@ import com.android.systemui.dagger.qualifiers.UiBackground;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.FeatureFlags;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.NotificationPresenter;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||
@@ -66,7 +69,11 @@ import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryListener;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
|
||||
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.notifcollection.DismissedByUserStats;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
|
||||
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpUtil;
|
||||
@@ -97,6 +104,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
private final ActivityStarter mActivityStarter;
|
||||
private final NotificationEntryManager mEntryManager;
|
||||
private final NotifPipeline mNotifPipeline;
|
||||
private final NotifCollection mNotifCollection;
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
private final StatusBarStateController mStatusBarStateController;
|
||||
private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
|
||||
private final MetricsLogger mMetricsLogger;
|
||||
@@ -135,7 +145,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
|
||||
MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils,
|
||||
Handler mainThreadHandler, Handler backgroundHandler, Executor uiBgExecutor,
|
||||
ActivityIntentHelper activityIntentHelper, BubbleController bubbleController) {
|
||||
ActivityIntentHelper activityIntentHelper, BubbleController bubbleController,
|
||||
FeatureFlags featureFlags, NotifPipeline notifPipeline,
|
||||
NotifCollection notifCollection) {
|
||||
mContext = context;
|
||||
mNotificationPanel = panel;
|
||||
mPresenter = presenter;
|
||||
@@ -162,12 +174,25 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
mLockPatternUtils = lockPatternUtils;
|
||||
mBackgroundHandler = backgroundHandler;
|
||||
mUiBgExecutor = uiBgExecutor;
|
||||
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
|
||||
@Override
|
||||
public void onPendingEntryAdded(NotificationEntry entry) {
|
||||
handleFullScreenIntent(entry);
|
||||
}
|
||||
});
|
||||
mFeatureFlags = featureFlags;
|
||||
mNotifPipeline = notifPipeline;
|
||||
mNotifCollection = notifCollection;
|
||||
if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
|
||||
@Override
|
||||
public void onPendingEntryAdded(NotificationEntry entry) {
|
||||
handleFullScreenIntent(entry);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
|
||||
@Override
|
||||
public void onEntryAdded(NotificationEntry entry) {
|
||||
handleFullScreenIntent(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mStatusBarRemoteInputCallback = remoteInputCallback;
|
||||
mMainThreadHandler = mainThreadHandler;
|
||||
mActivityIntentHelper = activityIntentHelper;
|
||||
@@ -246,15 +271,14 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
mHeadsUpManager.removeNotification(sbn.getKey(),
|
||||
true /* releaseImmediately */);
|
||||
}
|
||||
StatusBarNotification parentToCancel = null;
|
||||
NotificationEntry parentToCancel = null;
|
||||
if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
|
||||
StatusBarNotification summarySbn =
|
||||
mGroupManager.getLogicalGroupSummary(sbn).getSbn();
|
||||
if (shouldAutoCancel(summarySbn)) {
|
||||
NotificationEntry summarySbn = mGroupManager.getLogicalGroupSummary(sbn);
|
||||
if (shouldAutoCancel(summarySbn.getSbn())) {
|
||||
parentToCancel = summarySbn;
|
||||
}
|
||||
}
|
||||
final StatusBarNotification parentToCancelFinal = parentToCancel;
|
||||
final NotificationEntry parentToCancelFinal = parentToCancel;
|
||||
final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
|
||||
sbn, row, controller, intent,
|
||||
isActivityIntent, wasOccluded, parentToCancelFinal);
|
||||
@@ -279,7 +303,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
PendingIntent intent,
|
||||
boolean isActivityIntent,
|
||||
boolean wasOccluded,
|
||||
StatusBarNotification parentToCancelFinal) {
|
||||
NotificationEntry parentToCancelFinal) {
|
||||
String notificationKey = sbn.getKey();
|
||||
try {
|
||||
// The intent we are sending is for the application, which
|
||||
@@ -330,7 +354,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
collapseOnMainThread();
|
||||
}
|
||||
|
||||
final int count = mEntryManager.getActiveNotificationsCount();
|
||||
final int count = getVisibleNotificationsCount();
|
||||
final int rank = entry.getRanking().getRank();
|
||||
NotificationVisibility.NotificationLocation location =
|
||||
NotificationLogger.getNotificationLocation(entry);
|
||||
@@ -349,7 +373,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
|| mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
|
||||
notificationKey)) {
|
||||
// Automatically remove all notifications that we may have kept around longer
|
||||
removeNotification(sbn);
|
||||
removeNotification(row.getEntry());
|
||||
}
|
||||
}
|
||||
mIsCollapsingToShowActivityOverLockscreen = false;
|
||||
@@ -482,11 +506,10 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
return entry.shouldSuppressFullScreenIntent();
|
||||
}
|
||||
|
||||
private void removeNotification(StatusBarNotification notification) {
|
||||
private void removeNotification(NotificationEntry entry) {
|
||||
// We have to post it to the UI thread for synchronization
|
||||
mMainThreadHandler.post(() -> {
|
||||
Runnable removeRunnable =
|
||||
() -> mEntryManager.performRemoveNotification(notification, REASON_CLICK);
|
||||
Runnable removeRunnable = createRemoveRunnable(entry);
|
||||
if (mPresenter.isCollapsing()) {
|
||||
// To avoid lags we're only performing the remove
|
||||
// after the shade was collapsed
|
||||
@@ -497,6 +520,53 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
});
|
||||
}
|
||||
|
||||
// --------------------- NotificationEntryManager/NotifPipeline methods ------------------------
|
||||
|
||||
private int getVisibleNotificationsCount() {
|
||||
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||
return mNotifPipeline.getShadeListCount();
|
||||
} else {
|
||||
return mEntryManager.getActiveNotificationsCount();
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable createRemoveRunnable(NotificationEntry entry) {
|
||||
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// see NotificationLogger#logNotificationClear
|
||||
int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
|
||||
if (mHeadsUpManager.isAlerting(entry.getKey())) {
|
||||
dismissalSurface = NotificationStats.DISMISSAL_PEEK;
|
||||
} else if (mNotificationPanel.hasPulsingNotifications()) {
|
||||
dismissalSurface = NotificationStats.DISMISSAL_AOD;
|
||||
}
|
||||
|
||||
mNotifCollection.dismissNotification(
|
||||
entry,
|
||||
new DismissedByUserStats(
|
||||
dismissalSurface,
|
||||
DISMISS_SENTIMENT_NEUTRAL,
|
||||
NotificationVisibility.obtain(
|
||||
entry.getKey(),
|
||||
entry.getRanking().getRank(),
|
||||
mNotifPipeline.getShadeListCount(),
|
||||
true,
|
||||
NotificationLogger.getNotificationLocation(entry))
|
||||
));
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mEntryManager.performRemoveNotification(entry.getSbn(), REASON_CLICK);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public builder for {@link StatusBarNotificationActivityStarter}.
|
||||
*/
|
||||
@@ -506,6 +576,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
private final CommandQueue mCommandQueue;
|
||||
private final Lazy<AssistManager> mAssistManagerLazy;
|
||||
private final NotificationEntryManager mEntryManager;
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
private final NotifPipeline mNotifPipeline;
|
||||
private final NotifCollection mNotifCollection;
|
||||
private final HeadsUpManagerPhone mHeadsUpManager;
|
||||
private final ActivityStarter mActivityStarter;
|
||||
private final IStatusBarService mStatusBarService;
|
||||
@@ -557,7 +630,10 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
@UiBackground Executor uiBgExecutor,
|
||||
ActivityIntentHelper activityIntentHelper,
|
||||
BubbleController bubbleController,
|
||||
ShadeController shadeController) {
|
||||
ShadeController shadeController,
|
||||
FeatureFlags featureFlags,
|
||||
NotifPipeline notifPipeline,
|
||||
NotifCollection notifCollection) {
|
||||
mContext = context;
|
||||
mCommandQueue = commandQueue;
|
||||
mAssistManagerLazy = assistManagerLazy;
|
||||
@@ -583,6 +659,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
mActivityIntentHelper = activityIntentHelper;
|
||||
mBubbleController = bubbleController;
|
||||
mShadeController = shadeController;
|
||||
mFeatureFlags = featureFlags;
|
||||
mNotifPipeline = notifPipeline;
|
||||
mNotifCollection = notifCollection;
|
||||
}
|
||||
|
||||
/** Sets the status bar to use as {@link StatusBar}. */
|
||||
@@ -608,8 +687,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public StatusBarNotificationActivityStarter build() {
|
||||
return new StatusBarNotificationActivityStarter(mContext,
|
||||
mCommandQueue, mAssistManagerLazy,
|
||||
@@ -638,7 +715,10 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
mBackgroundHandler,
|
||||
mUiBgExecutor,
|
||||
mActivityIntentHelper,
|
||||
mBubbleController);
|
||||
mBubbleController,
|
||||
mFeatureFlags,
|
||||
mNotifPipeline,
|
||||
mNotifCollection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.statusbar.notification.collection;
|
||||
|
||||
import static android.app.Notification.FLAG_NO_CLEAR;
|
||||
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
|
||||
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
|
||||
import static android.service.notification.NotificationListenerService.REASON_CLICK;
|
||||
@@ -33,8 +34,8 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyObject;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -50,12 +51,12 @@ import android.app.Notification;
|
||||
import android.os.RemoteException;
|
||||
import android.service.notification.NotificationListenerService.Ranking;
|
||||
import android.service.notification.NotificationListenerService.RankingMap;
|
||||
import android.service.notification.NotificationStats;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
@@ -104,7 +105,6 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
@Spy private RecordingCollectionListener mCollectionListener;
|
||||
@Mock private CollectionReadyForBuildListener mBuildListener;
|
||||
@Mock private FeatureFlags mFeatureFlags;
|
||||
@Mock private DismissedByUserStats mDismissedByUserStats;
|
||||
|
||||
@Spy private RecordingLifetimeExtender mExtender1 = new RecordingLifetimeExtender("Extender1");
|
||||
@Spy private RecordingLifetimeExtender mExtender2 = new RecordingLifetimeExtender("Extender2");
|
||||
@@ -424,13 +424,16 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
public void testDismissingLifetimeExtendedSummaryDoesNotDismissChildren() {
|
||||
// GIVEN A notif group with one summary and two children
|
||||
mCollection.addNotificationLifetimeExtender(mExtender1);
|
||||
NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 1, "myTag")
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setGroupSummary(mContext, true));
|
||||
NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 2, "myTag")
|
||||
.setGroup(mContext, GROUP_1));
|
||||
NotifEvent notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3, "myTag")
|
||||
.setGroup(mContext, GROUP_1));
|
||||
CollectionEvent notif1 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 1, "myTag")
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setGroupSummary(mContext, true));
|
||||
CollectionEvent notif2 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 2, "myTag")
|
||||
.setGroup(mContext, GROUP_1));
|
||||
CollectionEvent notif3 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 3, "myTag")
|
||||
.setGroup(mContext, GROUP_1));
|
||||
|
||||
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
|
||||
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
|
||||
@@ -456,7 +459,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissInterceptorsAreCalled() throws RemoteException {
|
||||
public void testDismissNotificationCallsDismissInterceptors() throws RemoteException {
|
||||
// GIVEN a collection with notifications with multiple dismiss interceptors
|
||||
mInterceptor1.shouldInterceptDismissal = true;
|
||||
mInterceptor2.shouldInterceptDismissal = true;
|
||||
@@ -469,10 +472,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
NotificationEntry entry = mCollectionListener.getEntry(notif.key);
|
||||
|
||||
// WHEN a notification is manually dismissed
|
||||
DismissedByUserStats stats = new DismissedByUserStats(
|
||||
NotificationStats.DISMISSAL_SHADE,
|
||||
NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
|
||||
NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
|
||||
DismissedByUserStats stats = defaultStats(entry);
|
||||
mCollection.dismissNotification(entry, stats);
|
||||
|
||||
// THEN all interceptors get checked
|
||||
@@ -506,10 +506,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
NotificationEntry entry = mCollectionListener.getEntry(notif.key);
|
||||
|
||||
// WHEN a notification is manually dismissed and intercepted
|
||||
DismissedByUserStats stats = new DismissedByUserStats(
|
||||
NotificationStats.DISMISSAL_SHADE,
|
||||
NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
|
||||
NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
|
||||
DismissedByUserStats stats = defaultStats(entry);
|
||||
mCollection.dismissNotification(entry, stats);
|
||||
assertEquals(List.of(mInterceptor1, mInterceptor2), entry.mDismissInterceptors);
|
||||
clearInvocations(mInterceptor1, mInterceptor2);
|
||||
@@ -531,7 +528,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
eq(notif.sbn.getKey()),
|
||||
anyInt(),
|
||||
anyInt(),
|
||||
anyObject());
|
||||
eq(stats.notificationVisibility));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -544,19 +541,16 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
NotificationEntry entry = mCollectionListener.getEntry(notif.key);
|
||||
|
||||
// GIVEN a notification is manually dismissed
|
||||
DismissedByUserStats stats = new DismissedByUserStats(
|
||||
NotificationStats.DISMISSAL_SHADE,
|
||||
NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
|
||||
NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
|
||||
DismissedByUserStats stats = defaultStats(entry);
|
||||
mCollection.dismissNotification(entry, stats);
|
||||
|
||||
// WHEN all interceptors end their interception dismissal
|
||||
mInterceptor1.shouldInterceptDismissal = false;
|
||||
mInterceptor1.onEndInterceptionCallback.onEndDismissInterception(mInterceptor1, entry,
|
||||
mDismissedByUserStats);
|
||||
stats);
|
||||
|
||||
// THEN we send the dismissal to system server
|
||||
verify(mStatusBarService, times(1)).onNotificationClear(
|
||||
verify(mStatusBarService).onNotificationClear(
|
||||
eq(notif.sbn.getPackageName()),
|
||||
eq(notif.sbn.getTag()),
|
||||
eq(47),
|
||||
@@ -564,7 +558,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
eq(notif.sbn.getKey()),
|
||||
anyInt(),
|
||||
anyInt(),
|
||||
anyObject());
|
||||
eq(stats.notificationVisibility));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -581,16 +575,12 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
NotificationEntry entry = mCollectionListener.getEntry(notif.key);
|
||||
|
||||
// GIVEN a notification is manually dismissed
|
||||
DismissedByUserStats stats = new DismissedByUserStats(
|
||||
NotificationStats.DISMISSAL_SHADE,
|
||||
NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
|
||||
NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
|
||||
mCollection.dismissNotification(entry, stats);
|
||||
mCollection.dismissNotification(entry, defaultStats(entry));
|
||||
|
||||
// WHEN an interceptor ends its interception
|
||||
mInterceptor1.shouldInterceptDismissal = false;
|
||||
mInterceptor1.onEndInterceptionCallback.onEndDismissInterception(mInterceptor1, entry,
|
||||
mDismissedByUserStats);
|
||||
defaultStats(entry));
|
||||
|
||||
// THEN all interceptors get checked
|
||||
verify(mInterceptor1).shouldInterceptDismissal(entry);
|
||||
@@ -613,7 +603,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
|
||||
// WHEN we try to end the dismissal of an interceptor that didn't intercept the notif
|
||||
mInterceptor1.onEndInterceptionCallback.onEndDismissInterception(mInterceptor1, entry,
|
||||
mDismissedByUserStats);
|
||||
defaultStats(entry));
|
||||
|
||||
// THEN an exception is thrown
|
||||
}
|
||||
@@ -636,11 +626,11 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testGroupChildrenAreDismissedLocallyWhenSummaryIsDismissed() {
|
||||
// GIVEN a collection with two grouped notifs in it
|
||||
NotifEvent notif0 = mNoMan.postNotif(
|
||||
CollectionEvent notif0 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 0)
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setGroupSummary(mContext, true));
|
||||
NotifEvent notif1 = mNoMan.postNotif(
|
||||
CollectionEvent notif1 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 1)
|
||||
.setGroup(mContext, GROUP_1));
|
||||
NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key);
|
||||
@@ -657,11 +647,11 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testUpdatingDismissedSummaryBringsChildrenBack() {
|
||||
// GIVEN a collection with two grouped notifs in it
|
||||
NotifEvent notif0 = mNoMan.postNotif(
|
||||
CollectionEvent notif0 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 0)
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setGroupSummary(mContext, true));
|
||||
NotifEvent notif1 = mNoMan.postNotif(
|
||||
CollectionEvent notif1 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 1)
|
||||
.setGroup(mContext, GROUP_1));
|
||||
NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key);
|
||||
@@ -680,14 +670,14 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testDismissedChildrenAreNotResetByParentUpdate() {
|
||||
// GIVEN a collection with three grouped notifs in it
|
||||
NotifEvent notif0 = mNoMan.postNotif(
|
||||
CollectionEvent notif0 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 0)
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setGroupSummary(mContext, true));
|
||||
NotifEvent notif1 = mNoMan.postNotif(
|
||||
CollectionEvent notif1 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 1)
|
||||
.setGroup(mContext, GROUP_1));
|
||||
NotifEvent notif2 = mNoMan.postNotif(
|
||||
CollectionEvent notif2 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 2)
|
||||
.setGroup(mContext, GROUP_1));
|
||||
NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key);
|
||||
@@ -709,11 +699,11 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testUpdatingGroupKeyOfDismissedSummaryBringsChildrenBack() {
|
||||
// GIVEN a collection with two grouped notifs in it
|
||||
NotifEvent notif0 = mNoMan.postNotif(
|
||||
CollectionEvent notif0 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 0)
|
||||
.setOverrideGroupKey(GROUP_1)
|
||||
.setGroupSummary(mContext, true));
|
||||
NotifEvent notif1 = mNoMan.postNotif(
|
||||
CollectionEvent notif1 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 1)
|
||||
.setOverrideGroupKey(GROUP_1));
|
||||
NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key);
|
||||
@@ -1055,6 +1045,213 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
assertEquals(REASON_NOT_CANCELED, entry0.mCancellationReason);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissNotificationsRebuildsOnce() {
|
||||
// GIVEN a collection with a couple notifications
|
||||
NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
|
||||
NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
|
||||
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
|
||||
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
|
||||
clearInvocations(mBuildListener);
|
||||
|
||||
// WHEN both notifications are manually dismissed together
|
||||
mCollection.dismissNotifications(
|
||||
List.of(new Pair(entry1, defaultStats(entry1)),
|
||||
new Pair(entry2, defaultStats(entry2))));
|
||||
|
||||
// THEN build list is only called one time
|
||||
verify(mBuildListener).onBuildList(any(Collection.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissNotificationsSentToSystemServer() throws RemoteException {
|
||||
// GIVEN a collection with a couple notifications
|
||||
NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
|
||||
NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
|
||||
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
|
||||
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
|
||||
|
||||
// WHEN both notifications are manually dismissed together
|
||||
DismissedByUserStats stats1 = defaultStats(entry1);
|
||||
DismissedByUserStats stats2 = defaultStats(entry2);
|
||||
mCollection.dismissNotifications(
|
||||
List.of(new Pair(entry1, defaultStats(entry1)),
|
||||
new Pair(entry2, defaultStats(entry2))));
|
||||
|
||||
// THEN we send the dismissals to system server
|
||||
verify(mStatusBarService).onNotificationClear(
|
||||
notif1.sbn.getPackageName(),
|
||||
notif1.sbn.getTag(),
|
||||
47,
|
||||
notif1.sbn.getUser().getIdentifier(),
|
||||
notif1.sbn.getKey(),
|
||||
stats1.dismissalSurface,
|
||||
stats1.dismissalSentiment,
|
||||
stats1.notificationVisibility);
|
||||
|
||||
verify(mStatusBarService).onNotificationClear(
|
||||
notif2.sbn.getPackageName(),
|
||||
notif2.sbn.getTag(),
|
||||
88,
|
||||
notif2.sbn.getUser().getIdentifier(),
|
||||
notif2.sbn.getKey(),
|
||||
stats2.dismissalSurface,
|
||||
stats2.dismissalSentiment,
|
||||
stats2.notificationVisibility);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissNotificationsMarkedAsDismissed() {
|
||||
// GIVEN a collection with a couple notifications
|
||||
NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
|
||||
NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
|
||||
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
|
||||
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
|
||||
|
||||
// WHEN both notifications are manually dismissed together
|
||||
mCollection.dismissNotifications(
|
||||
List.of(new Pair(entry1, defaultStats(entry1)),
|
||||
new Pair(entry2, defaultStats(entry2))));
|
||||
|
||||
// THEN the entries are marked as dismissed
|
||||
assertEquals(DISMISSED, entry1.getDismissState());
|
||||
assertEquals(DISMISSED, entry2.getDismissState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissNotificationssCallsDismissInterceptors() {
|
||||
// GIVEN a collection with notifications with multiple dismiss interceptors
|
||||
mInterceptor1.shouldInterceptDismissal = true;
|
||||
mInterceptor2.shouldInterceptDismissal = true;
|
||||
mInterceptor3.shouldInterceptDismissal = false;
|
||||
mCollection.addNotificationDismissInterceptor(mInterceptor1);
|
||||
mCollection.addNotificationDismissInterceptor(mInterceptor2);
|
||||
mCollection.addNotificationDismissInterceptor(mInterceptor3);
|
||||
|
||||
NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
|
||||
NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
|
||||
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
|
||||
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
|
||||
|
||||
// WHEN both notifications are manually dismissed together
|
||||
mCollection.dismissNotifications(
|
||||
List.of(new Pair(entry1, defaultStats(entry1)),
|
||||
new Pair(entry2, defaultStats(entry2))));
|
||||
|
||||
// THEN all interceptors get checked
|
||||
verify(mInterceptor1).shouldInterceptDismissal(entry1);
|
||||
verify(mInterceptor2).shouldInterceptDismissal(entry1);
|
||||
verify(mInterceptor3).shouldInterceptDismissal(entry1);
|
||||
verify(mInterceptor1).shouldInterceptDismissal(entry2);
|
||||
verify(mInterceptor2).shouldInterceptDismissal(entry2);
|
||||
verify(mInterceptor3).shouldInterceptDismissal(entry2);
|
||||
|
||||
assertEquals(List.of(mInterceptor1, mInterceptor2), entry1.mDismissInterceptors);
|
||||
assertEquals(List.of(mInterceptor1, mInterceptor2), entry2.mDismissInterceptors);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissAllNotificationsCallsRebuildOnce() {
|
||||
// GIVEN a collection with a couple notifications
|
||||
NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
|
||||
NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
|
||||
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
|
||||
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
|
||||
clearInvocations(mBuildListener);
|
||||
|
||||
// WHEN all notifications are dismissed for the user who posted both notifs
|
||||
mCollection.dismissAllNotifications(entry1.getSbn().getUser().getIdentifier());
|
||||
|
||||
// THEN build list is only called one time
|
||||
verify(mBuildListener).onBuildList(any(Collection.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissAllNotificationsSentToSystemServer() throws RemoteException {
|
||||
// GIVEN a collection with a couple notifications
|
||||
NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
|
||||
NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
|
||||
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
|
||||
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
|
||||
|
||||
// WHEN all notifications are dismissed for the user who posted both notifs
|
||||
mCollection.dismissAllNotifications(entry1.getSbn().getUser().getIdentifier());
|
||||
|
||||
// THEN we send the dismissal to system server
|
||||
verify(mStatusBarService).onClearAllNotifications(
|
||||
entry1.getSbn().getUser().getIdentifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissAllNotificationsMarkedAsDismissed() {
|
||||
// GIVEN a collection with a couple notifications
|
||||
NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
|
||||
NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
|
||||
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
|
||||
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
|
||||
|
||||
// WHEN all notifications are dismissed for the user who posted both notifs
|
||||
mCollection.dismissAllNotifications(entry1.getSbn().getUser().getIdentifier());
|
||||
|
||||
// THEN the entries are marked as dismissed
|
||||
assertEquals(DISMISSED, entry1.getDismissState());
|
||||
assertEquals(DISMISSED, entry2.getDismissState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissAllNotificationsDoesNotMarkDismissedUnclearableNotifs() {
|
||||
// GIVEN a collection with one unclearable notification and one clearable notification
|
||||
NotificationEntryBuilder notifEntryBuilder = buildNotif(TEST_PACKAGE, 47, "myTag");
|
||||
notifEntryBuilder.modifyNotification(mContext)
|
||||
.setFlag(FLAG_NO_CLEAR, true);
|
||||
NotifEvent unclearabeNotif = mNoMan.postNotif(notifEntryBuilder);
|
||||
NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
|
||||
NotificationEntry unclearableEntry = mCollectionListener.getEntry(unclearabeNotif.key);
|
||||
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
|
||||
|
||||
// WHEN all notifications are dismissed for the user who posted both notifs
|
||||
mCollection.dismissAllNotifications(unclearableEntry.getSbn().getUser().getIdentifier());
|
||||
|
||||
// THEN only the clearable entry is marked as dismissed
|
||||
assertEquals(NOT_DISMISSED, unclearableEntry.getDismissState());
|
||||
assertEquals(DISMISSED, entry2.getDismissState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissAllNotificationsCallsDismissInterceptorsOnlyOnUnclearableNotifs() {
|
||||
// GIVEN a collection with multiple dismiss interceptors
|
||||
mInterceptor1.shouldInterceptDismissal = true;
|
||||
mInterceptor2.shouldInterceptDismissal = true;
|
||||
mInterceptor3.shouldInterceptDismissal = false;
|
||||
mCollection.addNotificationDismissInterceptor(mInterceptor1);
|
||||
mCollection.addNotificationDismissInterceptor(mInterceptor2);
|
||||
mCollection.addNotificationDismissInterceptor(mInterceptor3);
|
||||
|
||||
// GIVEN a collection with one unclearable and one clearable notification
|
||||
NotifEvent unclearableNotif = mNoMan.postNotif(
|
||||
buildNotif(TEST_PACKAGE, 47, "myTag")
|
||||
.setFlag(mContext, FLAG_NO_CLEAR, true));
|
||||
NotificationEntry unclearable = mCollectionListener.getEntry(unclearableNotif.key);
|
||||
NotifEvent clearableNotif = mNoMan.postNotif(
|
||||
buildNotif(TEST_PACKAGE, 88, "myTag")
|
||||
.setFlag(mContext, FLAG_NO_CLEAR, false));
|
||||
NotificationEntry clearable = mCollectionListener.getEntry(clearableNotif.key);
|
||||
|
||||
// WHEN all notifications are dismissed for the user who posted the notif
|
||||
mCollection.dismissAllNotifications(clearable.getSbn().getUser().getIdentifier());
|
||||
|
||||
// THEN all interceptors get checked for the unclearable notification
|
||||
verify(mInterceptor1).shouldInterceptDismissal(unclearable);
|
||||
verify(mInterceptor2).shouldInterceptDismissal(unclearable);
|
||||
verify(mInterceptor3).shouldInterceptDismissal(unclearable);
|
||||
assertEquals(List.of(mInterceptor1, mInterceptor2), unclearable.mDismissInterceptors);
|
||||
|
||||
// THEN no interceptors get checked for the clearable notification
|
||||
verify(mInterceptor1, never()).shouldInterceptDismissal(clearable);
|
||||
verify(mInterceptor2, never()).shouldInterceptDismissal(clearable);
|
||||
verify(mInterceptor3, never()).shouldInterceptDismissal(clearable);
|
||||
}
|
||||
|
||||
private static NotificationEntryBuilder buildNotif(String pkg, int id, String tag) {
|
||||
return new NotificationEntryBuilder()
|
||||
.setPkg(pkg)
|
||||
|
||||
@@ -70,6 +70,8 @@ import com.android.systemui.statusbar.notification.NotificationFilter;
|
||||
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
|
||||
import com.android.systemui.statusbar.notification.TestableNotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.VisualStabilityManager;
|
||||
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.NotificationEntryBuilder;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
|
||||
@@ -133,6 +135,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
@Mock private NotificationSectionsManager mNotificationSectionsManager;
|
||||
@Mock private NotificationSection mNotificationSection;
|
||||
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
|
||||
@Mock private FeatureFlags mFeatureFlags;
|
||||
private UserChangedListener mUserChangedListener;
|
||||
private TestableNotificationEntryManager mEntryManager;
|
||||
private int mOriginalInterruptionModelSetting;
|
||||
@@ -182,9 +185,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
mock(LeakDetector.class),
|
||||
mock(ForegroundServiceDismissalFeatureController.class)
|
||||
);
|
||||
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
|
||||
mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager);
|
||||
|
||||
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
|
||||
|
||||
NotificationShelf notificationShelf = mock(NotificationShelf.class);
|
||||
when(mNotificationSectionsManager.createSectionsForBuckets()).thenReturn(
|
||||
@@ -208,7 +210,11 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
mZenModeController,
|
||||
mNotificationSectionsManager,
|
||||
mock(ForegroundServiceSectionController.class),
|
||||
mock(ForegroundServiceDismissalFeatureController.class)
|
||||
mock(ForegroundServiceDismissalFeatureController.class),
|
||||
mFeatureFlags,
|
||||
mock(NotifPipeline.class),
|
||||
mEntryManager,
|
||||
mock(NotifCollection.class)
|
||||
);
|
||||
verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture());
|
||||
mUserChangedListener = userChangedCaptor.getValue();
|
||||
|
||||
@@ -58,6 +58,7 @@ import com.android.systemui.bubbles.BubbleController;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.FeatureFlags;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.NotificationPresenter;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||
@@ -67,6 +68,8 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
|
||||
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
|
||||
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.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
|
||||
@@ -114,6 +117,12 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
private BubbleController mBubbleController;
|
||||
@Mock
|
||||
private ShadeControllerImpl mShadeController;
|
||||
@Mock
|
||||
private FeatureFlags mFeatureFlags;
|
||||
@Mock
|
||||
private NotifPipeline mNotifPipeline;
|
||||
@Mock
|
||||
private NotifCollection mNotifCollection;
|
||||
|
||||
@Mock
|
||||
private ActivityIntentHelper mActivityIntentHelper;
|
||||
@@ -162,6 +171,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
mActiveNotifications.add(mBubbleNotificationRow.getEntry());
|
||||
when(mEntryManager.getVisibleNotifications()).thenReturn(mActiveNotifications);
|
||||
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
|
||||
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
|
||||
|
||||
mNotificationActivityStarter = (new StatusBarNotificationActivityStarter.Builder(
|
||||
getContext(), mock(CommandQueue.class), () -> mAssistManager,
|
||||
@@ -175,11 +185,12 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
mKeyguardStateController,
|
||||
mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class),
|
||||
mock(LockPatternUtils.class), mHandler, mHandler, mUiBgExecutor,
|
||||
mActivityIntentHelper, mBubbleController, mShadeController))
|
||||
mActivityIntentHelper, mBubbleController, mShadeController, mFeatureFlags,
|
||||
mNotifPipeline, mNotifCollection)
|
||||
.setStatusBar(mStatusBar)
|
||||
.setNotificationPanelViewController(mock(NotificationPanelViewController.class))
|
||||
.setNotificationPresenter(mock(NotificationPresenter.class))
|
||||
.setActivityLaunchAnimator(mock(ActivityLaunchAnimator.class))
|
||||
.setActivityLaunchAnimator(mock(ActivityLaunchAnimator.class)))
|
||||
.build();
|
||||
|
||||
// set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg
|
||||
|
||||
Reference in New Issue
Block a user