diff options
| author | 2019-11-14 15:10:24 +0000 | |
|---|---|---|
| committer | 2019-11-14 15:10:24 +0000 | |
| commit | bc657ffff44c8d77b025c87d4b0521db8991b4bf (patch) | |
| tree | 99faf52787a458c3bcde7278ac5560eb9535e26e | |
| parent | ccfc2e8255c6961971d08d3501c2d74f3ee7bcaa (diff) | |
| parent | 181de6242c77ae2d6e9195e55c12a9495d12dd34 (diff) | |
Merge "Remove NotificationData"
49 files changed, 1483 insertions, 1596 deletions
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index 91d00262dc18..818fdeaef8db 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -38,7 +38,6 @@ import com.android.systemui.statusbar.car.CarStatusBar; import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager; 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.phone.KeyguardEnvironmentImpl; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; @@ -101,7 +100,7 @@ abstract class CarSystemUIModule { abstract DockManager bindDockManager(DockManagerImpl dockManager); @Binds - abstract NotificationData.KeyguardEnvironment bindKeyguardEnvironment( + abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment( KeyguardEnvironmentImpl keyguardEnvironment); @Binds diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java index 53a88a9a54e9..ed945e7d4e72 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java @@ -19,8 +19,9 @@ import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; import com.android.systemui.statusbar.notification.logging.NotifLog; +import com.android.systemui.statusbar.phone.NotificationGroupManager; import javax.inject.Inject; import javax.inject.Singleton; @@ -35,8 +36,12 @@ import javax.inject.Singleton; public class CarNotificationEntryManager extends NotificationEntryManager { @Inject - public CarNotificationEntryManager(NotificationData notificationData, NotifLog notifLog) { - super(notificationData, notifLog); + public CarNotificationEntryManager( + NotifLog notifLog, + NotificationGroupManager groupManager, + NotificationRankingManager rankingManager, + KeyguardEnvironment keyguardEnvironment) { + super(notifLog, groupManager, rankingManager, keyguardEnvironment); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index dca5c8a5a36f..1a0690c1a273 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.SmartReplyController; 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 385de4acfea8..15a5c2773f0b 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java @@ -139,8 +139,7 @@ public class ForegroundServiceController { // 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 9f7bdd43fb11..1052a991dff8 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.NotificationRemoveInterceptor; 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 @@ public class BubbleController implements ConfigurationController.ConfigurationLi * @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 class BubbleController implements ConfigurationController.ConfigurationLi 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 @@ public class BubbleController implements ConfigurationController.ConfigurationLi 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 @@ public class BubbleController implements ConfigurationController.ConfigurationLi 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 6744d74004f0..7007f9defee6 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.StatusBarStateControllerImpl; 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.ExtensionController; 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 @@ public abstract class DependencyBinder { @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 48c72d311b1c..f1d02bb61ef9 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.stackdivider.Divider; 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 class SystemUIDefaultModule { 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 c4de2d3572bd..98a267599f7e 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 @@ public class NotificationListener extends NotificationListenerWithPlugins { } 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 @@ public class NotificationListener extends NotificationListenerWithPlugins { 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 571d3d7a11be..021e7e15c7f6 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 @@ public class NotificationLockscreenUserManagerImpl implements 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 @@ public class NotificationLockscreenUserManagerImpl implements } } 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 @@ public class NotificationLockscreenUserManagerImpl implements 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 @@ public class NotificationLockscreenUserManagerImpl implements && hideSilentNotificationsOnLockscreen()) { exceedsPriorityThreshold = entry.getBucket() != BUCKET_SILENT; } else { - exceedsPriorityThreshold = - !getEntryManager().getNotificationData().isAmbient(entry.getKey()); + exceedsPriorityThreshold = !entry.getRanking().isAmbient(); } return mShowLockscreenNotifications && exceedsPriorityThreshold; } @@ -467,8 +467,9 @@ public class NotificationLockscreenUserManagerImpl implements 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 d668665f062c..a98f826c0284 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 @@ public class NotificationMediaManager implements Dumpable { } - // 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 @@ public class NotificationMediaManager implements Dumpable { 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 class NotificationMediaManager implements Dumpable { 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 35f06f9d95c8..e10d27b241cc 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 @@ public class NotificationRemoteInputManager implements Dumpable { 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 @@ public class NotificationRemoteInputManager implements Dumpable { } 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 20a3e35791c4..ef733a967840 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 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle 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 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle } 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 7bdb21d0eac5..40f8e394f054 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 class SmartReplyController { 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 314dc04e574f..015c32348bb0 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 @@ import javax.inject.Singleton */ @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 @@ class BypassHeadsUpNotifier @Inject constructor( 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 @@ class BypassHeadsUpNotifier @Inject constructor( */ private fun canAutoHeadsUp(entry: NotificationEntry): Boolean { if (!isAutoHeadsUpAllowed()) { - return false; + return false } if (entry.isSensitive) { // filter sensitive notifications @@ -111,7 +112,7 @@ class BypassHeadsUpNotifier @Inject constructor( // 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 @@ class BypassHeadsUpNotifier @Inject constructor( /** * @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 df78fa3fd4a4..06949208c2bb 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 @@ public interface NotificationEntryListener { /** * 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 13d90ffdfca2..7a58097f3ec1 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 @@ package com.android.systemui.statusbar.notification; 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.NotificationRemoteInputManager; 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.logging.NotificationLogger; 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.Inject; 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 @@ public class NotificationEntryManager implements /** * 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 @@ public class NotificationEntryManager implements 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 @@ public class NotificationEntryManager implements @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 @@ public class NotificationEntryManager implements NotificationListContainer listContainer, HeadsUpManager headsUpManager) { mPresenter = presenter; - mNotificationData.setHeadsUpManager(headsUpManager); } /** Adds multiple {@link NotificationLifetimeExtender}s. */ @@ -188,10 +228,6 @@ public class NotificationEntryManager implements UNDEFINED_DISMISS_REASON)); } - public NotificationData getNotificationData() { - return mNotificationData; - } - @Override public void onReorderingAllowed() { updateNotifications("reordering is now allowed"); @@ -212,10 +248,17 @@ public class NotificationEntryManager implements } 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 @@ public class NotificationEntryManager implements 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 @@ public class NotificationEntryManager implements // 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 @@ public class NotificationEntryManager implements } } + /** + * 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 @@ public class NotificationEntryManager implements private void removeNotificationInternal( String key, - @Nullable NotificationListenerService.RankingMap ranking, + @Nullable RankingMap ranking, @Nullable NotificationVisibility visibility, boolean forceRemove, boolean removedByUser, @@ -300,7 +369,7 @@ public class NotificationEntryManager implements 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 @@ public class NotificationEntryManager implements // 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 @@ public class NotificationEntryManager implements * */ 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 @@ public class NotificationEntryManager implements } 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 @@ public class NotificationEntryManager implements } @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 @@ public class NotificationEntryManager implements } 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 @@ public class NotificationEntryManager implements // 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 @@ public class NotificationEntryManager implements } @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 @@ public class NotificationEntryManager implements * @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 @@ public class NotificationEntryManager implements } // 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 @@ public class NotificationEntryManager implements } } - private void updateRankingOfPendingNotifications( - @Nullable NotificationListenerService.RankingMap rankingMap) { + private void updateRankingOfPendingNotifications(@Nullable RankingMap rankingMap) { if (rankingMap == null) { return; } @@ -565,23 +635,35 @@ public class NotificationEntryManager implements } /** - * @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 @@ public class NotificationEntryManager implements } 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 b1164093acdd..e5f44bd3b9f7 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.internal.annotations.VisibleForTesting; 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 @@ public class NotificationFilter { 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 @@ public class NotificationFilter { @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 a0229d16d6eb..000000000000 --- 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 000000000000..8bce528bab8c --- /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 52fd07937546..1c0a9d4f14af 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 android.view.ViewGroup; 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 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { 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 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { 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 90c5502bd119..77ccf19f65ee 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.ExpandableViewState; 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 class NotificationLogger implements StateListener { 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 @@ public class NotificationLogger implements StateListener { // 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 class NotificationLogger implements StateListener { */ 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 0d8e30ef6988..462fa59c785c 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @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 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @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 2c931ae1c8ef..e763496da859 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 android.util.Log; 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 class KeyguardEnvironmentImpl implements KeyguardEnvironment { 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 93887a6617f9..5703f0653398 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 @@ public class LightsOutNotifController { } 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 1e10b6f025f2..3554b54db99b 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 androidx.collection.ArrayMap; 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.NotificationMediaManager; 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 @@ public class NotificationIconAreaController implements DarkReceiver, 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 @@ public class NotificationIconAreaController implements DarkReceiver, mStatusBar = statusBar; mContrastColorUtil = ContrastColorUtil.getInstance(context); mContext = context; - mEntryManager = Dependency.get(NotificationEntryManager.class); mStatusBarStateController = statusBarStateController; mStatusBarStateController.addCallback(this); mMediaManager = notificationMediaManager; @@ -247,7 +243,7 @@ public class NotificationIconAreaController implements DarkReceiver, 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 6839fb432c0a..6176cff82f6f 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 @@ public class NotificationPanelView extends PanelView implements 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 0e1985de4371..adea8c6aa014 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 @@ public class StatusBar extends SystemUI implements DemoMode, mContext, mAllowNotificationLongPress, mKeyguardBypassController, - mStatusBarStateController); + mStatusBarStateController, + mNotificationLogger); mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel, mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController, @@ -2494,8 +2495,8 @@ public class StatusBar extends SystemUI implements DemoMode, } if (DUMPTRUCK) { - synchronized (mEntryManager.getNotificationData()) { - mEntryManager.getNotificationData().dump(pw, " "); + synchronized (mEntryManager) { + mEntryManager.dump(pw, " "); } if (false) { @@ -2753,11 +2754,7 @@ public class StatusBar extends SystemUI implements DemoMode, }; 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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 @@ public class StatusBar extends SystemUI implements DemoMode, !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 @@ public class StatusBar extends SystemUI implements DemoMode, 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 64a45e16d749..1cf43cc310ba 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 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit 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 38ff86227733..30e26e57e435 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.notification.stack.NotificationListContain 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 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } 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 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } 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 class StatusBarNotificationPresenter implements NotificationPresenter, } public boolean hasActiveNotifications() { - return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty(); + return mEntryManager.hasActiveNotifications(); } public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index e63b6d6670fd..02a3766fb3b6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -102,7 +102,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { public void testAppOps_appOpAddedToForegroundNotif() { // GIVEN a notification associated with a foreground service NotificationEntry entry = addFgEntry(); - when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry); + when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(entry); // WHEN we are notified of a new app op for this notification mFsc.onAppOpChanged( @@ -123,7 +123,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { // GIVEN a foreground service associated notification that already has the correct app op NotificationEntry entry = addFgEntry(); entry.mActiveAppOps.add(AppOpsManager.OP_CAMERA); - when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry); + when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(entry); // WHEN we are notified of the same app op for this notification mFsc.onAppOpChanged( @@ -143,7 +143,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { public void testAppOps_appOpNotAddedToUnrelatedNotif() { // GIVEN no notification entries correspond to the newly updated appOp NotificationEntry entry = addFgEntry(); - when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(null); + when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(null); // WHEN a new app op is detected mFsc.onAppOpChanged( diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index a7c02045667d..8c9f75950eb4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -72,7 +72,6 @@ import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; 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.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.DozeParameters; @@ -141,8 +140,6 @@ public class BubbleControllerTest extends SysuiTestCase { private ExpandableNotificationRow mNonBubbleNotifRow; @Mock - private NotificationData mNotificationData; - @Mock private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener; @Mock private BubbleController.BubbleExpandListener mBubbleExpandListener; @@ -183,10 +180,9 @@ public class BubbleControllerTest extends SysuiTestCase { mNonBubbleNotifRow = mNotificationTestHelper.createRow(); // Return non-null notification data from the NEM - when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData); - when(mNotificationData.get(mRow.getEntry().getKey())).thenReturn(mRow.getEntry()); - when(mNotificationData.getChannel(mRow.getEntry().getKey())).thenReturn( - mRow.getEntry().getChannel()); + when(mNotificationEntryManager + .getActiveNotificationUnfiltered(mRow.getEntry().getKey())).thenReturn( + mRow.getEntry()); mZenModeConfig.suppressedVisualEffects = 0; when(mZenModeController.getConfig()).thenReturn(mZenModeConfig); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java index 86869bd65900..2f53a01b1d69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java @@ -37,7 +37,6 @@ import androidx.test.filters.SmallTest; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotificationData; import org.junit.Before; import org.junit.Test; @@ -54,7 +53,6 @@ public class NotificationListenerTest extends SysuiTestCase { @Mock private NotificationPresenter mPresenter; @Mock private NotificationListenerService.RankingMap mRanking; - @Mock private NotificationData mNotificationData; // Dependency mocks: @Mock private NotificationEntryManager mEntryManager; @@ -74,8 +72,6 @@ public class NotificationListenerTest extends SysuiTestCase { new Handler(TestableLooper.get(this).getLooper())); mContext.addMockSystemService(NotificationManager.class, mNotificationManager); - when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); - mListener = new NotificationListener(mContext); mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, new Notification(), UserHandle.CURRENT, null, 0); @@ -90,7 +86,7 @@ public class NotificationListenerTest extends SysuiTestCase { @Test public void testNotificationUpdateCallsUpdateNotification() { - when(mNotificationData.get(mSbn.getKey())) + when(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())) .thenReturn( new NotificationEntryBuilder() .setSbn(mSbn) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index 548f7a86adf3..d54e24ba2602 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar; +import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.content.Intent.ACTION_USER_SWITCHED; import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL; @@ -24,7 +25,6 @@ import static com.android.systemui.statusbar.notification.stack.NotificationSect import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -49,7 +49,6 @@ import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -72,7 +71,6 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { // Dependency mocks: @Mock private NotificationEntryManager mEntryManager; - @Mock private NotificationData mNotificationData; @Mock private DeviceProvisionedController mDeviceProvisionedController; @Mock private StatusBarKeyguardViewManager mKeyguardViewManager; @Mock private BroadcastDispatcher mBroadcastDispatcher; @@ -93,7 +91,6 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { when(mUserManager.getProfiles(mCurrentUserId)).thenReturn(Lists.newArrayList( new UserInfo(mCurrentUserId, "", 0), new UserInfo(mCurrentUserId + 1, "", 0))); - when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); mDependency.injectTestDependency(Dependency.MAIN_HANDLER, Handler.createAsync(Looper.myLooper())); @@ -170,9 +167,10 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { NOTIFICATION_NEW_INTERRUPTION_MODEL, 1); Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1); - when(mNotificationData.isHighPriority(any())).thenReturn(false); - NotificationEntry entry = new NotificationEntryBuilder().build(); + NotificationEntry entry = new NotificationEntryBuilder() + .setImportance(IMPORTANCE_LOW) + .build(); entry.setBucket(BUCKET_SILENT); assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(entry)); @@ -186,10 +184,12 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { NOTIFICATION_NEW_INTERRUPTION_MODEL, 1); Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0); - when(mNotificationData.isHighPriority(any())).thenReturn(false); - NotificationEntry entry = new NotificationEntryBuilder().build(); + NotificationEntry entry = new NotificationEntryBuilder() + .setImportance(IMPORTANCE_LOW) + .build(); entry.setBucket(BUCKET_SILENT); + entry.setIsHighPriority(true); assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(entry)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java index 90bd0e9936be..88546b9b31a7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.mock; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.Instrumentation; import android.app.Notification; import android.app.Notification.BubbleMetadata; import android.app.NotificationChannel; @@ -40,8 +39,6 @@ import android.text.TextUtils; import android.view.LayoutInflater; import android.widget.RemoteViews; -import androidx.test.InstrumentationRegistry; - import com.android.systemui.TestableDependency; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.bubbles.BubblesTestActivity; @@ -72,7 +69,6 @@ public class NotificationTestHelper { private static final String GROUP_KEY = "gruKey"; private final Context mContext; - private final Instrumentation mInstrumentation; private int mId; private final NotificationGroupManager mGroupManager; private ExpandableNotificationRow mRow; @@ -83,7 +79,7 @@ public class NotificationTestHelper { dependency.injectMockDependency(NotificationMediaManager.class); dependency.injectMockDependency(BubbleController.class); dependency.injectMockDependency(StatusBarWindowController.class); - mInstrumentation = InstrumentationRegistry.getInstrumentation(); + dependency.injectMockDependency(SmartReplyController.class); StatusBarStateController stateController = mock(StatusBarStateController.class); mGroupManager = new NotificationGroupManager(stateController); mHeadsUpManager = new HeadsUpManagerPhone(mContext, stateController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index 18649bfe68d3..99c94ac7dec2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -46,7 +46,6 @@ import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -73,7 +72,6 @@ import java.util.List; @TestableLooper.RunWithLooper public class NotificationViewHierarchyManagerTest extends SysuiTestCase { @Mock private NotificationPresenter mPresenter; - @Mock private NotificationData mNotificationData; @Spy private FakeListContainer mListContainer = new FakeListContainer(); // Dependency mocks: @@ -105,8 +103,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mHelper = new NotificationTestHelper(mContext, mDependency); - when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); - mViewHierarchyManager = new NotificationViewHierarchyManager(mContext, mHandler, mLockscreenUserManager, mGroupManager, mVisualStabilityManager, mock(StatusBarStateControllerImpl.class), mEntryManager, @@ -139,7 +135,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mListContainer.addContainerView(entry0.getRow()); mListContainer.addContainerView(entry1.getRow()); mListContainer.addContainerView(entry2.getRow()); - when(mNotificationData.getActiveNotifications()).thenReturn( + when(mEntryManager.getVisibleNotifications()).thenReturn( Lists.newArrayList(entry0, entry1, entry2)); // Set up group manager to report that they should be bundled now. @@ -168,7 +164,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { // Set up the prior state to look like one top level notification. mListContainer.addContainerView(entry0.getRow()); - when(mNotificationData.getActiveNotifications()).thenReturn( + when(mEntryManager.getVisibleNotifications()).thenReturn( Lists.newArrayList(entry0, entry1, entry2)); // Set up group manager to report that they should not be bundled now. @@ -197,7 +193,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { // Set up the prior state to look like a top level notification. mListContainer.addContainerView(entry0.getRow()); - when(mNotificationData.getActiveNotifications()).thenReturn( + when(mEntryManager.getVisibleNotifications()).thenReturn( Lists.newArrayList(entry0, entry1)); // Set up group manager to report a suppressed summary now. @@ -219,7 +215,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { public void testUpdateNotificationViews_appOps() throws Exception { NotificationEntry entry0 = createEntry(); entry0.setRow(spy(entry0.getRow())); - when(mNotificationData.getActiveNotifications()).thenReturn( + when(mEntryManager.getVisibleNotifications()).thenReturn( Lists.newArrayList(entry0)); mListContainer.addContainerView(entry0.getRow()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 86ef6e8593fc..a98945f49b99 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification; +import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.service.notification.NotificationListenerService.REASON_CANCEL; import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON; @@ -28,7 +29,6 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; @@ -40,14 +40,15 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.Notification; -import android.app.NotificationManager; +import android.app.NotificationChannel; import android.app.PendingIntent; import android.content.Intent; import android.graphics.drawable.Icon; import android.os.Handler; import android.os.Looper; 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.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -73,18 +74,18 @@ import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationRemoveInterceptor; +import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.StatusBarIconView; -import com.android.systemui.statusbar.notification.collection.NotificationData; -import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; +import com.android.systemui.statusbar.notification.NotificationEntryManager.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.collection.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.logging.NotifLog; -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.RowInflaterTask; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -93,6 +94,7 @@ import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.util.Assert; import org.junit.Before; import org.junit.Test; @@ -104,13 +106,14 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @SmallTest @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper() public class NotificationEntryManagerTest extends SysuiTestCase { private static final String TEST_PACKAGE_NAME = "test"; private static final int TEST_UID = 0; @@ -123,7 +126,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Mock private NotificationRemoveInterceptor mRemoveInterceptor; @Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback; @Mock private HeadsUpManager mHeadsUpManager; - @Mock private NotificationListenerService.RankingMap mRankingMap; + @Mock private RankingMap mRankingMap; @Mock private RemoteInputController mRemoteInputController; // Dependency mocks: @@ -139,6 +142,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Mock private SmartReplyController mSmartReplyController; @Mock private RowInflaterTask mAsyncInflationTask; @Mock private NotificationRowBinder mMockedRowBinder; + @Mock private NotifLog mNotifLog; private int mId; private NotificationEntry mEntry; @@ -146,43 +150,9 @@ public class NotificationEntryManagerTest extends SysuiTestCase { private TestableNotificationEntryManager mEntryManager; private CountDownLatch mCountDownLatch; - private class TestableNotificationEntryManager extends NotificationEntryManager { - private final CountDownLatch mCountDownLatch; - - TestableNotificationEntryManager() { - super( - new NotificationData( - mock(NotificationSectionsFeatureManager.class), - mock(NotifLog.class), - mock(PeopleNotificationIdentifier.class)), - mock(NotifLog.class)); - mCountDownLatch = new CountDownLatch(1); - } - - public void setNotificationData(NotificationData data) { - mNotificationData = data; - } - - @Override - public void onAsyncInflationFinished(NotificationEntry entry, - @InflationFlag int inflatedFlags) { - super.onAsyncInflationFinished(entry, inflatedFlags); - - mCountDownLatch.countDown(); - } - - public CountDownLatch getCountDownLatch() { - return mCountDownLatch; - } - - public ArrayList<NotificationLifetimeExtender> getLifetimeExtenders() { - return mNotificationLifetimeExtenders; - } - } - private void setUserSentiment(String key, int sentiment) { doAnswer(invocationOnMock -> { - NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking) + Ranking ranking = (Ranking) invocationOnMock.getArguments()[1]; ranking.populate( key, @@ -190,16 +160,16 @@ public class NotificationEntryManagerTest extends SysuiTestCase { false, 0, 0, - NotificationManager.IMPORTANCE_DEFAULT, + IMPORTANCE_DEFAULT, null, null, null, null, null, true, sentiment, false, -1, false, null, null, false, false); return true; - }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class)); + }).when(mRankingMap).getRanking(eq(key), any(Ranking.class)); } private void setSmartActions(String key, ArrayList<Notification.Action> smartActions) { doAnswer(invocationOnMock -> { - NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking) + Ranking ranking = (Ranking) invocationOnMock.getArguments()[1]; ranking.populate( key, @@ -207,13 +177,13 @@ public class NotificationEntryManagerTest extends SysuiTestCase { false, 0, 0, - NotificationManager.IMPORTANCE_DEFAULT, + IMPORTANCE_DEFAULT, null, null, null, null, null, true, - NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false, -1, + Ranking.USER_SENTIMENT_NEUTRAL, false, -1, false, smartActions, null, false, false); return true; - }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class)); + }).when(mRankingMap).getRanking(eq(key), any(Ranking.class)); } @Before @@ -249,7 +219,18 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntry.expandedIcon = mock(StatusBarIconView.class); - mEntryManager = new TestableNotificationEntryManager(); + mEntryManager = new TestableNotificationEntryManager( + mNotifLog, + mGroupManager, + new NotificationRankingManager( + () -> mock(NotificationMediaManager.class), + mGroupManager, + mHeadsUpManager, + mock(NotificationFilter.class), + mNotifLog, + mock(NotificationSectionsFeatureManager.class)), + mEnvironment + ); Dependency.get(InitController.class).executePostInitTasks(); mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager); mEntryManager.addNotificationEntryListener(mEntryListener); @@ -258,19 +239,19 @@ public class NotificationEntryManagerTest extends SysuiTestCase { NotificationRowBinderImpl notificationRowBinder = new NotificationRowBinderImpl(mContext, true, /* allowLongPress */ mock(KeyguardBypassController.class), - mock(StatusBarStateController.class)); + mock(StatusBarStateController.class), + mock(NotificationLogger.class)); notificationRowBinder.setUpWithPresenter( mPresenter, mListContainer, mHeadsUpManager, mEntryManager, mBindCallback); notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class)); mEntryManager.setRowBinder(notificationRowBinder); setUserSentiment( - mEntry.getKey(), NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL); + mEntry.getKey(), Ranking.USER_SENTIMENT_NEUTRAL); } @Test public void testAddNotification() throws Exception { - com.android.systemui.util.Assert.isNotMainThread(); TestableLooper.get(this).processAllMessages(); doAnswer(invocation -> { @@ -299,21 +280,20 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(mEntryListener).onNotificationAdded(entry); verify(mPresenter).updateNotificationViews(); - assertEquals(mEntryManager.getNotificationData().get(mSbn.getKey()), entry); + assertEquals(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()), entry); assertNotNull(entry.getRow()); assertEquals(mEntry.getUserSentiment(), - NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL); + Ranking.USER_SENTIMENT_NEUTRAL); } @Test public void testUpdateNotification() throws Exception { - com.android.systemui.util.Assert.isNotMainThread(); TestableLooper.get(this).processAllMessages(); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); setUserSentiment( - mEntry.getKey(), NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE); + mEntry.getKey(), Ranking.USER_SENTIMENT_NEGATIVE); mEntryManager.updateNotification(mSbn, mRankingMap); TestableLooper.get(this).processMessages(1); @@ -327,19 +307,15 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(mEntryListener).onPostEntryUpdated(mEntry); assertNotNull(mEntry.getRow()); - assertEquals(mEntry.getUserSentiment(), - NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE); + assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, + mEntry.getUserSentiment()); } @Test public void testUpdateNotification_prePostEntryOrder() throws Exception { - com.android.systemui.util.Assert.isNotMainThread(); TestableLooper.get(this).processAllMessages(); - NotificationData notifData = mock(NotificationData.class); - when(notifData.get(mEntry.getKey())).thenReturn(mEntry); - - mEntryManager.setNotificationData(notifData); + mEntryManager.addActiveNotificationForTest(mEntry); mEntryManager.updateNotification(mSbn, mRankingMap); TestableLooper.get(this).processMessages(1); @@ -349,9 +325,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(mEntryListener, never()).onInflationError(any(), any()); // Ensure that update callbacks happen in correct order - InOrder order = inOrder(mEntryListener, notifData, mPresenter, mEntryListener); + InOrder order = inOrder(mEntryListener, mPresenter, mEntryListener); order.verify(mEntryListener).onPreEntryUpdated(mEntry); - order.verify(notifData).filterAndSort(anyString()); order.verify(mPresenter).updateNotificationViews(); order.verify(mEntryListener).onPostEntryUpdated(mEntry); @@ -359,11 +334,12 @@ public class NotificationEntryManagerTest extends SysuiTestCase { } @Test - public void testRemoveNotification() throws Exception { - com.android.systemui.util.Assert.isNotMainThread(); + public void testRemoveNotification() { + // Row inflation happens off thread, so pretend that this test looper is main + Assert.sMainLooper = TestableLooper.get(this).getLooper(); mEntry.setRow(mRow); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); @@ -374,12 +350,11 @@ public class NotificationEntryManagerTest extends SysuiTestCase { eq(mEntry), any(), eq(false) /* removedByUser */); verify(mRow).setRemoved(); - assertNull(mEntryManager.getNotificationData().get(mSbn.getKey())); + assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); } @Test public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() { - com.android.systemui.util.Assert.isNotMainThread(); mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON); @@ -388,8 +363,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { } @Test - public void testRemoveNotification_whilePending() throws InterruptedException { - com.android.systemui.util.Assert.isNotMainThread(); + public void testRemoveNotification_whilePending() { mEntryManager.setRowBinder(mMockedRowBinder); @@ -408,7 +382,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntry.setRow(mRow); mEntry.setInflationTask(mAsyncInflationTask); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction()))); mEntryManager.updateNotificationRanking(mRankingMap); @@ -424,7 +398,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); mEntry.setRow(mRow); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); setSmartActions(mEntry.getKey(), null); mEntryManager.updateNotificationRanking(mRankingMap); @@ -438,7 +412,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); mEntry.setRow(null); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction()))); mEntryManager.updateNotificationRanking(mRankingMap); @@ -466,7 +440,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { public void testLifetimeExtenders_ifNotificationIsRetainedItIsntRemoved() { // GIVEN an entry manager with a notification mEntryManager.setRowBinder(mMockedRowBinder); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); // GIVEN a lifetime extender that always tries to extend lifetime NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class); @@ -479,15 +453,18 @@ public class NotificationEntryManagerTest extends SysuiTestCase { // THEN the extender is asked to manage the lifetime verify(extender).setShouldManageLifetime(mEntry, true); // THEN the notification is retained - assertNotNull(mEntryManager.getNotificationData().get(mSbn.getKey())); + assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); verify(mEntryListener, never()).onEntryRemoved(eq(mEntry), any(), eq(false)); } @Test public void testLifetimeExtenders_whenRetentionEndsNotificationIsRemoved() { + // Row inflation happens off thread, so pretend that this test looper is main + Assert.sMainLooper = TestableLooper.get(this).getLooper(); + // GIVEN an entry manager with a notification whose life has been extended mEntryManager.setRowBinder(mMockedRowBinder); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); final FakeNotificationLifetimeExtender extender = new FakeNotificationLifetimeExtender(); mEntryManager.addNotificationLifetimeExtender(extender); mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); @@ -498,7 +475,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { extender.getCallback().onSafeToRemove(mEntry.getKey()); // THEN the notification is removed - assertNull(mEntryManager.getNotificationData().get(mSbn.getKey())); + assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); verify(mEntryListener).onEntryRemoved(eq(mEntry), any(), eq(false)); } @@ -506,7 +483,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { public void testLifetimeExtenders_whenNotificationUpdatedRetainersAreCanceled() { // GIVEN an entry manager with a notification whose life has been extended mEntryManager.setRowBinder(mMockedRowBinder); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class); when(extender.shouldExtendLifetime(mEntry)).thenReturn(true); mEntryManager.addNotificationLifetimeExtender(extender); @@ -523,7 +500,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { public void testLifetimeExtenders_whenNewExtenderTakesPrecedenceOldExtenderIsCanceled() { // GIVEN an entry manager with a notification mEntryManager.setRowBinder(mMockedRowBinder); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); // GIVEN two lifetime extenders, the first which never extends and the second which // always extends @@ -554,15 +531,15 @@ public class NotificationEntryManagerTest extends SysuiTestCase { */ @Test public void testPerformRemoveNotification_removedEntry() { - mEntryManager.getNotificationData().remove(mSbn.getKey(), null /* ranking */); + mEntryManager.removeNotification(mSbn.getKey(), null, 0); mEntryManager.performRemoveNotification(mSbn, REASON_CANCEL); } @Test - public void testRemoveInterceptor_interceptsDontGetRemoved() { + public void testRemoveInterceptor_interceptsDontGetRemoved() throws InterruptedException { // GIVEN an entry manager with a notification mEntryManager.setRowBinder(mMockedRowBinder); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); // GIVEN interceptor that intercepts that entry when(mRemoveInterceptor.onNotificationRemoveRequested(eq(mEntry.getKey()), anyInt())) @@ -572,16 +549,19 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); // THEN the interceptor intercepts & the entry is not removed & no listeners are called - assertNotNull(mEntryManager.getNotificationData().get(mEntry.getKey())); + assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); verify(mEntryListener, never()).onEntryRemoved(eq(mEntry), any(NotificationVisibility.class), anyBoolean()); } @Test public void testRemoveInterceptor_notInterceptedGetsRemoved() { + // Row inflation happens off thread, so pretend that this test looper is main + Assert.sMainLooper = TestableLooper.get(this).getLooper(); + // GIVEN an entry manager with a notification mEntryManager.setRowBinder(mMockedRowBinder); - mEntryManager.getNotificationData().add(mEntry); + mEntryManager.addActiveNotificationForTest(mEntry); // GIVEN interceptor that doesn't intercept when(mRemoveInterceptor.onNotificationRemoveRequested(eq(mEntry.getKey()), anyInt())) @@ -591,7 +571,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); // THEN the interceptor intercepts & the entry is not removed & no listeners are called - assertNull(mEntryManager.getNotificationData().get(mEntry.getKey())); + assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); verify(mEntryListener, atLeastOnce()).onEntryRemoved(eq(mEntry), any(NotificationVisibility.class), anyBoolean()); } @@ -612,6 +592,63 @@ public class NotificationEntryManagerTest extends SysuiTestCase { .build(); } + /* Tests annexed from NotificationDataTest go here */ + + @Test + public void testChannelIsSetWhenAdded() { + NotificationChannel nc = new NotificationChannel( + "testId", + "testName", + IMPORTANCE_DEFAULT); + + Ranking r = new RankingBuilder() + .setKey(mEntry.getKey()) + .setChannel(nc) + .build(); + + RankingMap rm = new RankingMap(new Ranking[] { r }); + + // GIVEN: a notification is added, and the ranking updated + mEntryManager.addActiveNotificationForTest(mEntry); + mEntryManager.updateRanking(rm, "testReason"); + + // THEN the notification entry better have a channel on it + assertEquals( + "Channel must be set when adding a notification", + nc.getName(), + mEntry.getChannel().getName()); + } + + @Test + public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications() { + Assert.sMainLooper = TestableLooper.get(this).getLooper(); + Notification.Builder n = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .setContentTitle("Title") + .setContentText("Text"); + + NotificationEntry e2 = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setId(mId++) + .setNotification(n.build()) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .build(); + + mEntryManager.addActiveNotificationForTest(mEntry); + mEntryManager.addActiveNotificationForTest(e2); + + when(mEnvironment.isNotificationForCurrentProfiles(mEntry.getSbn())).thenReturn(false); + when(mEnvironment.isNotificationForCurrentProfiles(e2.getSbn())).thenReturn(true); + + List<NotificationEntry> result = mEntryManager.getActiveNotificationsForCurrentUser(); + assertEquals(result.size(), 1); + junit.framework.Assert.assertEquals(result.get(0), e2); + } + + /* End annex */ + private Notification.Action createAction() { return new Notification.Action.Builder( Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java index d85f2752a247..68730d12dee3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java @@ -44,7 +44,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationEntryBuilder; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationTestHelper; -import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -71,7 +71,7 @@ public class NotificationFilterTest extends SysuiTestCase { @Mock ForegroundServiceController mFsc; @Mock - NotificationData.KeyguardEnvironment mEnvironment; + KeyguardEnvironment mEnvironment; private final IPackageManager mMockPackageManager = mock(IPackageManager.class); private NotificationFilter mNotificationFilter; @@ -96,7 +96,7 @@ public class NotificationFilterTest extends SysuiTestCase { new NotificationGroupManager(mock(StatusBarStateController.class))); mDependency.injectMockDependency(ShadeController.class); mDependency.injectMockDependency(NotificationLockscreenUserManager.class); - mDependency.injectTestDependency(NotificationData.KeyguardEnvironment.class, mEnvironment); + mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment); when(mEnvironment.isDeviceProvisioned()).thenReturn(true); when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); mRow = new NotificationTestHelper(getContext(), mDependency).createRow(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java index cc56949d67f7..133d52b4f946 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java @@ -17,9 +17,7 @@ package com.android.systemui.statusbar.notification; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.Notification; @@ -34,14 +32,10 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationEntryBuilder; 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.notification.logging.NotifLog; -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; -import com.android.systemui.util.DeviceConfigProxyFake; import org.junit.Before; import org.junit.Test; @@ -67,13 +61,6 @@ public class NotificationListControllerTest extends SysuiTestCase { private NotificationEntryListener mEntryListener; private DeviceProvisionedListener mProvisionedListener; - // TODO: Remove this once EntryManager no longer needs to be mocked - private NotificationData mNotificationData = - new NotificationData( - new NotificationSectionsFeatureManager(new DeviceConfigProxyFake(), mContext), - mock(NotifLog.class), - mock(PeopleNotificationIdentifier.class)); - private int mNextNotifId = 0; @Before @@ -81,8 +68,6 @@ public class NotificationListControllerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mDependency.injectMockDependency(NotificationLockscreenUserManager.class); - when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); - mController = new NotificationListController( mEntryManager, mListContainer, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt new file mode 100644 index 000000000000..34beefe9843b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt @@ -0,0 +1,58 @@ +/* + * 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 + +import com.android.systemui.statusbar.NotificationPresenter +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.NotificationRankingManager +import com.android.systemui.statusbar.notification.logging.NotifLog +import com.android.systemui.statusbar.notification.stack.NotificationListContainer +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone +import com.android.systemui.statusbar.phone.NotificationGroupManager + +import java.util.concurrent.CountDownLatch + +/** + * Enable some test capabilities for NEM without making everything public on the base class + */ +class TestableNotificationEntryManager( + log: NotifLog, + gm: NotificationGroupManager, + rm: NotificationRankingManager, + ke: KeyguardEnvironment +) : NotificationEntryManager(log, gm, rm, ke) { + + public var countDownLatch: CountDownLatch = CountDownLatch(1) + + override fun onAsyncInflationFinished(entry: NotificationEntry?, inflatedFlags: Int) { + super.onAsyncInflationFinished(entry, inflatedFlags) + countDownLatch.countDown() + } + + fun setUpForTest( + presenter: NotificationPresenter?, + listContainer: NotificationListContainer?, + headsUpManager: HeadsUpManagerPhone? + ) { + super.setUpWithPresenter(presenter, listContainer, headsUpManager) + } + + fun setActiveNotificationList(activeList: List<NotificationEntry>) { + mSortedAndFiltered.clear() + mSortedAndFiltered.addAll(activeList) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java deleted file mode 100644 index 1a469d881d2c..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright (C) 2017 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 android.app.Notification.CATEGORY_ALARM; -import static android.app.Notification.CATEGORY_CALL; -import static android.app.Notification.CATEGORY_EVENT; -import static android.app.Notification.CATEGORY_MESSAGE; -import static android.app.Notification.CATEGORY_REMINDER; -import static android.app.NotificationManager.IMPORTANCE_DEFAULT; -import static android.app.NotificationManager.IMPORTANCE_LOW; -import static android.app.NotificationManager.IMPORTANCE_MIN; - -import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn; -import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_CHANNEL; -import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE; -import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_RANK; -import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS; -import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING; -import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT; - -import static junit.framework.Assert.assertEquals; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import android.Manifest; -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Person; -import android.content.Intent; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.graphics.drawable.Icon; -import android.media.session.MediaSession; -import android.os.Bundle; -import android.service.notification.NotificationListenerService; -import android.service.notification.NotificationListenerService.Ranking; -import android.service.notification.SnoozeCriterion; -import android.service.notification.StatusBarNotification; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.testing.TestableLooper.RunWithLooper; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.Dependency; -import com.android.systemui.ForegroundServiceController; -import com.android.systemui.InitController; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.NotificationEntryBuilder; -import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationTestHelper; -import com.android.systemui.statusbar.RankingBuilder; -import com.android.systemui.statusbar.SbnBuilder; -import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; -import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; -import com.android.systemui.statusbar.notification.logging.NotifLog; -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.statusbar.phone.ShadeController; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@RunWithLooper -public class NotificationDataTest extends SysuiTestCase { - - private static final int UID_NORMAL = 123; - private static final int UID_ALLOW_DURING_SETUP = 456; - private static final NotificationChannel NOTIFICATION_CHANNEL = - new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE); - - private NotificationEntry mEntry; - - @Mock - ForegroundServiceController mFsc; - @Mock - NotificationData.KeyguardEnvironment mEnvironment; - - private final IPackageManager mMockPackageManager = mock(IPackageManager.class); - private TestableNotificationData mNotificationData; - private ExpandableNotificationRow mRow; - - @Before - public void setUp() throws Exception { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); - MockitoAnnotations.initMocks(this); - - mEntry = new NotificationEntryBuilder() - .setUid(UID_NORMAL) - .build(); - - when(mMockPackageManager.checkUidPermission( - eq(Manifest.permission.NOTIFICATION_DURING_SETUP), - eq(UID_NORMAL))) - .thenReturn(PackageManager.PERMISSION_DENIED); - when(mMockPackageManager.checkUidPermission( - eq(Manifest.permission.NOTIFICATION_DURING_SETUP), - eq(UID_ALLOW_DURING_SETUP))) - .thenReturn(PackageManager.PERMISSION_GRANTED); - - mDependency.injectTestDependency(ForegroundServiceController.class, mFsc); - mDependency.injectTestDependency(NotificationGroupManager.class, - new NotificationGroupManager(mock(StatusBarStateController.class))); - mDependency.injectMockDependency(ShadeController.class); - mDependency.injectMockDependency(NotificationLockscreenUserManager.class); - mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment); - when(mEnvironment.isDeviceProvisioned()).thenReturn(true); - when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); - mNotificationData = new TestableNotificationData( - mock(NotificationSectionsFeatureManager.class)); - mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class), ""); - mRow = new NotificationTestHelper(getContext(), mDependency).createRow(); - Dependency.get(InitController.class).executePostInitTasks(); - } - - @Test - public void testChannelSetWhenAdded() { - Bundle override = new Bundle(); - override.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL); - mNotificationData.rankingOverrides.put(mRow.getEntry().getKey(), override); - mNotificationData.add(mRow.getEntry()); - assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().getChannel()); - } - - @Test - public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications() - throws Exception { - mNotificationData.add(mRow.getEntry()); - ExpandableNotificationRow row2 = new NotificationTestHelper(getContext(), mDependency) - .createRow(); - mNotificationData.add(row2.getEntry()); - - when(mEnvironment.isNotificationForCurrentProfiles( - mRow.getEntry().getSbn())).thenReturn(false); - when(mEnvironment.isNotificationForCurrentProfiles( - row2.getEntry().getSbn())).thenReturn(true); - ArrayList<NotificationEntry> result = - mNotificationData.getNotificationsForCurrentUser(); - - assertEquals(result.size(), 1); - junit.framework.Assert.assertEquals(result.get(0), row2.getEntry()); - } - - @Test - public void testIsExemptFromDndVisualSuppression_foreground() { - initStatusBarNotification(false); - - mEntry.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; - mEntry.setRow(mRow); - mNotificationData.add(mEntry); - Bundle override = new Bundle(); - override.putInt(OVERRIDE_VIS_EFFECTS, 255); - mNotificationData.rankingOverrides.put(mEntry.getKey(), override); - - assertTrue(mEntry.isExemptFromDndVisualSuppression()); - assertFalse(mEntry.shouldSuppressAmbient()); - } - - @Test - public void testIsExemptFromDndVisualSuppression_media() { - initStatusBarNotification(false); - Notification n = mEntry.getSbn().getNotification(); - Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n); - nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); - n = nb.build(); - modifySbn(mEntry) - .setNotification(n) - .build(); - mEntry.setRow(mRow); - mNotificationData.add(mEntry); - Bundle override = new Bundle(); - override.putInt(OVERRIDE_VIS_EFFECTS, 255); - mNotificationData.rankingOverrides.put(mEntry.getKey(), override); - - assertTrue(mEntry.isExemptFromDndVisualSuppression()); - assertFalse(mEntry.shouldSuppressAmbient()); - } - - @Test - public void testIsExemptFromDndVisualSuppression_system() { - initStatusBarNotification(false); - mEntry.setRow(mRow); - mEntry.mIsSystemNotification = true; - mNotificationData.add(mEntry); - Bundle override = new Bundle(); - override.putInt(OVERRIDE_VIS_EFFECTS, 255); - mNotificationData.rankingOverrides.put(mEntry.getKey(), override); - - assertTrue(mEntry.isExemptFromDndVisualSuppression()); - assertFalse(mEntry.shouldSuppressAmbient()); - } - - @Test - public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() { - initStatusBarNotification(false); - NotificationEntry entry = new NotificationEntryBuilder() - .setUid(UID_NORMAL) - .build(); - entry.setRow(mRow); - entry.mIsSystemNotification = true; - Bundle override = new Bundle(); - override.putInt(OVERRIDE_VIS_EFFECTS, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT); - mNotificationData.rankingOverrides.put(entry.getKey(), override); - mNotificationData.add(entry); - - modifySbn(entry) - .setNotification( - new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build()) - .build(); - assertFalse(entry.isExemptFromDndVisualSuppression()); - assertTrue(entry.shouldSuppressAmbient()); - - modifySbn(entry) - .setNotification( - new Notification.Builder(mContext, "") - .setCategory(CATEGORY_REMINDER) - .build()) - .build(); - assertFalse(entry.isExemptFromDndVisualSuppression()); - - modifySbn(entry) - .setNotification( - new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build()) - .build(); - assertFalse(entry.isExemptFromDndVisualSuppression()); - - modifySbn(entry) - .setNotification( - new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build()) - .build(); - assertFalse(entry.isExemptFromDndVisualSuppression()); - - modifySbn(entry) - .setNotification( - new Notification.Builder(mContext, "") - .setCategory(CATEGORY_MESSAGE) - .build()) - .build(); - assertFalse(entry.isExemptFromDndVisualSuppression()); - } - - @Test - public void testCreateNotificationDataEntry_RankingUpdate() { - StatusBarNotification sbn = new SbnBuilder().build(); - sbn.getNotification().actions = - new Notification.Action[] { createContextualAction("appGeneratedAction") }; - - ArrayList<Notification.Action> systemGeneratedSmartActions = - createActions("systemGeneratedAction"); - - SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation"); - ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>(); - snoozeCriterions.add(snoozeCriterion); - - Ranking ranking = new RankingBuilder() - .setKey(sbn.getKey()) - .setSmartActions(systemGeneratedSmartActions) - .setChannel(NOTIFICATION_CHANNEL) - .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE) - .setSnoozeCriteria(snoozeCriterions) - .build(); - - NotificationEntry entry = - new NotificationEntry(sbn, ranking); - - assertEquals(systemGeneratedSmartActions, entry.getSmartActions()); - assertEquals(NOTIFICATION_CHANNEL, entry.getChannel()); - assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.getUserSentiment()); - assertEquals(snoozeCriterions, entry.getSnoozeCriteria()); - } - - @Test - public void notificationDataEntry_testIsLastMessageFromReply() { - Person.Builder person = new Person.Builder() - .setName("name") - .setKey("abc") - .setUri("uri") - .setBot(true); - - // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES - Bundle bundle = new Bundle(); - bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build()); - Bundle[] messagesBundle = new Bundle[]{ new Notification.MessagingStyle.Message( - "text", 0, person.build()).toBundle() }; - bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle); - - Notification notification = new Notification.Builder(mContext, "test") - .addExtras(bundle) - .build(); - - NotificationEntry entry = new NotificationEntryBuilder() - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(notification) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build(); - entry.setHasSentReply(); - - assertTrue(entry.isLastMessageFromReply()); - } - - @Test - public void personHighPriority() { - Person person = new Person.Builder() - .setName("name") - .setKey("abc") - .setUri("uri") - .setBot(true) - .build(); - - Notification notification = new Notification.Builder(mContext, "test") - .addPerson(person) - .build(); - - StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, - notification, mContext.getUser(), "", 0); - - assertTrue(mNotificationData.isHighPriority(sbn)); - } - - @Test - public void messagingStyleHighPriority() { - - Notification notification = new Notification.Builder(mContext, "test") - .setStyle(new Notification.MessagingStyle("")) - .build(); - - StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, - notification, mContext.getUser(), "", 0); - - assertTrue(mNotificationData.isHighPriority(sbn)); - } - - @Test - public void minForegroundNotHighPriority() { - Notification notification = mock(Notification.class); - when(notification.isForegroundService()).thenReturn(true); - - StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, - notification, mContext.getUser(), "", 0); - - Bundle override = new Bundle(); - override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN); - mNotificationData.rankingOverrides.put(sbn.getKey(), override); - - assertFalse(mNotificationData.isHighPriority(sbn)); - } - - @Test - public void lowForegroundHighPriority() { - Notification notification = mock(Notification.class); - when(notification.isForegroundService()).thenReturn(true); - - StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, - notification, mContext.getUser(), "", 0); - - Bundle override = new Bundle(); - override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW); - mNotificationData.rankingOverrides.put(sbn.getKey(), override); - - assertTrue(mNotificationData.isHighPriority(sbn)); - } - - @Test - public void userChangeTrumpsHighPriorityCharacteristics() { - Person person = new Person.Builder() - .setName("name") - .setKey("abc") - .setUri("uri") - .setBot(true) - .build(); - - Notification notification = new Notification.Builder(mContext, "test") - .addPerson(person) - .setStyle(new Notification.MessagingStyle("")) - .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) - .build(); - - StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, - notification, mContext.getUser(), "", 0); - - NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); - channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); - - Bundle override = new Bundle(); - override.putParcelable(OVERRIDE_CHANNEL, channel); - mNotificationData.rankingOverrides.put(sbn.getKey(), override); - - assertFalse(mNotificationData.isHighPriority(sbn)); - } - - @Test - public void testSort_highPriorityTrumpsNMSRank() { - // NMS rank says A and then B. But A is not high priority and B is, so B should sort in - // front - Notification aN = new Notification.Builder(mContext, "test") - .setStyle(new Notification.MessagingStyle("")) - .build(); - NotificationEntry a = new NotificationEntryBuilder() - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(aN) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build(); - a.setRow(mock(ExpandableNotificationRow.class)); - a.setIsHighPriority(false); - - Bundle override = new Bundle(); - override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW); - override.putInt(OVERRIDE_RANK, 1); - mNotificationData.rankingOverrides.put(a.getKey(), override); - - Notification bN = new Notification.Builder(mContext, "test") - .setStyle(new Notification.MessagingStyle("")) - .build(); - NotificationEntry b = new NotificationEntryBuilder() - .setPkg("pkg2") - .setOpPkg("pkg2") - .setTag("tag") - .setNotification(bN) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build(); - b.setIsHighPriority(true); - b.setRow(mock(ExpandableNotificationRow.class)); - - Bundle bOverride = new Bundle(); - bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW); - bOverride.putInt(OVERRIDE_RANK, 2); - mNotificationData.rankingOverrides.put(b.getKey(), bOverride); - - assertEquals(1, mNotificationData.mRankingComparator.compare(a, b)); - } - - @Test - public void testSort_samePriorityUsesNMSRank() { - // NMS rank says A and then B, and they are the same priority so use that rank - Notification aN = new Notification.Builder(mContext, "test") - .setStyle(new Notification.MessagingStyle("")) - .build(); - NotificationEntry a = new NotificationEntryBuilder() - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(aN) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build(); - a.setRow(mock(ExpandableNotificationRow.class)); - a.setIsHighPriority(false); - - Bundle override = new Bundle(); - override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW); - override.putInt(OVERRIDE_RANK, 1); - mNotificationData.rankingOverrides.put(a.getKey(), override); - - Notification bN = new Notification.Builder(mContext, "test") - .setStyle(new Notification.MessagingStyle("")) - .build(); - NotificationEntry b = new NotificationEntryBuilder() - .setPkg("pkg2") - .setOpPkg("pkg2") - .setTag("tag") - .setNotification(bN) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build(); - b.setRow(mock(ExpandableNotificationRow.class)); - b.setIsHighPriority(false); - - Bundle bOverride = new Bundle(); - bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW); - bOverride.putInt(OVERRIDE_RANK, 2); - mNotificationData.rankingOverrides.put(b.getKey(), bOverride); - - assertEquals(-1, mNotificationData.mRankingComparator.compare(a, b)); - } - - @Test - public void testSort_properlySetsAlertingBucket() { - Notification notification = new Notification.Builder(mContext, "test") - .build(); - NotificationEntry entry = new NotificationEntryBuilder() - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(notification) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build(); - - Bundle override = new Bundle(); - override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_DEFAULT); - mNotificationData.rankingOverrides.put(entry.getKey(), override); - - entry.setRow(mRow); - mNotificationData.add(entry); - - assertEquals(entry.getBucket(), BUCKET_ALERTING); - } - - @Test - public void testSort_properlySetsSilentBucket() { - Notification notification = new Notification.Builder(mContext, "test") - .build(); - - NotificationEntry entry = new NotificationEntryBuilder() - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(notification) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build(); - - Bundle override = new Bundle(); - override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW); - mNotificationData.rankingOverrides.put(entry.getKey(), override); - - entry.setRow(mRow); - mNotificationData.add(entry); - - assertEquals(entry.getBucket(), BUCKET_SILENT); - } - - private void initStatusBarNotification(boolean allowDuringSetup) { - Bundle bundle = new Bundle(); - bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup); - Notification notification = new Notification.Builder(mContext, "test") - .addExtras(bundle) - .build(); - modifySbn(mEntry) - .setNotification(notification) - .build(); - } - - public static class TestableNotificationData extends NotificationData { - public TestableNotificationData(NotificationSectionsFeatureManager sectionsFeatureManager) { - super( - sectionsFeatureManager, - mock(NotifLog.class), - mock(PeopleNotificationIdentifier.class)); - } - - public static final String OVERRIDE_RANK = "r"; - public static final String OVERRIDE_DND = "dnd"; - public static final String OVERRIDE_VIS_OVERRIDE = "vo"; - public static final String OVERRIDE_VIS_EFFECTS = "ve"; - public static final String OVERRIDE_IMPORTANCE = "i"; - public static final String OVERRIDE_IMP_EXP = "ie"; - public static final String OVERRIDE_GROUP = "g"; - public static final String OVERRIDE_CHANNEL = "c"; - public static final String OVERRIDE_PEOPLE = "p"; - public static final String OVERRIDE_SNOOZE_CRITERIA = "sc"; - public static final String OVERRIDE_BADGE = "b"; - public static final String OVERRIDE_USER_SENTIMENT = "us"; - public static final String OVERRIDE_HIDDEN = "h"; - public static final String OVERRIDE_LAST_ALERTED = "la"; - public static final String OVERRIDE_NOISY = "n"; - public static final String OVERRIDE_SMART_ACTIONS = "sa"; - public static final String OVERRIDE_SMART_REPLIES = "sr"; - public static final String OVERRIDE_BUBBLE = "cb"; - public static final String OVERRIDE_VISUALLY_INTERRUPTIVE = "vi"; - - public Map<String, Bundle> rankingOverrides = new HashMap<>(); - - @Override - protected boolean getRanking(String key, Ranking outRanking) { - super.getRanking(key, outRanking); - - ArrayList<String> currentAdditionalPeople = new ArrayList<>(); - if (outRanking.getAdditionalPeople() != null) { - currentAdditionalPeople.addAll(outRanking.getAdditionalPeople()); - } - - ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>(); - if (outRanking.getSnoozeCriteria() != null) { - currentSnooze.addAll(outRanking.getSnoozeCriteria()); - } - - ArrayList<Notification.Action> currentActions = new ArrayList<>(); - if (outRanking.getSmartActions() != null) { - currentActions.addAll(outRanking.getSmartActions()); - } - - ArrayList<CharSequence> currentReplies = new ArrayList<>(); - if (outRanking.getSmartReplies() != null) { - currentReplies.addAll(outRanking.getSmartReplies()); - } - - if (rankingOverrides.get(key) != null) { - Bundle overrides = rankingOverrides.get(key); - outRanking.populate(key, - overrides.getInt(OVERRIDE_RANK, outRanking.getRank()), - overrides.getBoolean(OVERRIDE_DND, outRanking.matchesInterruptionFilter()), - overrides.getInt(OVERRIDE_VIS_OVERRIDE, outRanking.getVisibilityOverride()), - overrides.getInt(OVERRIDE_VIS_EFFECTS, - outRanking.getSuppressedVisualEffects()), - overrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()), - overrides.getCharSequence(OVERRIDE_IMP_EXP, - outRanking.getImportanceExplanation()), - overrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()), - overrides.containsKey(OVERRIDE_CHANNEL) - ? (NotificationChannel) overrides.getParcelable(OVERRIDE_CHANNEL) - : outRanking.getChannel(), - overrides.containsKey(OVERRIDE_PEOPLE) - ? overrides.getStringArrayList(OVERRIDE_PEOPLE) - : currentAdditionalPeople, - overrides.containsKey(OVERRIDE_SNOOZE_CRITERIA) - ? overrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA) - : currentSnooze, - overrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()), - overrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()), - overrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()), - overrides.getLong(OVERRIDE_LAST_ALERTED, - outRanking.getLastAudiblyAlertedMillis()), - overrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()), - overrides.containsKey(OVERRIDE_SMART_ACTIONS) - ? overrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS) - : currentActions, - overrides.containsKey(OVERRIDE_SMART_REPLIES) - ? overrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES) - : currentReplies, - overrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble()), - overrides.getBoolean(OVERRIDE_VISUALLY_INTERRUPTIVE, - outRanking.visuallyInterruptive())); - } else { - outRanking.populate( - new RankingBuilder() - .setKey(key) - .build()); - } - return true; - } - } - - private Notification.Action createContextualAction(String title) { - return new Notification.Action.Builder( - Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon), - title, - PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)) - .setContextual(true) - .build(); - } - - private Notification.Action createAction(String title) { - return new Notification.Action.Builder( - Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon), - title, - PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build(); - } - - private ArrayList<Notification.Action> createActions(String... titles) { - ArrayList<Notification.Action> actions = new ArrayList<>(); - for (String title : titles) { - actions.add(createAction(title)); - } - return actions; - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java new file mode 100644 index 000000000000..536aeb4d0163 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java @@ -0,0 +1,254 @@ +/* + * 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 android.app.Notification.CATEGORY_ALARM; +import static android.app.Notification.CATEGORY_CALL; +import static android.app.Notification.CATEGORY_EVENT; +import static android.app.Notification.CATEGORY_MESSAGE; +import static android.app.Notification.CATEGORY_REMINDER; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; + +import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking; +import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import android.app.ActivityManager; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.PendingIntent; +import android.app.Person; +import android.content.Intent; +import android.graphics.drawable.Icon; +import android.media.session.MediaSession; +import android.os.Bundle; +import android.os.UserHandle; +import android.service.notification.NotificationListenerService.Ranking; +import android.service.notification.SnoozeCriterion; +import android.service.notification.StatusBarNotification; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.NotificationEntryBuilder; +import com.android.systemui.statusbar.RankingBuilder; +import com.android.systemui.statusbar.SbnBuilder; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class NotificationEntryTest extends SysuiTestCase { + private static final String TEST_PACKAGE_NAME = "test"; + private static final int TEST_UID = 0; + private static final int UID_NORMAL = 123; + private static final NotificationChannel NOTIFICATION_CHANNEL = + new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE); + + private int mId; + + private NotificationEntry mEntry; + + @Before + public void setup() { + Notification.Builder n = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .setContentTitle("Title") + .setContentText("Text"); + + mEntry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setId(mId++) + .setNotification(n.build()) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .build(); + } + + @Test + public void testIsExemptFromDndVisualSuppression_foreground() { + mEntry.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; + + assertTrue(mEntry.isExemptFromDndVisualSuppression()); + assertFalse(mEntry.shouldSuppressAmbient()); + } + + @Test + public void testIsExemptFromDndVisualSuppression_media() { + Notification.Builder n = new Notification.Builder(mContext, "") + .setStyle(new Notification.MediaStyle() + .setMediaSession(mock(MediaSession.Token.class))) + .setSmallIcon(R.drawable.ic_person) + .setContentTitle("Title") + .setContentText("Text"); + NotificationEntry e1 = new NotificationEntryBuilder() + .setNotification(n.build()) + .build(); + + assertTrue(e1.isExemptFromDndVisualSuppression()); + assertFalse(e1.shouldSuppressAmbient()); + } + + @Test + public void testIsExemptFromDndVisualSuppression_system() { + mEntry.mIsSystemNotification = true; + + assertTrue(mEntry.isExemptFromDndVisualSuppression()); + assertFalse(mEntry.shouldSuppressAmbient()); + } + + @Test + public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() { + NotificationEntry entry = new NotificationEntryBuilder() + .setUid(UID_NORMAL) + .build(); + entry.mIsSystemNotification = true; + modifyRanking(entry).setSuppressedVisualEffects(SUPPRESSED_EFFECT_AMBIENT).build(); + + modifySbn(entry) + .setNotification( + new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build()) + .build(); + assertFalse(entry.isExemptFromDndVisualSuppression()); + assertTrue(entry.shouldSuppressAmbient()); + + modifySbn(entry) + .setNotification( + new Notification.Builder(mContext, "") + .setCategory(CATEGORY_REMINDER) + .build()) + .build(); + assertFalse(entry.isExemptFromDndVisualSuppression()); + + modifySbn(entry) + .setNotification( + new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build()) + .build(); + assertFalse(entry.isExemptFromDndVisualSuppression()); + + modifySbn(entry) + .setNotification( + new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build()) + .build(); + assertFalse(entry.isExemptFromDndVisualSuppression()); + + modifySbn(entry) + .setNotification( + new Notification.Builder(mContext, "") + .setCategory(CATEGORY_MESSAGE) + .build()) + .build(); + assertFalse(entry.isExemptFromDndVisualSuppression()); + } + + @Test + public void testCreateNotificationDataEntry_RankingUpdate() { + StatusBarNotification sbn = new SbnBuilder().build(); + sbn.getNotification().actions = + new Notification.Action[]{createContextualAction("appGeneratedAction")}; + + ArrayList<Notification.Action> systemGeneratedSmartActions = + createActions("systemGeneratedAction"); + + SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation"); + ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>(); + snoozeCriterions.add(snoozeCriterion); + + Ranking ranking = new RankingBuilder() + .setKey(sbn.getKey()) + .setSmartActions(systemGeneratedSmartActions) + .setChannel(NOTIFICATION_CHANNEL) + .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE) + .setSnoozeCriteria(snoozeCriterions) + .build(); + + NotificationEntry entry = + new NotificationEntry(sbn, ranking); + + assertEquals(systemGeneratedSmartActions, entry.getSmartActions()); + assertEquals(NOTIFICATION_CHANNEL, entry.getChannel()); + assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.getUserSentiment()); + assertEquals(snoozeCriterions, entry.getSnoozeCriteria()); + } + + @Test + public void notificationDataEntry_testIsLastMessageFromReply() { + Person.Builder person = new Person.Builder() + .setName("name") + .setKey("abc") + .setUri("uri") + .setBot(true); + + // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES + Bundle bundle = new Bundle(); + bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build()); + Bundle[] messagesBundle = new Bundle[]{new Notification.MessagingStyle.Message( + "text", 0, person.build()).toBundle()}; + bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle); + + Notification notification = new Notification.Builder(mContext, "test") + .addExtras(bundle) + .build(); + + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg("pkg") + .setOpPkg("pkg") + .setTag("tag") + .setNotification(notification) + .setUser(mContext.getUser()) + .setOverrideGroupKey("") + .build(); + entry.setHasSentReply(); + + assertTrue(entry.isLastMessageFromReply()); + } + + private Notification.Action createContextualAction(String title) { + return new Notification.Action.Builder( + Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon), + title, + PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)) + .setContextual(true) + .build(); + } + + private Notification.Action createAction(String title) { + return new Notification.Action.Builder( + Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon), + title, + PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build(); + } + + private ArrayList<Notification.Action> createActions(String... titles) { + ArrayList<Notification.Action> actions = new ArrayList<>(); + for (String title : titles) { + actions.add(createAction(title)); + } + return actions; + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt new file mode 100644 index 000000000000..01b2f8932d9b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt @@ -0,0 +1,318 @@ +/* + * 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.NotificationChannel +import android.app.NotificationManager.IMPORTANCE_DEFAULT +import android.app.NotificationManager.IMPORTANCE_LOW +import android.app.Person +import android.service.notification.NotificationListenerService.RankingMap +import android.service.notification.StatusBarNotification +import android.testing.AndroidTestingRunner + +import org.junit.runner.RunWith + +import androidx.test.filters.SmallTest + +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.NotificationEntryBuilder +import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking +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.NotifLog +import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING +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 dagger.Lazy +import junit.framework.Assert.assertEquals +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue + +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class NotificationRankingManagerTest + : SysuiTestCase() { + + private var lazyMedia: Lazy<NotificationMediaManager> = Lazy { + mock<NotificationMediaManager>(NotificationMediaManager::class.java) + } + + private val rankingManager = TestableNotificationRankingManager( + lazyMedia, + mock<NotificationGroupManager>(NotificationGroupManager::class.java), + mock<HeadsUpManager>(HeadsUpManager::class.java), + mock<NotificationFilter>(NotificationFilter::class.java), + mock<NotifLog>(NotifLog::class.java), + mock<NotificationSectionsFeatureManager>(NotificationSectionsFeatureManager::class.java) + ) + + @Before + fun setup() { + } + + @Test + fun testPeopleNotification_isHighPriority() { + val person = Person.Builder() + .setName("name") + .setKey("abc") + .setUri("uri") + .setBot(true) + .build() + + val notification = Notification.Builder(mContext, "test") + .addPerson(person) + .build() + + val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.user, "", 0) + + val e = NotificationEntryBuilder() + .setNotification(notification) + .setSbn(sbn) + .build() + + assertTrue(rankingManager.isHighPriority2(e)) + } + + @Test + fun messagingStyleHighPriority() { + + val notif = Notification.Builder(mContext, "test") + .setStyle(Notification.MessagingStyle("")) + .build() + + val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notif, mContext.getUser(), "", 0) + + val e = NotificationEntryBuilder() + .setNotification(notif) + .setSbn(sbn) + .build() + + assertTrue(rankingManager.isHighPriority2(e)) + } + + @Test + fun lowForegroundHighPriority() { + val notification = mock(Notification::class.java) + `when`<Boolean>(notification.isForegroundService).thenReturn(true) + + val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.user, "", 0) + + val e = NotificationEntryBuilder() + .setNotification(notification) + .setSbn(sbn) + .build() + + modifyRanking(e) + .setImportance(IMPORTANCE_LOW) + .build() + + assertTrue(rankingManager.isHighPriority2(e)) + } + + @Test + fun userChangeTrumpsHighPriorityCharacteristics() { + val person = Person.Builder() + .setName("name") + .setKey("abc") + .setUri("uri") + .setBot(true) + .build() + + val notification = Notification.Builder(mContext, "test") + .addPerson(person) + .setStyle(Notification.MessagingStyle("")) + .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) + .build() + + val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.user, "", 0) + + val channel = NotificationChannel("a", "a", IMPORTANCE_LOW) + channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE) + + val e = NotificationEntryBuilder() + .setSbn(sbn) + .setChannel(channel) + .build() + + assertFalse(rankingManager.isHighPriority2(e)) + } + + @Test + fun testSort_highPriorityTrumpsNMSRank() { + // NMS rank says A and then B. But A is not high priority and B is, so B should sort in + // front + val aN = Notification.Builder(mContext, "test") + .setStyle(Notification.MessagingStyle("")) + .build() + val a = NotificationEntryBuilder() + .setPkg("pkg") + .setOpPkg("pkg") + .setTag("tag") + .setNotification(aN) + .setUser(mContext.getUser()) + .setOverrideGroupKey("") + .build() + + a.setIsHighPriority(false) + + modifyRanking(a) + .setImportance(IMPORTANCE_LOW) + .setRank(1) + .build() + + val bN = Notification.Builder(mContext, "test") + .setStyle(Notification.MessagingStyle("")) + .build() + val b = NotificationEntryBuilder() + .setPkg("pkg2") + .setOpPkg("pkg2") + .setTag("tag") + .setNotification(bN) + .setUser(mContext.getUser()) + .setOverrideGroupKey("") + .build() + b.setIsHighPriority(true) + + modifyRanking(b) + .setImportance(IMPORTANCE_LOW) + .setRank(2) + .build() + + assertEquals( + listOf(b, a), + rankingManager.updateRanking(null, listOf(a, b), "test")) + } + + @Test + fun testSort_samePriorityUsesNMSRank() { + // NMS rank says A and then B, and they are the same priority so use that rank + val aN = Notification.Builder(mContext, "test") + .setStyle(Notification.MessagingStyle("")) + .build() + val a = NotificationEntryBuilder() + .setPkg("pkg") + .setOpPkg("pkg") + .setTag("tag") + .setNotification(aN) + .setUser(mContext.getUser()) + .setOverrideGroupKey("") + .build() + a.setIsHighPriority(false) + + modifyRanking(a) + .setImportance(IMPORTANCE_LOW) + .setRank(1) + .build() + + val bN = Notification.Builder(mContext, "test") + .setStyle(Notification.MessagingStyle("")) + .build() + val b = NotificationEntryBuilder() + .setPkg("pkg2") + .setOpPkg("pkg2") + .setTag("tag") + .setNotification(bN) + .setUser(mContext.getUser()) + .setOverrideGroupKey("") + .build() + b.setIsHighPriority(false) + + modifyRanking(b) + .setImportance(IMPORTANCE_LOW) + .setRank(2) + .build() + + assertEquals( + listOf(a, b), + rankingManager.updateRanking(null, listOf(a, b), "test")) + } + + @Test + fun testSort_properlySetsAlertingBucket() { + val notif = Notification.Builder(mContext, "test") .build() + + val e = NotificationEntryBuilder() + .setPkg("pkg") + .setOpPkg("pkg") + .setTag("tag") + .setNotification(notif) + .setUser(mContext.user) + .setOverrideGroupKey("") + .build() + + modifyRanking(e).setImportance(IMPORTANCE_DEFAULT) .build() + + rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test") + assertEquals(e.bucket, BUCKET_ALERTING) + } + + @Test + fun testSort_properlySetsSilentBucket() { + val notif = Notification.Builder(mContext, "test") .build() + + val e = NotificationEntryBuilder() + .setPkg("pkg") + .setOpPkg("pkg") + .setTag("tag") + .setNotification(notif) + .setUser(mContext.user) + .setOverrideGroupKey("") + .build() + + modifyRanking(e).setImportance(IMPORTANCE_LOW).build() + + rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test") + assertEquals(e.bucket, BUCKET_SILENT) + } + + internal class TestableNotificationRankingManager( + mediaManager: Lazy<NotificationMediaManager>, + groupManager: NotificationGroupManager, + headsUpManager: HeadsUpManager, + filter: NotificationFilter, + notifLog: NotifLog, + sectionsFeatureManager: NotificationSectionsFeatureManager + ) : NotificationRankingManager( + mediaManager, + groupManager, + headsUpManager, + filter, + notifLog, + sectionsFeatureManager + ) { + + fun isHighPriority2(e: NotificationEntry): Boolean { + return isHighPriority(e) + } + + fun applyTestRankingMap(r: RankingMap) { + rankingMap = r + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java index 47c17ad88fcb..d1398667f497 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java @@ -44,7 +44,6 @@ import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -71,7 +70,6 @@ public class NotificationLoggerTest extends SysuiTestCase { @Mock private NotificationListContainer mListContainer; @Mock private IStatusBarService mBarService; - @Mock private NotificationData mNotificationData; @Mock private ExpandableNotificationRow mRow; @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger; @@ -91,8 +89,6 @@ public class NotificationLoggerTest extends SysuiTestCase { mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager); mDependency.injectTestDependency(NotificationListener.class, mListener); - when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); - mEntry = new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_NAME) .setOpPkg(TEST_PACKAGE_NAME) @@ -131,7 +127,7 @@ public class NotificationLoggerTest extends SysuiTestCase { any(NotificationVisibility[].class)); when(mListContainer.isInVisibleLocation(any())).thenReturn(true); - when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry)); + when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); TestableLooper.get(this).processAllMessages(); waitForUiOffloadThread(); @@ -153,7 +149,7 @@ public class NotificationLoggerTest extends SysuiTestCase { public void testStoppingNotificationLoggingReportsCurrentNotifications() throws Exception { when(mListContainer.isInVisibleLocation(any())).thenReturn(true); - when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry)); + when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); TestableLooper.get(this).processAllMessages(); waitForUiOffloadThread(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 6f52e4a6686b..5b624bc6e4b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -20,7 +20,6 @@ import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -56,7 +55,9 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.EmptyShadeView; +import com.android.systemui.statusbar.NotificationEntryBuilder; import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; @@ -65,9 +66,13 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; -import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.TestableNotificationEntryManager; +import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; +import com.android.systemui.statusbar.notification.logging.NotifLog; import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.FooterView; @@ -80,7 +85,6 @@ import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.StatusBarTest.TestableNotificationEntryManager; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.DeviceConfigProxyFake; @@ -97,6 +101,7 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.ArrayList; +import java.util.List; /** * Tests for {@link NotificationStackScrollLayout}. @@ -117,7 +122,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private NotificationGroupManager mGroupManager; @Mock private ExpandHelper mExpandHelper; @Mock private EmptyShadeView mEmptyShadeView; - @Mock private NotificationData mNotificationData; @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private RemoteInputController mRemoteInputController; @Mock private NotificationIconAreaController mNotificationIconAreaController; @@ -140,6 +144,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { NOTIFICATION_NEW_INTERRUPTION_MODEL, 1); // Inject dependencies before initializing the layout + mDependency.injectMockDependency(VisualStabilityManager.class); mDependency.injectTestDependency( NotificationBlockingHelperManager.class, mBlockingHelperManager); @@ -150,7 +155,18 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mDependency.injectMockDependency(ShadeController.class); when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); - mEntryManager = new TestableNotificationEntryManager(mNotificationData); + mEntryManager = new TestableNotificationEntryManager( + mock(NotifLog.class), + mock(NotificationGroupManager.class), + new NotificationRankingManager( + () -> mock(NotificationMediaManager.class), + mGroupManager, + mHeadsUpManager, + mock(NotificationFilter.class), + mock(NotifLog.class), + mock(NotificationSectionsFeatureManager.class) + ), + mock(NotificationEntryManager.KeyguardEnvironment.class)); mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager); Dependency.get(InitController.class).executePostInitTasks(); mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager); @@ -161,8 +177,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { // The actual class under test. You may need to work with this class directly when // testing anonymous class members of mStackScroller, like mMenuEventListener, // which refer to members of NotificationStackScrollLayout. The spy - // holds a copy of the CUT's instances of these classes, so they still refer to the CUT's - // member variables, not the spy's member variables. + // holds a copy of the CUT's instances of these KeyguardBypassController, so they still + // refer to the CUT's member variables, not the spy's member variables. mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null, true /* allowLongPress */, mNotificationRoundnessManager, mock(DynamicPrivacyController.class), @@ -293,7 +309,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_noNotifications() { setBarStateForTest(StatusBarState.SHADE); - assertEquals(0, mNotificationData.getActiveNotifications().size()); + assertEquals(0, mEntryManager.getActiveNotificationsCount()); mStackScroller.updateFooter(); verify(mStackScroller, atLeastOnce()).updateFooterView(false, false); @@ -303,8 +319,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { public void testUpdateFooter_remoteInput() { setBarStateForTest(StatusBarState.SHADE); ArrayList<NotificationEntry> entries = new ArrayList<>(); - entries.add(mock(NotificationEntry.class)); - when(mNotificationData.getActiveNotifications()).thenReturn(entries); + entries.add(new NotificationEntryBuilder().build()); + addEntriesToEntryManager(entries); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); when(row.canViewBeDismissed()).thenReturn(true); @@ -319,9 +335,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_oneClearableNotification() { setBarStateForTest(StatusBarState.SHADE); + ArrayList<NotificationEntry> entries = new ArrayList<>(); - entries.add(mock(NotificationEntry.class)); - when(mNotificationData.getActiveNotifications()).thenReturn(entries); + entries.add(new NotificationEntryBuilder().build()); + addEntriesToEntryManager(entries); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); when(row.canViewBeDismissed()).thenReturn(true); @@ -335,10 +352,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_oneNonClearableNotification() { setBarStateForTest(StatusBarState.SHADE); + ArrayList<NotificationEntry> entries = new ArrayList<>(); - entries.add(mock(NotificationEntry.class)); - when(mEntryManager.getNotificationData().getActiveNotifications()).thenReturn(entries); - assertTrue(mEntryManager.getNotificationData().getActiveNotifications().size() != 0); + entries.add(new NotificationEntryBuilder().build()); + addEntriesToEntryManager(entries); mStackScroller.updateFooter(); verify(mStackScroller).updateFooterView(true, false); @@ -460,4 +477,14 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { // rather than the mock because the spy just coppied the anonymous inner /shruggie. mStackScroller.setStatusBarState(state); } + + private void addEntriesToEntryManager(List<NotificationEntry> entries) { + for (NotificationEntry e : entries) { + mEntryManager.addActiveNotificationForTest(e); + } + } + + private void addActiveNotificationsToManager(List<NotificationEntry> entries) { + mEntryManager.setActiveNotificationList(entries); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java index 64c1b510cbf9..a02445487dc0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java @@ -40,7 +40,6 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import org.junit.Before; @@ -51,8 +50,6 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.ArrayList; - @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper @@ -61,7 +58,6 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { private static final int LIGHTS_OUT = APPEARANCE_LOW_PROFILE_BARS; @Mock private NotificationEntryManager mEntryManager; - @Mock private NotificationData mNotificationData; @Mock private CommandQueue mCommandQueue; @Mock private WindowManager mWindowManager; @Mock private Display mDisplay; @@ -71,7 +67,6 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { private View mLightsOutView; private LightsOutNotifController mLightsOutNotifController; - private ArrayList<NotificationEntry> mActiveNotifications = new ArrayList<>(); private int mDisplayId; private NotificationEntryListener mEntryListener; private CommandQueue.Callbacks mCallbacks; @@ -81,8 +76,6 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mDisplayId = mContext.getDisplayId(); mLightsOutView = new View(mContext); - when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); - when(mNotificationData.getActiveNotifications()).thenReturn(mActiveNotifications); when(mWindowManager.getDefaultDisplay()).thenReturn(mDisplay); when(mDisplay.getDisplayId()).thenReturn(mDisplayId); @@ -136,7 +129,7 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { @Test public void testLightsOut_withNotifs_onSystemBarAppearanceChanged() { // GIVEN active visible notifications - mActiveNotifications.add(mock(NotificationEntry.class)); + when(mEntryManager.hasActiveNotifications()).thenReturn(true); // WHEN lights out mCallbacks.onSystemBarAppearanceChanged( @@ -153,7 +146,7 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { @Test public void testLightsOut_withoutNotifs_onSystemBarAppearanceChanged() { // GIVEN no active visible notifications - mActiveNotifications.clear(); + when(mEntryManager.hasActiveNotifications()).thenReturn(false); // WHEN lights out mCallbacks.onSystemBarAppearanceChanged( @@ -170,7 +163,7 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { @Test public void testLightsOn_afterLightsOut_onSystemBarAppearanceChanged() { // GIVEN active visible notifications - mActiveNotifications.add(mock(NotificationEntry.class)); + when(mEntryManager.hasActiveNotifications()).thenReturn(true); // WHEN lights on mCallbacks.onSystemBarAppearanceChanged( @@ -187,13 +180,13 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { @Test public void testEntryAdded() { // GIVEN no visible notifications and lights out - mActiveNotifications.clear(); + when(mEntryManager.hasActiveNotifications()).thenReturn(false); mLightsOutNotifController.mAppearance = LIGHTS_OUT; mLightsOutNotifController.updateLightsOutView(); assertIsShowingDot(false); // WHEN an active notification is added - mActiveNotifications.add(mock(NotificationEntry.class)); + when(mEntryManager.hasActiveNotifications()).thenReturn(true); assertTrue(mLightsOutNotifController.shouldShowDot()); mEntryListener.onNotificationAdded(mock(NotificationEntry.class)); @@ -204,13 +197,13 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { @Test public void testEntryRemoved() { // GIVEN a visible notification and lights out - mActiveNotifications.add(mock(NotificationEntry.class)); + when(mEntryManager.hasActiveNotifications()).thenReturn(true); mLightsOutNotifController.mAppearance = LIGHTS_OUT; mLightsOutNotifController.updateLightsOutView(); assertIsShowingDot(true); // WHEN all active notifications are removed - mActiveNotifications.clear(); + when(mEntryManager.hasActiveNotifications()).thenReturn(false); assertFalse(mLightsOutNotifController.shouldShowDot()); mEntryListener.onEntryRemoved(mock(NotificationEntry.class), null, false); @@ -221,13 +214,13 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { @Test public void testEntryUpdated() { // GIVEN no visible notifications and lights out - mActiveNotifications.clear(); + when(mEntryManager.hasActiveNotifications()).thenReturn(false); mLightsOutNotifController.mAppearance = LIGHTS_OUT; mLightsOutNotifController.updateLightsOutView(); assertIsShowingDot(false); // WHEN an active notification is added - mActiveNotifications.add(mock(NotificationEntry.class)); + when(mEntryManager.hasActiveNotifications()).thenReturn(true); assertTrue(mLightsOutNotifController.shouldShowDot()); mEntryListener.onPostEntryUpdated(mock(NotificationEntry.class)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 280cc90c0ca4..c165e561b393 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -54,11 +54,9 @@ import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; -import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; import com.android.systemui.statusbar.notification.logging.NotifLog; -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -239,11 +237,10 @@ public class NotificationPanelViewTest extends SysuiTestCase { mock(ShadeController.class), mock(NotificationLockscreenUserManager.class), new NotificationEntryManager( - new NotificationData( - mock(NotificationSectionsFeatureManager.class), - mock(NotifLog.class), - mock(PeopleNotificationIdentifier.class)), - mock(NotifLog.class)), + mock(NotifLog.class), + mock(NotificationGroupManager.class), + mock(NotificationRankingManager.class), + mock(NotificationEntryManager.KeyguardEnvironment.class)), mock(KeyguardStateController.class), statusBarStateController, mock(DozeLog.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index d8a68b0c230c..24a5d932fd85 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -68,7 +68,6 @@ 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.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -117,7 +116,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { @Mock private Intent mContentIntentInner; @Mock - private NotificationData mNotificationData; private NotificationActivityStarter mNotificationActivityStarter; @@ -134,7 +132,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); - when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); when(mContentIntent.isActivity()).thenReturn(true); when(mContentIntent.getCreatorUserHandle()).thenReturn(UserHandle.of(1)); @@ -157,7 +154,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mActiveNotifications = new ArrayList<>(); mActiveNotifications.add(mNotificationRow.getEntry()); mActiveNotifications.add(mBubbleNotificationRow.getEntry()); - when(mNotificationData.getActiveNotifications()).thenReturn(mActiveNotifications); + when(mEntryManager.getVisibleNotifications()).thenReturn(mActiveNotifications); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); mNotificationActivityStarter = new StatusBarNotificationActivityStarter(getContext(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index de87d3197ef6..1c02b60902b8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -52,7 +52,6 @@ import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; @@ -100,11 +99,9 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mDependency.injectMockDependency(NotificationGutsManager.class); mDependency.injectMockDependency(StatusBarWindowController.class); mDependency.injectMockDependency(InitController.class); - NotificationData notificationData = mock(NotificationData.class); - when(notificationData.getNotificationsForCurrentUser()).thenReturn(new ArrayList<>()); NotificationEntryManager entryManager = mDependency.injectMockDependency(NotificationEntryManager.class); - when(entryManager.getNotificationData()).thenReturn(notificationData); + when(entryManager.getActiveNotificationsForCurrentUser()).thenReturn(new ArrayList<>()); StatusBarWindowView statusBarWindowView = mock(StatusBarWindowView.class); when(statusBarWindowView.getResources()).thenReturn(mContext.getResources()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index f3273784c6ca..95929c3adcb8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -101,7 +101,6 @@ import com.android.systemui.statusbar.NotificationEntryBuilder; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.PulseExpansionHandler; @@ -120,12 +119,9 @@ import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.logging.NotifLog; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; -import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -177,7 +173,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private ArrayList<NotificationEntry> mNotificationList; @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; @Mock private BiometricUnlockController mBiometricUnlockController; - @Mock private NotificationData mNotificationData; @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor; @Mock private VisualStabilityManager mVisualStabilityManager; @Mock private NotificationListener mNotificationListener; @@ -240,6 +235,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private ViewMediatorCallback mViewMediatorCallback; @Mock private DismissCallbackRegistry mDismissCallbackRegistry; @Mock private ScreenPinningRequest mScreenPinningRequest; + @Mock private NotificationEntryManager mEntryManager; @Before public void setup() throws Exception { @@ -260,10 +256,8 @@ public class StatusBarTest extends SysuiTestCase { mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class)); mMetricsLogger = new FakeMetricsLogger(); - TestableNotificationEntryManager entryManager = new TestableNotificationEntryManager( - mNotificationData); NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener, - Dependency.get(UiOffloadThread.class), entryManager, mStatusBarStateController, + Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController, mExpansionStateLogger); notificationLogger.setVisibilityReporter(mock(Runnable.class)); @@ -332,7 +326,7 @@ public class StatusBarTest extends SysuiTestCase { ), mNotificationGutsManager, notificationLogger, - entryManager, + mEntryManager, mNotificationInterruptionStateProvider, mNotificationViewHierarchyManager, mKeyguardViewMediator, @@ -407,9 +401,6 @@ public class StatusBarTest extends SysuiTestCase { mStatusBar.mStatusBarWindowViewController = mStatusBarWindowViewController; mStatusBar.startKeyguard(); Dependency.get(InitController.class).executePostInitTasks(); - entryManager.setUpForTest(mock(NotificationPresenter.class), mStackScroller, - mHeadsUpManager); - entryManager.addNotificationEntryListener(mEntryListener); notificationLogger.setUpWithContainer(mStackScroller); } @@ -645,8 +636,7 @@ public class StatusBarTest extends SysuiTestCase { public void testPanelOpenForHeadsUp() { when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true); - when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList); - when(mNotificationList.size()).thenReturn(5); + when(mEntryManager.getActiveNotificationsCount()).thenReturn(5); when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(true); mStatusBar.setBarStateForTest(StatusBarState.SHADE); @@ -664,8 +654,8 @@ public class StatusBarTest extends SysuiTestCase { @Test public void testPanelOpenAndClear() { when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false); - when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList); - when(mNotificationList.size()).thenReturn(5); + when(mEntryManager.getActiveNotificationsCount()).thenReturn(5); + when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false); mStatusBar.setBarStateForTest(StatusBarState.SHADE); @@ -683,8 +673,7 @@ public class StatusBarTest extends SysuiTestCase { @Test public void testPanelOpenAndNoClear() { when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false); - when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList); - when(mNotificationList.size()).thenReturn(5); + when(mEntryManager.getActiveNotificationsCount()).thenReturn(5); when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false); mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); @@ -842,19 +831,6 @@ public class StatusBarTest extends SysuiTestCase { any(UserHandle.class)); } - public static class TestableNotificationEntryManager extends NotificationEntryManager { - - public TestableNotificationEntryManager(NotificationData notificationData) { - super(notificationData, mock(NotifLog.class)); - } - - public void setUpForTest(NotificationPresenter presenter, - NotificationListContainer listContainer, - HeadsUpManagerPhone headsUpManager) { - super.setUpWithPresenter(presenter, listContainer, headsUpManager); - } - } - public static class TestableNotificationInterruptionStateProvider extends NotificationInterruptionStateProvider { |