Remove NotificationData
Ye olde NotificationData class was responsible for a few general things:
- Keep a list of visible `NotificationEntry`s
- Filter / sort the visible entries
- Keep a sorted / filtered list of those entries
- Answer lots of questions about the entries themselves (rank,
isAmbient, list of entries for current user, etc.)
- Keep track of the current RankingMap
- Set priority buckets on entries
- Tell the group manager when things changed
The basic idea here is to remove NotificationData in favor of 3 other
changes:
1. Any place which needed to query NotificationData for info about the
entry (in particular its ranking) can just ask the entry for it now.
Entries all keep a reference to their rank
2. NotificationEntryManager now just maintains its own list of visible
notifications. It was already the point of contact to get a handle to
NotificationData so this makes call sites simpler.
3. Create a simpler NotificationRankingManager (maybe delete this
eventually) to encapsulate the sorting logic and hang on to the latest
RankingMap
Test: atest SystemUITests
Change-Id: I14073e103c6d50da37207ca8fd86828da0aaaff9
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index dca5c8a..1a0690c 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -75,10 +75,10 @@
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index 385de4a..15a5c27 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -139,8 +139,7 @@
// Update appOp if there's an associated pending or visible notification:
final String foregroundKey = getStandardLayoutKey(userId, packageName);
if (foregroundKey != null) {
- final NotificationEntry entry = mEntryManager.getPendingOrCurrentNotif(
- foregroundKey);
+ final NotificationEntry entry = mEntryManager.getPendingOrActiveNotif(foregroundKey);
if (entry != null
&& uid == entry.getSbn().getUid()
&& packageName.equals(entry.getSbn().getPackageName())) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 9f7bdd4..1052a99 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -78,7 +78,6 @@
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.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -352,14 +351,13 @@
* @param userId the id of the user
*/
private void restoreBubbles(@UserIdInt int userId) {
- NotificationData notificationData =
- mNotificationEntryManager.getNotificationData();
ArraySet<String> savedBubbleKeys = mSavedBubbleKeysPerUser.get(userId);
if (savedBubbleKeys == null) {
// There were no bubbles saved for this used.
return;
}
- for (NotificationEntry e : notificationData.getNotificationsForCurrentUser()) {
+ for (NotificationEntry e :
+ mNotificationEntryManager.getActiveNotificationsForCurrentUser()) {
if (savedBubbleKeys.contains(e.getKey())
&& mNotificationInterruptionStateProvider.shouldBubbleUp(e)
&& canLaunchInActivityView(mContext, e)) {
@@ -458,7 +456,7 @@
public boolean isBubbleNotificationSuppressedFromShade(String key) {
boolean isBubbleAndSuppressed = mBubbleData.hasBubbleWithKey(key)
&& !mBubbleData.getBubbleWithKey(key).showInShadeWhenBubble();
- NotificationEntry entry = mNotificationEntryManager.getNotificationData().get(key);
+ NotificationEntry entry = mNotificationEntryManager.getActiveNotificationUnfiltered(key);
String groupKey = entry != null ? entry.getSbn().getGroupKey() : null;
boolean isSuppressedSummary = mBubbleData.isSummarySuppressed(groupKey);
boolean isSummary = key.equals(mBubbleData.getSummaryKey(groupKey));
@@ -571,7 +569,8 @@
new NotificationRemoveInterceptor() {
@Override
public boolean onNotificationRemoveRequested(String key, int reason) {
- NotificationEntry entry = mNotificationEntryManager.getNotificationData().get(key);
+ NotificationEntry entry =
+ mNotificationEntryManager.getActiveNotificationUnfiltered(key);
String groupKey = entry != null ? entry.getSbn().getGroupKey() : null;
ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
@@ -768,7 +767,7 @@
String notifKey = mBubbleData.getSummaryKey(groupKey);
mBubbleData.removeSuppressedSummary(groupKey);
NotificationEntry entry =
- mNotificationEntryManager.getNotificationData().get(notifKey);
+ mNotificationEntryManager.getActiveNotificationUnfiltered(notifKey);
mNotificationEntryManager.performRemoveNotification(
entry.getSbn(), UNDEFINED_DISMISS_REASON);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index 6744d74..7007f9d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -35,6 +35,7 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.statusbar.phone.DozeServiceHost;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -50,6 +51,7 @@
import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotControllerImpl;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -257,4 +259,7 @@
@Binds
public abstract VolumeComponent provideVolumeComponent(
VolumeDialogComponent volumeDialogComponent);
+ /** */
+ @Binds
+ public abstract HeadsUpManager bindHeadsUpManager(HeadsUpManagerPhone headsUpManagerPhone);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 48c72d3..f1d02bb 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -33,7 +33,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -74,7 +74,7 @@
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
- abstract NotificationData.KeyguardEnvironment bindKeyguardEnvironment(
+ abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment(
KeyguardEnvironmentImpl keyguardEnvironment);
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index c4de2d3..98a2675 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -110,8 +110,7 @@
}
String key = sbn.getKey();
- boolean isUpdate =
- mEntryManager.getNotificationData().get(key) != null;
+ boolean isUpdate = mEntryManager.getActiveNotificationUnfiltered(key) != null;
// In case we don't allow child notifications, we ignore children of
// notifications that have a summary, since` we're not going to show them
// anyway. This is true also when the summary is canceled,
@@ -126,8 +125,7 @@
if (isUpdate) {
mEntryManager.removeNotification(key, rankingMap, UNDEFINED_DISMISS_REASON);
} else {
- mEntryManager.getNotificationData()
- .updateRanking(rankingMap, "onNotificationPosted");
+ mEntryManager.updateRanking(rankingMap, "onNotificationPosted");
}
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 571d3d7..021e7e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -15,6 +15,7 @@
*/
package com.android.systemui.statusbar;
+import static android.app.Notification.VISIBILITY_SECRET;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
import static com.android.systemui.DejankUtils.whitelistIpcs;
@@ -126,7 +127,7 @@
updatePublicMode();
// The filtering needs to happen before the update call below in order to make sure
// the presenter has the updated notifications from the new user
- getEntryManager().getNotificationData().filterAndSort("user switched");
+ getEntryManager().reapplyFilterAndSort("user switched");
mPresenter.onUserSwitched(mCurrentUserId);
for (UserChangedListener listener : mListeners) {
@@ -148,17 +149,17 @@
}
}
if (notificationKey != null) {
- final int count =
- getEntryManager().getNotificationData().getActiveNotifications().size();
- final int rank = getEntryManager().getNotificationData().getRank(notificationKey);
+ NotificationEntry entry =
+ getEntryManager().getActiveNotificationUnfiltered(notificationKey);
+ final int count = getEntryManager().getActiveNotificationsCount();
+ final int rank = entry != null ? entry.getRanking().getRank() : 0;
NotificationVisibility.NotificationLocation location =
- NotificationLogger.getNotificationLocation(
- getEntryManager().getNotificationData().get(notificationKey));
+ NotificationLogger.getNotificationLocation(entry);
final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
rank, count, true, location);
try {
mBarService.onNotificationClick(notificationKey, nv);
- } catch (RemoteException e) {
+ } catch (RemoteException exception) {
/* ignore */
}
}
@@ -311,9 +312,9 @@
Log.wtf(TAG, "mEntryManager was null!", new Throwable());
return true;
}
- return isLockscreenPublicMode(mCurrentUserId)
- && getEntryManager().getNotificationData().getVisibilityOverride(key) ==
- Notification.VISIBILITY_SECRET;
+ NotificationEntry visibleEntry = getEntryManager().getActiveNotificationUnfiltered(key);
+ return isLockscreenPublicMode(mCurrentUserId) && visibleEntry != null
+ && visibleEntry.getRanking().getVisibilityOverride() == VISIBILITY_SECRET;
}
public boolean shouldShowOnKeyguard(NotificationEntry entry) {
@@ -326,8 +327,7 @@
&& hideSilentNotificationsOnLockscreen()) {
exceedsPriorityThreshold = entry.getBucket() != BUCKET_SILENT;
} else {
- exceedsPriorityThreshold =
- !getEntryManager().getNotificationData().isAmbient(entry.getKey());
+ exceedsPriorityThreshold = !entry.getRanking().isAmbient();
}
return mShowLockscreenNotifications && exceedsPriorityThreshold;
}
@@ -467,8 +467,9 @@
Log.wtf(TAG, "mEntryManager was null!", new Throwable());
return true;
}
- return getEntryManager().getNotificationData().getVisibilityOverride(key) ==
- Notification.VISIBILITY_PRIVATE;
+ NotificationEntry entry = getEntryManager().getActiveNotificationUnfiltered(key);
+ return entry != null
+ && entry.getRanking().getVisibilityOverride() == Notification.VISIBILITY_PRIVATE;
}
private void updateCurrentProfilesCache() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index d668665..a98f826 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -102,8 +102,7 @@
}
- // Late binding
- private NotificationEntryManager mEntryManager;
+ private final NotificationEntryManager mEntryManager;
// Late binding, also @Nullable due to being in com.android.systemui.statusbar.phone package
@Nullable
@@ -258,8 +257,9 @@
if (mMediaNotificationKey == null) {
return null;
}
- synchronized (mEntryManager.getNotificationData()) {
- NotificationEntry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
+ synchronized (mEntryManager) {
+ NotificationEntry entry = mEntryManager
+ .getActiveNotificationUnfiltered(mMediaNotificationKey);
if (entry == null || entry.expandedIcon == null) {
return null;
}
@@ -281,8 +281,9 @@
public void findAndUpdateMediaNotifications() {
boolean metaDataChanged = false;
- synchronized (mEntryManager.getNotificationData()) {
- Set<NotificationEntry> allNotifications = mEntryManager.getAllNotifs();
+ synchronized (mEntryManager) {
+ Set<NotificationEntry> allNotifications =
+ mEntryManager.getPendingAndActiveNotifications();
// Promote the media notification with a controller in 'playing' state, if any.
NotificationEntry mediaNotification = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 35f06f9..e10d27b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -184,8 +184,9 @@
ViewGroup actionGroup = (ViewGroup) parent;
buttonIndex = actionGroup.indexOfChild(view);
}
- final int count = mEntryManager.getNotificationData().getActiveNotifications().size();
- final int rank = mEntryManager.getNotificationData().getRank(key);
+ final int count = mEntryManager.getActiveNotificationsCount();
+ final int rank = mEntryManager
+ .getActiveNotificationUnfiltered(key).getRanking().getRank();
// Notification may be updated before this function is executed, and thus play safe
// here and verify that the action object is still the one that where the click happens.
@@ -202,7 +203,7 @@
}
NotificationVisibility.NotificationLocation location =
NotificationLogger.getNotificationLocation(
- mEntryManager.getNotificationData().get(key));
+ mEntryManager.getActiveNotificationUnfiltered(key));
final NotificationVisibility nv =
NotificationVisibility.obtain(key, rank, count, true, location);
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 20a3e35..ef733a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -140,8 +140,7 @@
Assert.isMainThread();
beginUpdate();
- ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
- .getActiveNotifications();
+ List<NotificationEntry> activeNotifications = mEntryManager.getVisibleNotifications();
ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
final int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
@@ -339,7 +338,7 @@
}
for (ExpandableNotificationRow remove : toRemove) {
parent.removeChildNotification(remove);
- if (mEntryManager.getNotificationData().get(
+ if (mEntryManager.getActiveNotificationUnfiltered(
remove.getStatusBarNotification().getKey()) == null) {
// We only want to add an animation if the view is completely removed
// otherwise it's just a transfer
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 7bdb21d..40f8e39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -73,8 +73,8 @@
public void smartActionClicked(
NotificationEntry entry, int actionIndex, Notification.Action action,
boolean generatedByAssistant) {
- final int count = mEntryManager.getNotificationData().getActiveNotifications().size();
- final int rank = mEntryManager.getNotificationData().getRank(entry.getKey());
+ final int count = mEntryManager.getActiveNotificationsCount();
+ final int rank = entry.getRanking().getRank();
NotificationVisibility.NotificationLocation location =
NotificationLogger.getNotificationLocation(entry);
final NotificationVisibility nv = NotificationVisibility.obtain(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
index 314dc04..015c323 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -37,14 +37,14 @@
*/
@Singleton
class BypassHeadsUpNotifier @Inject constructor(
- private val context: Context,
- private val bypassController: KeyguardBypassController,
- private val statusBarStateController: StatusBarStateController,
- private val headsUpManager: HeadsUpManagerPhone,
- private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
- private val mediaManager: NotificationMediaManager,
- tunerService: TunerService) : StatusBarStateController.StateListener,
- NotificationMediaManager.MediaListener {
+ private val context: Context,
+ private val bypassController: KeyguardBypassController,
+ private val statusBarStateController: StatusBarStateController,
+ private val headsUpManager: HeadsUpManagerPhone,
+ private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
+ private val mediaManager: NotificationMediaManager,
+ tunerService: TunerService
+) : StatusBarStateController.StateListener, NotificationMediaManager.MediaListener {
private lateinit var entryManager: NotificationEntryManager
private var currentMediaEntry: NotificationEntry? = null
@@ -77,7 +77,8 @@
override fun onMetadataOrStateChanged(metadata: MediaMetadata?, state: Int) {
val previous = currentMediaEntry
- var newEntry = entryManager.notificationData.get(mediaManager.mediaNotificationKey)
+ var newEntry = entryManager
+ .getActiveNotificationUnfiltered(mediaManager.mediaNotificationKey)
if (!NotificationMediaManager.isPlayingState(state)) {
newEntry = null
}
@@ -101,7 +102,7 @@
*/
private fun canAutoHeadsUp(entry: NotificationEntry): Boolean {
if (!isAutoHeadsUpAllowed()) {
- return false;
+ return false
}
if (entry.isSensitive) {
// filter sensitive notifications
@@ -111,7 +112,7 @@
// filter notifications invisible on Keyguard
return false
}
- if (!entryManager.notificationData.activeNotifications.contains(entry)) {
+ if (entryManager.getActiveNotificationUnfiltered(entry.key) != null) {
// filter notifications not the active list currently
return false
}
@@ -125,7 +126,7 @@
/**
* @return {@code true} if autoHeadsUp is possible right now.
*/
- private fun isAutoHeadsUpAllowed() : Boolean {
+ private fun isAutoHeadsUpAllowed(): Boolean {
if (!enabled) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index df78fa3..0694920 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -99,7 +99,8 @@
/**
* Called whenever notification ranking changes, in response to
* {@link NotificationListenerService#onNotificationRankingUpdate}. This is called after
- * NotificationData has processed the update and notifications have been re-sorted and filtered.
+ * NotificationEntryManager has processed the update and notifications have been re-sorted
+ * and filtered.
*
* @param rankingMap provides access to ranking information on currently active notifications
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 13d90ff..7a58097 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -18,10 +18,12 @@
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_ERROR;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
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.Log;
@@ -36,9 +38,8 @@
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.NotificationUpdateHandler;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
import com.android.systemui.statusbar.notification.logging.NotifEvent;
import com.android.systemui.statusbar.notification.logging.NotifLog;
@@ -46,12 +47,15 @@
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.util.Assert;
import com.android.systemui.util.leak.LeakDetector;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -62,9 +66,29 @@
import javax.inject.Singleton;
/**
- * NotificationEntryManager is responsible for the adding, removing, and updating of notifications.
- * It also handles tasks such as their inflation and their interaction with other
- * Notification.*Manager objects.
+ * NotificationEntryManager is responsible for the adding, removing, and updating of
+ * {@link NotificationEntry}s. It also handles tasks such as their inflation and their interaction
+ * with other Notification.*Manager objects.
+ *
+ * We track notification entries through this lifecycle:
+ * 1. Pending
+ * 2. Active
+ * 3. Sorted / filtered (visible)
+ *
+ * Every entry spends some amount of time in the pending state, while it is being inflated. Once
+ * inflated, an entry moves into the active state, where it _could_ potentially be shown to the
+ * user. After an entry makes its way into the active state, we sort and filter the entire set to
+ * repopulate the visible set.
+ *
+ * There are a few different things that other classes may be interested in, and most of them
+ * involve the current set of notifications. Here's a brief overview of things you may want to know:
+ * @see #getVisibleNotifications() for the visible set
+ * @see #getActiveNotificationUnfiltered(String) to check if a key exists
+ * @see #getPendingNotificationsIterator() for an iterator over the pending notifications
+ * @see #getPendingOrActiveNotif(String) to find a notification exists for that key in any list
+ * @see #getPendingAndActiveNotifications() to get the entire set of Notifications that we're
+ * aware of
+ * @see #getActiveNotificationsForCurrentUser() to see every notification that the current user owns
*/
@Singleton
public class NotificationEntryManager implements
@@ -78,12 +102,23 @@
/**
* Used when a notification is removed and it doesn't have a reason that maps to one of the
* reasons defined in NotificationListenerService
- * (e.g. {@link NotificationListenerService.REASON_CANCEL})
+ * (e.g. {@link NotificationListenerService#REASON_CANCEL})
*/
public static final int UNDEFINED_DISMISS_REASON = 0;
+ /** Pending notifications are ones awaiting inflation */
@VisibleForTesting
protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
+ /**
+ * Active notifications have been inflated / prepared and could become visible, but may get
+ * filtered out if for instance they are not for the current user
+ */
+ private final ArrayMap<String, NotificationEntry> mActiveNotifications = new ArrayMap<>();
+ @VisibleForTesting
+ /** This is the list of "active notifications for this user in this context" */
+ protected final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
+ private final List<NotificationEntry> mReadOnlyNotifications =
+ Collections.unmodifiableList(mSortedAndFiltered);
private final Map<NotificationEntry, NotificationLifetimeExtender> mRetainedNotifications =
new ArrayMap<>();
@@ -92,10 +127,12 @@
private NotificationRemoteInputManager mRemoteInputManager;
private NotificationRowBinder mNotificationRowBinder;
+ private final KeyguardEnvironment mKeyguardEnvironment;
+ private final NotificationGroupManager mGroupManager;
+ private final NotificationRankingManager mRankingManager;
+
private NotificationPresenter mPresenter;
- private NotificationListenerService.RankingMap mLatestRankingMap;
- @VisibleForTesting
- protected NotificationData mNotificationData;
+ private RankingMap mLatestRankingMap;
private NotifLog mNotifLog;
@VisibleForTesting
@@ -129,10 +166,14 @@
@Inject
public NotificationEntryManager(
- NotificationData notificationData,
- NotifLog notifLog) {
- mNotificationData = notificationData;
+ NotifLog notifLog,
+ NotificationGroupManager groupManager,
+ NotificationRankingManager rankingManager,
+ KeyguardEnvironment keyguardEnvironment) {
mNotifLog = notifLog;
+ mGroupManager = groupManager;
+ mRankingManager = rankingManager;
+ mKeyguardEnvironment = keyguardEnvironment;
}
/** Adds a {@link NotificationEntryListener}. */
@@ -171,7 +212,6 @@
NotificationListContainer listContainer,
HeadsUpManager headsUpManager) {
mPresenter = presenter;
- mNotificationData.setHeadsUpManager(headsUpManager);
}
/** Adds multiple {@link NotificationLifetimeExtender}s. */
@@ -188,10 +228,6 @@
UNDEFINED_DISMISS_REASON));
}
- public NotificationData getNotificationData() {
- return mNotificationData;
- }
-
@Override
public void onReorderingAllowed() {
updateNotifications("reordering is now allowed");
@@ -212,10 +248,17 @@
}
private NotificationVisibility obtainVisibility(String key) {
- final int rank = mNotificationData.getRank(key);
- final int count = mNotificationData.getActiveNotifications().size();
+ NotificationEntry e = mActiveNotifications.get(key);
+ final int rank;
+ if (e != null) {
+ rank = e.getRanking().getRank();
+ } else {
+ rank = 0;
+ }
+
+ final int count = mActiveNotifications.size();
NotificationVisibility.NotificationLocation location =
- NotificationLogger.getNotificationLocation(getNotificationData().get(key));
+ NotificationLogger.getNotificationLocation(getActiveNotificationUnfiltered(key));
return NotificationVisibility.obtain(key, rank, count, true, location);
}
@@ -227,7 +270,7 @@
mNotifLog.log(NotifEvent.INFLATION_ABORTED, entry.getSbn(), null,
"PendingNotification aborted. " + reason);
}
- NotificationEntry addedEntry = mNotificationData.get(key);
+ NotificationEntry addedEntry = getActiveNotificationUnfiltered(key);
if (addedEntry != null) {
addedEntry.abortTask();
mNotifLog.log(NotifEvent.INFLATION_ABORTED, addedEntry.getSbn(),
@@ -258,13 +301,13 @@
// If there was an async task started after the removal, we don't want to add it back to
// the list, otherwise we might get leaks.
if (!entry.isRowRemoved()) {
- boolean isNew = mNotificationData.get(entry.getKey()) == null;
+ boolean isNew = getActiveNotificationUnfiltered(entry.getKey()) == null;
if (isNew) {
for (NotificationEntryListener listener : mNotificationEntryListeners) {
mNotifLog.log(NotifEvent.INFLATED, entry);
listener.onEntryInflated(entry, inflatedFlags);
}
- mNotificationData.add(entry);
+ addActiveNotification(entry);
updateNotifications("onAsyncInflationFinished");
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onNotificationAdded(entry);
@@ -278,8 +321,34 @@
}
}
+ /**
+ * Equivalent to the old NotificationData#add
+ * @param entry - an entry which is prepared for display
+ */
+ private void addActiveNotification(NotificationEntry entry) {
+ Assert.isMainThread();
+
+ mActiveNotifications.put(entry.getKey(), entry);
+ mGroupManager.onEntryAdded(entry);
+ updateRankingAndSort(mRankingManager.getRankingMap(), "addEntryInternalInternal");
+ }
+
+ /**
+ * Available so that tests can directly manipulate the list of active notifications easily
+ *
+ * @param entry the entry to add directly to the visible notification map
+ */
+ @VisibleForTesting
+ public void addActiveNotificationForTest(NotificationEntry entry) {
+ mActiveNotifications.put(entry.getKey(), entry);
+ mGroupManager.onEntryAdded(entry);
+
+ reapplyFilterAndSort("addVisibleNotification");
+ }
+
+
@Override
- public void removeNotification(String key, NotificationListenerService.RankingMap ranking,
+ public void removeNotification(String key, RankingMap ranking,
int reason) {
removeNotificationInternal(key, ranking, obtainVisibility(key), false /* forceRemove */,
false /* removedByUser */, reason);
@@ -287,7 +356,7 @@
private void removeNotificationInternal(
String key,
- @Nullable NotificationListenerService.RankingMap ranking,
+ @Nullable RankingMap ranking,
@Nullable NotificationVisibility visibility,
boolean forceRemove,
boolean removedByUser,
@@ -300,7 +369,7 @@
return;
}
- final NotificationEntry entry = mNotificationData.get(key);
+ final NotificationEntry entry = getActiveNotificationUnfiltered(key);
boolean lifetimeExtended = false;
// Notification was canceled before it got inflated
@@ -355,8 +424,7 @@
// Let's remove the children if this was a summary
handleGroupSummaryRemoved(key);
-
- mNotificationData.remove(key, ranking);
+ removeVisibleNotification(key);
updateNotifications("removeNotificationInternal");
Dependency.get(LeakDetector.class).trackGarbage(entry);
removedByUser |= entryDismissed;
@@ -381,7 +449,7 @@
*
*/
private void handleGroupSummaryRemoved(String key) {
- NotificationEntry entry = mNotificationData.get(key);
+ NotificationEntry entry = getActiveNotificationUnfiltered(key);
if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) {
if (entry.getSbn().getOverrideGroupKey() != null && !entry.isRowDismissed()) {
// We don't want to remove children for autobundled notifications as they are not
@@ -413,13 +481,14 @@
}
private void addNotificationInternal(StatusBarNotification notification,
- NotificationListenerService.RankingMap rankingMap) throws InflationException {
+ RankingMap rankingMap) throws InflationException {
String key = notification.getKey();
if (DEBUG) {
Log.d(TAG, "addNotification key=" + key);
}
- mNotificationData.updateRanking(rankingMap, "addNotificationInternal");
+ updateRankingAndSort(rankingMap, "addNotificationInternal");
+
Ranking ranking = new Ranking();
rankingMap.getRanking(key, ranking);
@@ -439,8 +508,7 @@
}
@Override
- public void addNotification(StatusBarNotification notification,
- NotificationListenerService.RankingMap ranking) {
+ public void addNotification(StatusBarNotification notification, RankingMap ranking) {
try {
addNotificationInternal(notification, ranking);
} catch (InflationException e) {
@@ -449,12 +517,12 @@
}
private void updateNotificationInternal(StatusBarNotification notification,
- NotificationListenerService.RankingMap ranking) throws InflationException {
+ RankingMap ranking) throws InflationException {
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final String key = notification.getKey();
abortExistingInflation(key, "updateNotification");
- NotificationEntry entry = mNotificationData.get(key);
+ NotificationEntry entry = getActiveNotificationUnfiltered(key);
if (entry == null) {
return;
}
@@ -463,7 +531,11 @@
// to keep its lifetime extended.
cancelLifetimeExtension(entry);
- mNotificationData.update(entry, ranking, notification, "updateNotificationInternal");
+ updateRankingAndSort(ranking, "updateNotificationInternal");
+ StatusBarNotification oldSbn = entry.getSbn();
+ entry.setSbn(notification);
+ mGroupManager.onEntryUpdated(entry, oldSbn);
+
mNotifLog.log(NotifEvent.NOTIF_UPDATED, entry.getSbn(), entry.getRanking());
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPreEntryUpdated(entry);
@@ -486,8 +558,7 @@
}
@Override
- public void updateNotification(StatusBarNotification notification,
- NotificationListenerService.RankingMap ranking) {
+ public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
try {
updateNotificationInternal(notification, ranking);
} catch (InflationException e) {
@@ -500,16 +571,16 @@
* @param reason why the notifications are updating
*/
public void updateNotifications(String reason) {
- mNotificationData.filterAndSort(reason);
+ reapplyFilterAndSort(reason);
if (mPresenter != null) {
mPresenter.updateNotificationViews();
}
}
@Override
- public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
+ public void updateNotificationRanking(RankingMap rankingMap) {
List<NotificationEntry> entries = new ArrayList<>();
- entries.addAll(mNotificationData.getActiveNotifications());
+ entries.addAll(getVisibleNotifications());
entries.addAll(mPendingNotifications.values());
// Has a copy of the current UI adjustments.
@@ -523,7 +594,7 @@
}
// Populate notification entries from the new rankings.
- mNotificationData.updateRanking(rankingMap, "updateNotificationRanking");
+ updateRankingAndSort(rankingMap, "updateNotificationRanking");
updateRankingOfPendingNotifications(rankingMap);
// By comparing the old and new UI adjustments, reinflate the view accordingly.
@@ -542,8 +613,7 @@
}
}
- private void updateRankingOfPendingNotifications(
- @Nullable NotificationListenerService.RankingMap rankingMap) {
+ private void updateRankingOfPendingNotifications(@Nullable RankingMap rankingMap) {
if (rankingMap == null) {
return;
}
@@ -565,23 +635,35 @@
}
/**
- * @return all notification we're currently aware of (both pending and visible notifications)
+ * @return all notifications we're currently aware of (both pending and active notifications)
*/
- public Set<NotificationEntry> getAllNotifs() {
+ public Set<NotificationEntry> getPendingAndActiveNotifications() {
Set<NotificationEntry> allNotifs = new HashSet<>(mPendingNotifications.values());
- allNotifs.addAll(mNotificationData.getActiveNotifications());
+ allNotifs.addAll(mSortedAndFiltered);
return allNotifs;
}
/**
+ * Use this method to retrieve a notification entry that has been prepared for presentation.
+ * Note that the notification may be filtered out and never shown to the user.
+ *
+ * @see #getVisibleNotifications() for the currently sorted and filtered list
+ *
+ * @return a {@link NotificationEntry} if it has been prepared, else null
+ */
+ public NotificationEntry getActiveNotificationUnfiltered(String key) {
+ return mActiveNotifications.get(key);
+ }
+
+ /**
* Gets the pending or visible notification entry with the given key. Returns null if
* notification doesn't exist.
*/
- public NotificationEntry getPendingOrCurrentNotif(String key) {
+ public NotificationEntry getPendingOrActiveNotif(String key) {
if (mPendingNotifications.containsKey(key)) {
return mPendingNotifications.get(key);
} else {
- return mNotificationData.get(key);
+ return mActiveNotifications.get(key);
}
}
@@ -608,4 +690,136 @@
}
return mNotificationRowBinder;
}
+
+ /*
+ * -----
+ * Annexed from NotificationData below:
+ * Some of these methods may be redundant but require some reworking to remove. For now
+ * we'll try to keep the behavior the same and can simplify these interfaces in another pass
+ */
+
+ /** Internalization of NotificationData#remove */
+ private void removeVisibleNotification(String key) {
+ // no need to synchronize if we're on the main thread dawg
+ Assert.isMainThread();
+
+ NotificationEntry removed = mActiveNotifications.remove(key);
+
+ if (removed == null) return;
+ mGroupManager.onEntryRemoved(removed);
+ }
+
+ /** @return list of active notifications filtered for the current user */
+ public List<NotificationEntry> getActiveNotificationsForCurrentUser() {
+ Assert.isMainThread();
+ ArrayList<NotificationEntry> filtered = new ArrayList<>();
+
+ final int len = mActiveNotifications.size();
+ for (int i = 0; i < len; i++) {
+ NotificationEntry entry = mActiveNotifications.valueAt(i);
+ final StatusBarNotification sbn = entry.getSbn();
+ if (!mKeyguardEnvironment.isNotificationForCurrentProfiles(sbn)) {
+ continue;
+ }
+ filtered.add(entry);
+ }
+
+ return filtered;
+ }
+
+ //TODO: Get rid of this in favor of NotificationUpdateHandler#updateNotificationRanking
+ /**
+ * @param rankingMap the {@link RankingMap} to apply to the current notification list
+ * @param reason the reason for calling this method, for {@link NotifLog}
+ */
+ public void updateRanking(RankingMap rankingMap, String reason) {
+ updateRankingAndSort(rankingMap, reason);
+ }
+
+ /** Resorts / filters the current notification set with the current RankingMap */
+ public void reapplyFilterAndSort(String reason) {
+ updateRankingAndSort(mRankingManager.getRankingMap(), reason);
+ }
+
+ /** Calls to NotificationRankingManager and updates mSortedAndFiltered */
+ private void updateRankingAndSort(@NonNull RankingMap rankingMap, String reason) {
+ mSortedAndFiltered.clear();
+ mSortedAndFiltered.addAll(mRankingManager.updateRanking(
+ rankingMap, mActiveNotifications.values(), reason));
+ }
+
+ /** dump the current active notification list. Called from StatusBar */
+ public void dump(PrintWriter pw, String indent) {
+ pw.println("NotificationEntryManager");
+ int filteredLen = mSortedAndFiltered.size();
+ pw.print(indent);
+ pw.println("active notifications: " + filteredLen);
+ int active;
+ for (active = 0; active < filteredLen; active++) {
+ NotificationEntry e = mSortedAndFiltered.get(active);
+ dumpEntry(pw, indent, active, e);
+ }
+ synchronized (mActiveNotifications) {
+ int totalLen = mActiveNotifications.size();
+ pw.print(indent);
+ pw.println("inactive notifications: " + (totalLen - active));
+ int inactiveCount = 0;
+ for (int i = 0; i < totalLen; i++) {
+ NotificationEntry entry = mActiveNotifications.valueAt(i);
+ if (!mSortedAndFiltered.contains(entry)) {
+ dumpEntry(pw, indent, inactiveCount, entry);
+ inactiveCount++;
+ }
+ }
+ }
+ }
+
+ private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
+ pw.print(indent);
+ pw.println(" [" + i + "] key=" + e.getKey() + " icon=" + e.icon);
+ StatusBarNotification n = e.getSbn();
+ pw.print(indent);
+ pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
+ + e.getRanking().getImportance());
+ pw.print(indent);
+ pw.println(" notification=" + n.getNotification());
+ }
+
+ /**
+ * This is the answer to the question "what notifications should the user be seeing right now?"
+ * These are sorted and filtered, and directly inform the notification shade what to show
+ *
+ * @return A read-only list of the currently active notifications
+ */
+ public List<NotificationEntry> getVisibleNotifications() {
+ return mReadOnlyNotifications;
+ }
+
+ /** @return A count of the active notifications */
+ public int getActiveNotificationsCount() {
+ return mReadOnlyNotifications.size();
+ }
+
+ /**
+ * @return {@code true} if there is at least one notification that should be visible right now
+ */
+ public boolean hasActiveNotifications() {
+ return mReadOnlyNotifications.size() != 0;
+ }
+
+ /*
+ * End annexation
+ * -----
+ */
+
+
+ /**
+ * Provides access to keyguard state and user settings dependent data.
+ */
+ public interface KeyguardEnvironment {
+ /** true if the device is provisioned (should always be true in practice) */
+ boolean isDeviceProvisioned();
+ /** true if the notification is for the current profiles */
+ boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index b116409..e5f44bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -28,7 +28,6 @@
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -44,7 +43,7 @@
private final NotificationGroupManager mGroupManager = Dependency.get(
NotificationGroupManager.class);
- private NotificationData.KeyguardEnvironment mEnvironment;
+ private NotificationEntryManager.KeyguardEnvironment mEnvironment;
private ShadeController mShadeController;
private ForegroundServiceController mFsc;
private NotificationLockscreenUserManager mUserManager;
@@ -52,9 +51,9 @@
@Inject
public NotificationFilter() {}
- private NotificationData.KeyguardEnvironment getEnvironment() {
+ private NotificationEntryManager.KeyguardEnvironment getEnvironment() {
if (mEnvironment == null) {
- mEnvironment = Dependency.get(NotificationData.KeyguardEnvironment.class);
+ mEnvironment = Dependency.get(NotificationEntryManager.KeyguardEnvironment.class);
}
return mEnvironment;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
deleted file mode 100644
index a0229d1..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Copyright (C) 2019 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.statusbar.notification.collection;
-
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.Person;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.logging.NotifEvent;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-
-import javax.inject.Inject;
-
-/**
- * The list of currently displaying notifications.
- */
-public class NotificationData {
- private static final String TAG = "NotificationData";
-
- private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
-
- /**
- * These dependencies are late init-ed
- */
- private KeyguardEnvironment mEnvironment;
- private NotificationMediaManager mMediaManager;
-
- private HeadsUpManager mHeadsUpManager;
-
- private final ArrayMap<String, NotificationEntry> mEntries = new ArrayMap<>();
- private final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
-
- private final NotificationGroupManager mGroupManager =
- Dependency.get(NotificationGroupManager.class);
-
- private RankingMap mRankingMap;
- private final Ranking mTmpRanking = new Ranking();
- private final boolean mUsePeopleFiltering;
- private final NotifLog mNotifLog;
- private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
-
- @Inject
- public NotificationData(
- NotificationSectionsFeatureManager sectionsFeatureManager,
- NotifLog notifLog,
- PeopleNotificationIdentifier peopleNotificationIdentifier) {
- mUsePeopleFiltering = sectionsFeatureManager.isFilteringEnabled();
- mNotifLog = notifLog;
- mPeopleNotificationIdentifier = peopleNotificationIdentifier;
- }
-
- public void setHeadsUpManager(HeadsUpManager headsUpManager) {
- mHeadsUpManager = headsUpManager;
- }
-
- @VisibleForTesting
- protected final Comparator<NotificationEntry> mRankingComparator =
- new Comparator<NotificationEntry>() {
- @Override
- public int compare(NotificationEntry a, NotificationEntry b) {
- final StatusBarNotification na = a.getSbn();
- final StatusBarNotification nb = b.getSbn();
- int aRank = getRank(a.getKey());
- int bRank = getRank(b.getKey());
-
- boolean aPeople = isPeopleNotification(a);
- boolean bPeople = isPeopleNotification(b);
-
- boolean aMedia = isImportantMedia(a);
- boolean bMedia = isImportantMedia(b);
-
- boolean aSystemMax = isSystemMax(a);
- boolean bSystemMax = isSystemMax(b);
-
- boolean aHeadsUp = a.isRowHeadsUp();
- boolean bHeadsUp = b.isRowHeadsUp();
-
- if (mUsePeopleFiltering && aPeople != bPeople) {
- return aPeople ? -1 : 1;
- } else if (aHeadsUp != bHeadsUp) {
- return aHeadsUp ? -1 : 1;
- } else if (aHeadsUp) {
- // Provide consistent ranking with headsUpManager
- return mHeadsUpManager.compare(a, b);
- } else if (aMedia != bMedia) {
- // Upsort current media notification.
- return aMedia ? -1 : 1;
- } else if (aSystemMax != bSystemMax) {
- // Upsort PRIORITY_MAX system notifications
- return aSystemMax ? -1 : 1;
- } else if (a.isHighPriority() != b.isHighPriority()) {
- return -1 * Boolean.compare(a.isHighPriority(), b.isHighPriority());
- } else if (aRank != bRank) {
- return aRank - bRank;
- } else {
- return Long.compare(nb.getNotification().when, na.getNotification().when);
- }
- }
- };
-
- private KeyguardEnvironment getEnvironment() {
- if (mEnvironment == null) {
- mEnvironment = Dependency.get(KeyguardEnvironment.class);
- }
- return mEnvironment;
- }
-
- private NotificationMediaManager getMediaManager() {
- if (mMediaManager == null) {
- mMediaManager = Dependency.get(NotificationMediaManager.class);
- }
- return mMediaManager;
- }
-
- /**
- * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
- *
- * <p>
- * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
- * when the environment changes.
- * <p>
- * Don't hold on to or modify the returned list.
- */
- public ArrayList<NotificationEntry> getActiveNotifications() {
- return mSortedAndFiltered;
- }
-
- public ArrayList<NotificationEntry> getNotificationsForCurrentUser() {
- synchronized (mEntries) {
- final int len = mEntries.size();
- ArrayList<NotificationEntry> filteredForUser = new ArrayList<>(len);
-
- for (int i = 0; i < len; i++) {
- NotificationEntry entry = mEntries.valueAt(i);
- final StatusBarNotification sbn = entry.getSbn();
- if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
- continue;
- }
- filteredForUser.add(entry);
- }
- return filteredForUser;
- }
- }
-
- public NotificationEntry get(String key) {
- return mEntries.get(key);
- }
-
- public void add(NotificationEntry entry) {
- synchronized (mEntries) {
- mEntries.put(entry.getSbn().getKey(), entry);
- }
- mGroupManager.onEntryAdded(entry);
-
- updateRankingAndSort(mRankingMap, "addEntry=" + entry.getSbn());
- }
-
- public NotificationEntry remove(String key, RankingMap ranking) {
- NotificationEntry removed;
- synchronized (mEntries) {
- removed = mEntries.remove(key);
- }
- if (removed == null) return null;
- mGroupManager.onEntryRemoved(removed);
- updateRankingAndSort(ranking, "removeEntry=" + removed.getSbn());
- return removed;
- }
-
- /** Updates the given notification entry with the provided ranking. */
- public void update(
- NotificationEntry entry,
- RankingMap ranking,
- StatusBarNotification notification,
- String reason) {
- updateRanking(ranking, reason);
- final StatusBarNotification oldNotification = entry.getSbn();
- entry.setSbn(notification);
- mGroupManager.onEntryUpdated(entry, oldNotification);
- }
-
- /**
- * Update ranking and trigger a re-sort
- */
- public void updateRanking(RankingMap ranking, String reason) {
- updateRankingAndSort(ranking, reason);
- }
-
- /**
- * Returns true if this notification should be displayed in the high-priority notifications
- * section
- */
- public boolean isHighPriority(StatusBarNotification statusBarNotification) {
- if (mRankingMap != null) {
- getRanking(statusBarNotification.getKey(), mTmpRanking);
- if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
- || hasHighPriorityCharacteristics(
- mTmpRanking.getChannel(), statusBarNotification)) {
- return true;
- }
- if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
- final ArrayList<NotificationEntry> logicalChildren =
- mGroupManager.getLogicalChildren(statusBarNotification);
- for (NotificationEntry child : logicalChildren) {
- if (isHighPriority(child.getSbn())) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- private boolean hasHighPriorityCharacteristics(NotificationChannel channel,
- StatusBarNotification statusBarNotification) {
-
- if (isImportantOngoing(statusBarNotification.getNotification())
- || statusBarNotification.getNotification().hasMediaSession()
- || hasPerson(statusBarNotification.getNotification())
- || hasStyle(statusBarNotification.getNotification(),
- Notification.MessagingStyle.class)) {
- // Users who have long pressed and demoted to silent should not see the notification
- // in the top section
- if (channel != null && channel.hasUserSetImportance()) {
- return false;
- }
- return true;
- }
-
- return false;
- }
-
- private boolean isImportantOngoing(Notification notification) {
- return notification.isForegroundService()
- && mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_LOW;
- }
-
- private boolean hasStyle(Notification notification, Class targetStyle) {
- Class<? extends Notification.Style> style = notification.getNotificationStyle();
- return targetStyle.equals(style);
- }
-
- private boolean hasPerson(Notification notification) {
- // TODO: cache favorite and recent contacts to check contact affinity
- ArrayList<Person> people = notification.extras != null
- ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
- : new ArrayList<>();
- return people != null && !people.isEmpty();
- }
-
- public boolean isAmbient(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.isAmbient();
- }
- return false;
- }
-
- public int getVisibilityOverride(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getVisibilityOverride();
- }
- return Ranking.VISIBILITY_NO_OVERRIDE;
- }
-
- public List<SnoozeCriterion> getSnoozeCriteria(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getSnoozeCriteria();
- }
- return null;
- }
-
- public NotificationChannel getChannel(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getChannel();
- }
- return null;
- }
-
- public int getRank(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getRank();
- }
- return 0;
- }
-
- private boolean isImportantMedia(NotificationEntry e) {
- int importance = e.getRanking().getImportance();
- boolean media = e.getKey().equals(getMediaManager().getMediaNotificationKey())
- && importance > NotificationManager.IMPORTANCE_MIN;
-
- return media;
- }
-
- private boolean isSystemMax(NotificationEntry e) {
- int importance = e.getRanking().getImportance();
- boolean sys = importance >= NotificationManager.IMPORTANCE_HIGH
- && isSystemNotification(e.getSbn());
-
- return sys;
- }
-
- public boolean shouldHide(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.isSuspended();
- }
- return false;
- }
-
- private void updateRankingAndSort(RankingMap rankingMap, String reason) {
- if (rankingMap != null) {
- mRankingMap = rankingMap;
- synchronized (mEntries) {
- final int len = mEntries.size();
- for (int i = 0; i < len; i++) {
- NotificationEntry entry = mEntries.valueAt(i);
- Ranking newRanking = new Ranking();
- if (!getRanking(entry.getKey(), newRanking)) {
- continue;
- }
- entry.setRanking(newRanking);
-
- final StatusBarNotification oldSbn = entry.getSbn().cloneLight();
- final String overrideGroupKey = newRanking.getOverrideGroupKey();
- if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
- entry.getSbn().setOverrideGroupKey(overrideGroupKey);
- mGroupManager.onEntryUpdated(entry, oldSbn);
- }
- entry.setIsHighPriority(isHighPriority(entry.getSbn()));
- }
- }
- }
- filterAndSort(reason);
- }
-
- /**
- * Get the ranking from the current ranking map.
- *
- * @param key the key to look up
- * @param outRanking the ranking to populate
- *
- * @return {@code true} if the ranking was properly obtained.
- */
- @VisibleForTesting
- protected boolean getRanking(String key, Ranking outRanking) {
- return mRankingMap.getRanking(key, outRanking);
- }
-
- // TODO: This should not be public. Instead the Environment should notify this class when
- // anything changed, and this class should call back the UI so it updates itself.
- /**
- * Filters and sorts the list of notification entries
- */
- public void filterAndSort(String reason) {
- mNotifLog.log(NotifEvent.FILTER_AND_SORT, reason);
- mSortedAndFiltered.clear();
-
- synchronized (mEntries) {
- final int len = mEntries.size();
- for (int i = 0; i < len; i++) {
- NotificationEntry entry = mEntries.valueAt(i);
-
- if (mNotificationFilter.shouldFilterOut(entry)) {
- continue;
- }
-
- mSortedAndFiltered.add(entry);
- }
- }
-
- Collections.sort(mSortedAndFiltered, mRankingComparator);
-
- int bucket = BUCKET_PEOPLE;
- for (NotificationEntry e : mSortedAndFiltered) {
- assignBucketForEntry(e);
- if (e.getBucket() < bucket) {
- android.util.Log.wtf(TAG, "Detected non-contiguous bucket!");
- }
- bucket = e.getBucket();
- }
- }
-
- private void assignBucketForEntry(NotificationEntry e) {
- boolean isHeadsUp = e.isRowHeadsUp();
- boolean isMedia = isImportantMedia(e);
- boolean isSystemMax = isSystemMax(e);
-
- setBucket(e, isHeadsUp, isMedia, isSystemMax);
- }
-
- private void setBucket(
- NotificationEntry e,
- boolean isHeadsUp,
- boolean isMedia,
- boolean isSystemMax) {
- if (mUsePeopleFiltering && isPeopleNotification(e)) {
- e.setBucket(BUCKET_PEOPLE);
- } else if (isHeadsUp || isMedia || isSystemMax || e.isHighPriority()) {
- e.setBucket(BUCKET_ALERTING);
- } else {
- e.setBucket(BUCKET_SILENT);
- }
- }
-
- private boolean isPeopleNotification(NotificationEntry e) {
- return mPeopleNotificationIdentifier.isPeopleNotification(e.getSbn());
- }
-
- public void dump(PrintWriter pw, String indent) {
- int filteredLen = mSortedAndFiltered.size();
- pw.print(indent);
- pw.println("active notifications: " + filteredLen);
- int active;
- for (active = 0; active < filteredLen; active++) {
- NotificationEntry e = mSortedAndFiltered.get(active);
- dumpEntry(pw, indent, active, e);
- }
- synchronized (mEntries) {
- int totalLen = mEntries.size();
- pw.print(indent);
- pw.println("inactive notifications: " + (totalLen - active));
- int inactiveCount = 0;
- for (int i = 0; i < totalLen; i++) {
- NotificationEntry entry = mEntries.valueAt(i);
- if (!mSortedAndFiltered.contains(entry)) {
- dumpEntry(pw, indent, inactiveCount, entry);
- inactiveCount++;
- }
- }
- }
- }
-
- private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
- getRanking(e.getKey(), mTmpRanking);
- pw.print(indent);
- pw.println(" [" + i + "] key=" + e.getKey() + " icon=" + e.icon);
- StatusBarNotification n = e.getSbn();
- pw.print(indent);
- pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
- + mTmpRanking.getImportance());
- pw.print(indent);
- pw.println(" notification=" + n.getNotification());
- }
-
- private static boolean isSystemNotification(StatusBarNotification sbn) {
- String sbnPackage = sbn.getPackageName();
- return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage);
- }
-
- /**
- * Provides access to keyguard state and user settings dependent data.
- */
- public interface KeyguardEnvironment {
- boolean isDeviceProvisioned();
- boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
new file mode 100644
index 0000000..8bce528
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2019 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.statusbar.notification.collection
+
+import android.app.Notification
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.app.NotificationManager.IMPORTANCE_LOW
+import android.app.NotificationManager.IMPORTANCE_MIN
+import android.app.Person
+import android.service.notification.NotificationListenerService.Ranking
+import android.service.notification.NotificationListenerService.RankingMap
+import android.service.notification.StatusBarNotification
+import com.android.internal.annotations.VisibleForTesting
+
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.notification.NotificationFilter
+import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.logging.NotifEvent
+import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
+import com.android.systemui.statusbar.phone.NotificationGroupManager
+import com.android.systemui.statusbar.policy.HeadsUpManager
+
+import java.util.Objects
+import java.util.ArrayList
+
+import javax.inject.Inject
+
+import kotlin.Comparator
+
+import dagger.Lazy
+
+private const val TAG = "NotifRankingManager"
+
+/**
+ * NotificationRankingManager is responsible for holding on to the most recent [RankingMap], and
+ * updating SystemUI's set of [NotificationEntry]s with their own ranking. It also sorts and filters
+ * a set of entries (but retains none of them). We also set buckets on the entries here since
+ * bucketing is tied closely to sorting.
+ *
+ * For the curious: this class is one iteration closer to null of what used to be called
+ * NotificationData.java.
+ */
+open class NotificationRankingManager @Inject constructor(
+ private val mediaManagerLazy: Lazy<NotificationMediaManager>,
+ private val groupManager: NotificationGroupManager,
+ private val headsUpManager: HeadsUpManager,
+ private val notifFilter: NotificationFilter,
+ private val notifLog: NotifLog,
+ sectionsFeatureManager: NotificationSectionsFeatureManager
+) {
+
+ var rankingMap: RankingMap? = null
+ protected set
+ private val mediaManager by lazy {
+ mediaManagerLazy.get()
+ }
+ private val usePeopleFiltering: Boolean = sectionsFeatureManager.isFilteringEnabled()
+ private val rankingComparator: Comparator<NotificationEntry> = Comparator { a, b ->
+ val na = a.sbn
+ val nb = b.sbn
+ val aRank = a.ranking.rank
+ val bRank = b.ranking.rank
+
+ val aMedia = isImportantMedia(a)
+ val bMedia = isImportantMedia(b)
+
+ val aSystemMax = a.isSystemMax()
+ val bSystemMax = b.isSystemMax()
+
+ val aHeadsUp = a.isRowHeadsUp
+ val bHeadsUp = b.isRowHeadsUp
+
+ if (usePeopleFiltering && a.isPeopleNotification() != b.isPeopleNotification()) {
+ if (a.isPeopleNotification()) -1 else 1
+ } else if (aHeadsUp != bHeadsUp) {
+ if (aHeadsUp) -1 else 1
+ } else if (aHeadsUp) {
+ // Provide consistent ranking with headsUpManager
+ headsUpManager.compare(a, b)
+ } else if (aMedia != bMedia) {
+ // Upsort current media notification.
+ if (aMedia) -1 else 1
+ } else if (aSystemMax != bSystemMax) {
+ // Upsort PRIORITY_MAX system notifications
+ if (aSystemMax) -1 else 1
+ } else if (a.isHighPriority != b.isHighPriority) {
+ -1 * java.lang.Boolean.compare(a.isHighPriority, b.isHighPriority)
+ } else if (aRank != bRank) {
+ aRank - bRank
+ } else {
+ nb.notification.`when`.compareTo(na.notification.`when`)
+ }
+ }
+
+ private fun isImportantMedia(entry: NotificationEntry): Boolean {
+ val importance = entry.ranking.importance
+ return entry.key == mediaManager.mediaNotificationKey && importance > IMPORTANCE_MIN
+ }
+
+ @VisibleForTesting
+ protected fun isHighPriority(entry: NotificationEntry): Boolean {
+ if (entry.importance >= IMPORTANCE_DEFAULT ||
+ hasHighPriorityCharacteristics(entry)) {
+ return true
+ }
+
+ if (groupManager.isSummaryOfGroup(entry.sbn)) {
+ val logicalChildren = groupManager.getLogicalChildren(entry.sbn)
+ for (child in logicalChildren) {
+ if (isHighPriority(child)) {
+ return true
+ }
+ }
+ }
+
+ return false
+ }
+
+ private fun hasHighPriorityCharacteristics(entry: NotificationEntry): Boolean {
+ val c = entry.channel
+ val n = entry.sbn.notification
+
+ if (((n.isForegroundService && entry.ranking.importance >= IMPORTANCE_LOW) ||
+ n.hasMediaSession() ||
+ n.hasPerson() ||
+ n.hasStyle(Notification.MessagingStyle::class.java))) {
+ // Users who have long pressed and demoted to silent should not see the notification
+ // in the top section
+ if (c != null && c.hasUserSetImportance()) {
+ return false
+ }
+
+ return true
+ }
+
+ return false
+ }
+
+ fun updateRanking(
+ newRankingMap: RankingMap?,
+ entries: Collection<NotificationEntry>,
+ reason: String
+ ): List<NotificationEntry> {
+ val eSeq = entries.asSequence()
+
+ // TODO: may not be ideal to guard on null here, but this code is implementing exactly what
+ // NotificationData used to do
+ if (newRankingMap != null) {
+ rankingMap = newRankingMap
+ updateRankingForEntries(eSeq)
+ }
+
+ val filtered: Sequence<NotificationEntry>
+ synchronized(this) {
+ filtered = filterAndSortLocked(eSeq, reason)
+ }
+
+ return filtered.toList()
+ }
+
+ /** Uses the [rankingComparator] to sort notifications which aren't filtered */
+ private fun filterAndSortLocked(
+ entries: Sequence<NotificationEntry>,
+ reason: String
+ ): Sequence<NotificationEntry> {
+ notifLog.log(NotifEvent.FILTER_AND_SORT, reason)
+
+ return entries.filter { !notifFilter.shouldFilterOut(it) }
+ .sortedWith(rankingComparator)
+ .map {
+ assignBucketForEntry(it)
+ it
+ }
+ }
+
+ private fun assignBucketForEntry(entry: NotificationEntry) {
+ val isHeadsUp = entry.isRowHeadsUp
+ val isMedia = isImportantMedia(entry)
+ val isSystemMax = entry.isSystemMax()
+ setBucket(entry, isHeadsUp, isMedia, isSystemMax)
+ }
+
+ private fun setBucket(
+ entry: NotificationEntry,
+ isHeadsUp: Boolean,
+ isMedia: Boolean,
+ isSystemMax: Boolean
+ ) {
+ if (usePeopleFiltering && entry.hasAssociatedPeople()) {
+ entry.bucket = BUCKET_PEOPLE
+ } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority) {
+ entry.bucket = BUCKET_ALERTING
+ } else {
+ entry.bucket = BUCKET_SILENT
+ }
+ }
+
+ private fun updateRankingForEntries(entries: Sequence<NotificationEntry>) {
+ rankingMap?.let { rankingMap ->
+ synchronized(entries) {
+ entries.forEach { entry ->
+ val newRanking = Ranking()
+ if (!rankingMap.getRanking(entry.key, newRanking)) {
+ return@forEach
+ }
+ entry.ranking = newRanking
+
+ val oldSbn = entry.sbn.cloneLight()
+ val newOverrideGroupKey = newRanking.overrideGroupKey
+ if (!Objects.equals(oldSbn.overrideGroupKey, newOverrideGroupKey)) {
+ entry.sbn.overrideGroupKey = newOverrideGroupKey
+ // TODO: notify group manager here?
+ groupManager.onEntryUpdated(entry, oldSbn)
+ }
+ entry.setIsHighPriority(isHighPriority(entry))
+ }
+ }
+ }
+ }
+}
+
+// Convenience functions
+private fun NotificationEntry.isSystemMax(): Boolean {
+ return importance >= IMPORTANCE_HIGH && sbn.isSystemNotification()
+}
+
+private fun StatusBarNotification.isSystemNotification(): Boolean {
+ return "android" == packageName || "com.android.systemui" == packageName
+}
+
+private fun Notification.hasPerson(): Boolean {
+ val people: ArrayList<Person> =
+ (extras?.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)) ?: ArrayList()
+ return people.isNotEmpty()
+}
+
+private fun Notification.hasStyle(targetStyleClass: Class<*>): Boolean {
+ return targetStyleClass == notificationStyle
+}
+
+private fun NotificationEntry.isPeopleNotification(): Boolean =
+ sbn.notification.hasStyle(Notification.MessagingStyle::class.java)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 52fd079..1c0a9d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -32,7 +32,6 @@
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.UiOffloadThread;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -61,7 +60,6 @@
Dependency.get(NotificationGroupManager.class);
private final NotificationGutsManager mGutsManager =
Dependency.get(NotificationGutsManager.class);
- private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
Dependency.get(NotificationInterruptionStateProvider.class);
@@ -81,16 +79,20 @@
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
private BindRowCallback mBindRowCallback;
private NotificationClicker mNotificationClicker;
- private final NotificationLogger mNotificationLogger = Dependency.get(NotificationLogger.class);
+ private final NotificationLogger mNotificationLogger;
- public NotificationRowBinderImpl(Context context, boolean allowLongPress,
+ public NotificationRowBinderImpl(
+ Context context,
+ boolean allowLongPress,
KeyguardBypassController keyguardBypassController,
- StatusBarStateController statusBarStateController) {
+ StatusBarStateController statusBarStateController,
+ NotificationLogger logger) {
mContext = context;
mMessagingUtil = new NotificationMessagingUtil(context);
mAllowLongPress = allowLongPress;
mKeyguardBypassController = keyguardBypassController;
mStatusBarStateController = statusBarStateController;
+ mNotificationLogger = logger;
}
private NotificationRemoteInputManager getRemoteInputManager() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 90c5502..77ccf19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -43,9 +43,9 @@
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import javax.inject.Inject;
@@ -113,7 +113,7 @@
public void run() {
mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
- // 1. Loop over mNotificationData entries:
+ // 1. Loop over active entries:
// A. Keep list of visible notifications.
// B. Keep list of previously hidden, now visible notifications.
// 2. Compute no-longer visible notifications by removing currently
@@ -121,8 +121,7 @@
// notifications.
// 3. Report newly visible and no-longer visible notifications.
// 4. Keep currently visible notifications for next report.
- ArrayList<NotificationEntry> activeNotifications = mEntryManager
- .getNotificationData().getActiveNotifications();
+ List<NotificationEntry> activeNotifications = mEntryManager.getVisibleNotifications();
int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
NotificationEntry entry = activeNotifications.get(i);
@@ -403,7 +402,7 @@
*/
public void onExpansionChanged(String key, boolean isUserAction, boolean isExpanded) {
NotificationVisibility.NotificationLocation location =
- getNotificationLocation(mEntryManager.getNotificationData().get(key));
+ getNotificationLocation(mEntryManager.getActiveNotificationUnfiltered(key));
mExpansionStateLogger.onExpansionChanged(key, isUserAction, isExpanded, location);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 0d8e30e..462fa59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -696,8 +696,7 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL);
- boolean showFooterView = (showDismissView ||
- mEntryManager.getNotificationData().getActiveNotifications().size() != 0)
+ boolean showFooterView = (showDismissView || mEntryManager.hasActiveNotifications())
&& mStatusBarState != StatusBarState.KEYGUARD
&& !mRemoteInputManager.getController().isRemoteInputActive();
@@ -5787,11 +5786,6 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public boolean hasActiveNotifications() {
- return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateSpeedBumpIndex() {
int speedBumpIndex = 0;
int currentIndex = 0;
@@ -6400,7 +6394,7 @@
@Override
public boolean onDraggedDown(View startingChild, int dragLengthY) {
if (mStatusBarState == StatusBarState.KEYGUARD
- && hasActiveNotifications()) {
+ && mEntryManager.hasActiveNotifications()) {
mLockscreenGestureLogger.write(
MetricsEvent.ACTION_LS_SHADE,
(int) (dragLengthY / mDisplayMetrics.density),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
index 2c931ae..e763496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
@@ -22,7 +22,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import javax.inject.Inject;
@@ -42,12 +42,12 @@
public KeyguardEnvironmentImpl() {
}
- @Override // NotificationData.KeyguardEnvironment
+ @Override // NotificationEntryManager.KeyguardEnvironment
public boolean isDeviceProvisioned() {
return mDeviceProvisionedController.isDeviceProvisioned();
}
- @Override // NotificationData.KeyguardEnvironment
+ @Override // NotificationEntryManager.KeyguardEnvironment
public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
final int notificationUserId = n.getUserId();
if (DEBUG && MULTIUSER_DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
index 93887a6..5703f06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
@@ -97,7 +97,7 @@
}
private boolean hasActiveNotifications() {
- return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
+ return mEntryManager.hasActiveNotifications();
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 1e10b6f..3554b54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -15,7 +15,6 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -26,7 +25,6 @@
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -48,7 +46,6 @@
private static final long AOD_ICONS_APPEAR_DURATION = 200;
private final ContrastColorUtil mContrastColorUtil;
- private final NotificationEntryManager mEntryManager;
private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
private final StatusBarStateController mStatusBarStateController;
private final NotificationMediaManager mMediaManager;
@@ -91,7 +88,6 @@
mStatusBar = statusBar;
mContrastColorUtil = ContrastColorUtil.getInstance(context);
mContext = context;
- mEntryManager = Dependency.get(NotificationEntryManager.class);
mStatusBarStateController = statusBarStateController;
mStatusBarStateController.addCallback(this);
mMediaManager = notificationMediaManager;
@@ -247,7 +243,7 @@
if (hideCenteredIcon && isCenteredNotificationIcon && !entry.isRowHeadsUp()) {
return false;
}
- if (mEntryManager.getNotificationData().isAmbient(entry.getKey()) && !showAmbient) {
+ if (entry.getRanking().isAmbient() && !showAmbient) {
return false;
}
if (hideCurrentMedia && entry.getKey().equals(mMediaManager.getMediaNotificationKey())) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 6839fb4..6176cff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -3562,8 +3562,7 @@
private void updateShowEmptyShadeView() {
boolean showEmptyShadeView =
- mBarState != StatusBarState.KEYGUARD &&
- mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
+ mBarState != StatusBarState.KEYGUARD && mEntryManager.hasActiveNotifications();
showEmptyShadeView(showEmptyShadeView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 0e1985d..adea8c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1228,7 +1228,8 @@
mContext,
mAllowNotificationLongPress,
mKeyguardBypassController,
- mStatusBarStateController);
+ mStatusBarStateController,
+ mNotificationLogger);
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
@@ -2494,8 +2495,8 @@
}
if (DUMPTRUCK) {
- synchronized (mEntryManager.getNotificationData()) {
- mEntryManager.getNotificationData().dump(pw, " ");
+ synchronized (mEntryManager) {
+ mEntryManager.dump(pw, " ");
}
if (false) {
@@ -2753,11 +2754,7 @@
};
public void resetUserExpandedStates() {
- ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
- .getActiveNotifications();
- final int notificationCount = activeNotifications.size();
- for (int i = 0; i < notificationCount; i++) {
- NotificationEntry entry = activeNotifications.get(i);
+ for (NotificationEntry entry : mEntryManager.getVisibleNotifications()) {
entry.resetUserExpansion();
}
}
@@ -2857,8 +2854,7 @@
try {
// consider the transition from peek to expanded to be a panel open,
// but not one that clears notification effects.
- int notificationLoad = mEntryManager.getNotificationData()
- .getActiveNotifications().size();
+ int notificationLoad = mEntryManager.getActiveNotificationsCount();
mBarService.onPanelRevealed(false, notificationLoad);
} catch (RemoteException ex) {
// Won't fail unless the world has ended.
@@ -2876,8 +2872,7 @@
!mPresenter.isPresenterFullyCollapsed() &&
(mState == StatusBarState.SHADE
|| mState == StatusBarState.SHADE_LOCKED);
- int notificationLoad = mEntryManager.getNotificationData().getActiveNotifications()
- .size();
+ int notificationLoad = mEntryManager.getActiveNotificationsCount();
if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) {
notificationLoad = 1;
}
@@ -3862,10 +3857,6 @@
mScreenPinningRequest.showPrompt(taskId, allowCancel);
}
- public boolean hasActiveNotifications() {
- return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
- }
-
@Override
public void appTransitionCancelled(int displayId) {
if (displayId == mDisplayId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 64a45e1..1cf43cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -326,12 +326,14 @@
collapseOnMainThread();
}
- final int count =
- mEntryManager.getNotificationData().getActiveNotifications().size();
- final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
+ //TODO(b/144306683): prove that this `activeEntry` is the same as `entry` above and simplify
+ // this call stack
+ NotificationEntry activeEntry =
+ mEntryManager.getActiveNotificationUnfiltered(notificationKey);
+ final int count = mEntryManager.getActiveNotificationsCount();
+ final int rank = activeEntry != null ? activeEntry.getRanking().getRank() : 0;
NotificationVisibility.NotificationLocation location =
- NotificationLogger.getNotificationLocation(
- mEntryManager.getNotificationData().get(notificationKey));
+ NotificationLogger.getNotificationLocation(activeEntry);
final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
rank, count, true, location);
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 38ff862..30e26e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -75,7 +75,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import java.util.ArrayList;
+import java.util.List;
public class StatusBarNotificationPresenter implements NotificationPresenter,
ConfigurationController.ConfigurationListener,
@@ -252,8 +252,8 @@
}
private void updateNotificationOnUiModeChanged() {
- ArrayList<NotificationEntry> userNotifications
- = mEntryManager.getNotificationData().getNotificationsForCurrentUser();
+ List<NotificationEntry> userNotifications =
+ mEntryManager.getActiveNotificationsForCurrentUser();
for (int i = 0; i < userNotifications.size(); i++) {
NotificationEntry entry = userNotifications.get(i);
ExpandableNotificationRow row = entry.getRow();
@@ -264,8 +264,8 @@
}
private void updateNotificationsOnDensityOrFontScaleChanged() {
- ArrayList<NotificationEntry> userNotifications =
- mEntryManager.getNotificationData().getNotificationsForCurrentUser();
+ List<NotificationEntry> userNotifications =
+ mEntryManager.getActiveNotificationsForCurrentUser();
for (int i = 0; i < userNotifications.size(); i++) {
NotificationEntry entry = userNotifications.get(i);
entry.onDensityOrFontScaleChanged();
@@ -326,7 +326,7 @@
}
public boolean hasActiveNotifications() {
- return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
+ return mEntryManager.hasActiveNotifications();
}
public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {