From b8da5df67a8af77a3395af5f033586de4ae172ea Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Mon, 1 Nov 2021 10:42:04 -0400 Subject: [PATCH 1/3] New Pipeline: Add a NotificationVisibilityProvider to support both pipelines Fixes: 169655596 Fixes: 204183781 Fixes: 204770080 Test: atest SystemUITests Change-Id: I96cd96d1a037e7cca301242b1dba25ecdd72be9a --- .../systemui/dagger/SystemUIModule.java | 6 +- .../widget/LaunchConversationActivity.java | 32 +++++----- ...NotificationLockscreenUserManagerImpl.java | 28 +++++---- .../statusbar/NotificationMediaManager.java | 23 ++------ .../NotificationRemoteInputManager.java | 13 ++--- .../statusbar/SmartReplyController.java | 17 ++---- .../dagger/StatusBarDependenciesModule.java | 13 ++++- .../NotificationEntryManager.java | 14 +++-- .../collection/NotifPipeline.java | 3 +- .../coordinator/BubbleCoordinator.java | 2 +- .../OnUserInteractionCallbackImpl.java | 17 ++---- .../LegacyNotificationVisibilityProvider.kt | 50 ++++++++++++++++ .../OnUserInteractionCallbackImplLegacy.java | 13 ++--- .../CommonNotifCollection.java | 8 +++ .../render/NotificationVisibilityProvider.kt | 32 ++++++++++ .../NotificationVisibilityProviderImpl.kt | 43 ++++++++++++++ .../dagger/NotificationsModule.java | 26 ++++++++- .../logging/NotificationLogger.java | 15 ++++- ...tificationStackScrollLayoutController.java | 26 +++------ .../StatusBarNotificationActivityStarter.java | 19 +++--- .../systemui/wmshell/BubblesManager.java | 14 ++--- .../LaunchConversationActivityTest.java | 58 ++++++++++++++----- ...NotificationLockscreenUserManagerTest.java | 8 +++ .../NotificationRemoteInputManagerTest.java | 6 +- .../statusbar/SmartReplyControllerTest.java | 9 ++- .../logging/NotificationLoggerTest.java | 31 ++++++++-- ...cationStackScrollLayoutControllerTest.java | 3 + ...tusBarNotificationActivityStarterTest.java | 10 ++++ .../statusbar/phone/StatusBarTest.java | 15 ++++- .../android/systemui/wmshell/BubblesTest.java | 4 ++ .../wmshell/NewNotifPipelineBubblesTest.java | 4 ++ 31 files changed, 407 insertions(+), 155 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationVisibilityProvider.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProvider.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProviderImpl.kt diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index dcb44cc79111e..f4de3bf943eee 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -60,6 +60,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.people.PeopleHubModule; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; @@ -204,7 +205,9 @@ public abstract class SystemUIModule { NotificationShadeWindowController notificationShadeWindowController, StatusBarStateController statusBarStateController, ShadeController shadeController, ConfigurationController configurationController, - @Nullable IStatusBarService statusBarService, INotificationManager notificationManager, + @Nullable IStatusBarService statusBarService, + INotificationManager notificationManager, + NotificationVisibilityProvider visibilityProvider, NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager, @@ -213,6 +216,7 @@ public abstract class SystemUIModule { return Optional.ofNullable(BubblesManager.create(context, bubblesOptional, notificationShadeWindowController, statusBarStateController, shadeController, configurationController, statusBarService, notificationManager, + visibilityProvider, interruptionStateProvider, zenModeController, notifUserManager, groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager, sysuiMainExecutor)); diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java index 79318d69837d7..e1b97a454c5d7 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java @@ -36,8 +36,9 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.people.PeopleSpaceUtils; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubble; @@ -50,7 +51,8 @@ public class LaunchConversationActivity extends Activity { private static final String TAG = "PeopleSpaceLaunchConv"; private static final boolean DEBUG = PeopleSpaceUtils.DEBUG; private UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); - private NotificationEntryManager mNotificationEntryManager; + private NotificationVisibilityProvider mVisibilityProvider; + private CommonNotifCollection mCommonNotifCollection; private final Optional mBubblesManagerOptional; private final UserManager mUserManager; private boolean mIsForTesting; @@ -60,11 +62,16 @@ public class LaunchConversationActivity extends Activity { private NotificationEntry mEntryToBubble; @Inject - public LaunchConversationActivity(NotificationEntryManager notificationEntryManager, - Optional bubblesManagerOptional, UserManager userManager, - CommandQueue commandQueue) { + public LaunchConversationActivity( + NotificationVisibilityProvider visibilityProvider, + CommonNotifCollection commonNotifCollection, + Optional bubblesManagerOptional, + UserManager userManager, + CommandQueue commandQueue + ) { super(); - mNotificationEntryManager = notificationEntryManager; + mVisibilityProvider = visibilityProvider; + mCommonNotifCollection = commonNotifCollection; mBubblesManagerOptional = bubblesManagerOptional; mUserManager = userManager; mCommandQueue = commandQueue; @@ -128,8 +135,7 @@ public class LaunchConversationActivity extends Activity { // shortcutId, fallback to notificationKey if it exists. if (mBubblesManagerOptional.isPresent()) { mBubble = mBubblesManagerOptional.get().getBubbleWithShortcutId(tileId); - NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif( - notificationKey); + NotificationEntry entry = mCommonNotifCollection.getEntry(notificationKey); if (mBubble != null || (entry != null && entry.canBubble())) { mEntryToBubble = entry; if (DEBUG) { @@ -167,14 +173,14 @@ public class LaunchConversationActivity extends Activity { } try { - if (mIStatusBarService == null || mNotificationEntryManager == null) { + if (mIStatusBarService == null || mCommonNotifCollection == null) { if (DEBUG) { Log.d(TAG, "Skipping clear notification: null services, key: " + notifKey); } return; } - NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(notifKey); + NotificationEntry entry = mCommonNotifCollection.getEntry(notifKey); if (entry == null || entry.getRanking() == null) { if (DEBUG) { Log.d(TAG, "Skipping clear notification: NotificationEntry or its Ranking" @@ -183,10 +189,8 @@ public class LaunchConversationActivity extends Activity { return; } - int count = mNotificationEntryManager.getActiveNotificationsCount(); - int rank = entry.getRanking().getRank(); - NotificationVisibility notifVisibility = NotificationVisibility.obtain(notifKey, - rank, count, true); + NotificationVisibility notifVisibility = mVisibilityProvider.obtain(entry, true); + int rank = notifVisibility.rank; if (DEBUG) Log.d(TAG, "Clearing notification, key: " + notifKey + ", rank: " + rank); mIStatusBarService.onNotificationClear( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index fca2a18c61f3d..1311abe971670 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -51,12 +51,13 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -67,6 +68,8 @@ import java.util.List; import javax.inject.Inject; +import dagger.Lazy; + /** * Handles keeping track of the current user, profiles, and various things related to hiding * contents, redacting notifications, and the lockscreen. @@ -86,6 +89,8 @@ public class NotificationLockscreenUserManagerImpl implements // Lazy private NotificationEntryManager mEntryManager; + private final FeatureFlags mFeatureFlags; + private final Lazy mVisibilityProviderLazy; private final DevicePolicyManager mDevicePolicyManager; private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray(); private final SparseBooleanArray mUsersWithSeperateWorkChallenge = new SparseBooleanArray(); @@ -162,15 +167,8 @@ public class NotificationLockscreenUserManagerImpl implements } } if (notificationKey != null) { - NotificationEntry entry = - getEntryManager().getActiveNotificationUnfiltered(notificationKey); - final int count = getEntryManager().getActiveNotificationsCount(); - final int rank = entry != null ? entry.getRanking().getRank() : 0; - NotificationVisibility.NotificationLocation location = - NotificationLogger.getNotificationLocation(entry); - final NotificationVisibility nv = NotificationVisibility.obtain( - notificationKey, - rank, count, true, location); + final NotificationVisibility nv = mVisibilityProviderLazy.get() + .obtain(notificationKey, true); mClickNotifier.onNotificationClick(notificationKey, nv); } break; @@ -197,9 +195,11 @@ public class NotificationLockscreenUserManagerImpl implements @Inject public NotificationLockscreenUserManagerImpl(Context context, + FeatureFlags featureFlags, BroadcastDispatcher broadcastDispatcher, DevicePolicyManager devicePolicyManager, UserManager userManager, + Lazy visibilityProviderLazy, NotificationClickNotifier clickNotifier, KeyguardManager keyguardManager, StatusBarStateController statusBarStateController, @@ -208,10 +208,12 @@ public class NotificationLockscreenUserManagerImpl implements KeyguardStateController keyguardStateController, DumpManager dumpManager) { mContext = context; + mFeatureFlags = featureFlags; mMainHandler = mainHandler; mDevicePolicyManager = devicePolicyManager; mUserManager = userManager; mCurrentUserId = ActivityManager.getCurrentUser(); + mVisibilityProviderLazy = visibilityProviderLazy; mClickNotifier = clickNotifier; statusBarStateController.addCallback(this); mLockPatternUtils = new LockPatternUtils(context); @@ -337,6 +339,8 @@ public class NotificationLockscreenUserManagerImpl implements * package-specific override. */ public boolean shouldHideNotifications(String key) { + // TODO(b/204764178): support new pipeline + mFeatureFlags.checkLegacyPipelineEnabled(); if (getEntryManager() == null) { Log.wtf(TAG, "mEntryManager was null!", new Throwable()); return true; @@ -347,6 +351,8 @@ public class NotificationLockscreenUserManagerImpl implements } public boolean shouldShowOnKeyguard(NotificationEntry entry) { + // TODO(b/204764178): support new pipeline + mFeatureFlags.checkLegacyPipelineEnabled(); if (getEntryManager() == null) { Log.wtf(TAG, "mEntryManager was null!", new Throwable()); return false; @@ -520,6 +526,8 @@ public class NotificationLockscreenUserManagerImpl implements } private boolean packageHasVisibilityOverride(String key) { + // TODO(b/204764178): support new pipeline + mFeatureFlags.checkLegacyPipelineEnabled(); if (getEntryManager() == null) { Log.wtf(TAG, "mEntryManager was null!", new Throwable()); return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index dcb1e4f341888..7cfa830d5d2a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -66,7 +66,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; @@ -113,6 +113,7 @@ public class NotificationMediaManager implements Dumpable { PAUSED_MEDIA_STATES.add(PlaybackState.STATE_CONNECTING); } + private final NotificationVisibilityProvider mVisibilityProvider; private final NotificationEntryManager mEntryManager; private final MediaDataManager mMediaDataManager; private final NotifPipeline mNotifPipeline; @@ -181,6 +182,7 @@ public class NotificationMediaManager implements Dumpable { Context context, Lazy> statusBarOptionalLazy, Lazy notificationShadeWindowController, + NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, MediaArtworkProcessor mediaArtworkProcessor, KeyguardBypassController keyguardBypassController, @@ -201,6 +203,7 @@ public class NotificationMediaManager implements Dumpable { // TODO: use KeyguardStateController#isOccluded to remove this dependency mStatusBarOptionalLazy = statusBarOptionalLazy; mNotificationShadeWindowController = notificationShadeWindowController; + mVisibilityProvider = visibilityProvider; mEntryManager = notificationEntryManager; mMainExecutor = mainExecutor; mMediaDataManager = mediaDataManager; @@ -351,21 +354,10 @@ public class NotificationMediaManager implements Dumpable { } private DismissedByUserStats getDismissedByUserStats(NotificationEntry entry) { - final int activeNotificationsCount; - if (mUsingNotifPipeline) { - activeNotificationsCount = mNotifPipeline.getShadeListCount(); - } else { - activeNotificationsCount = mEntryManager.getActiveNotificationsCount(); - } return new DismissedByUserStats( NotificationStats.DISMISSAL_SHADE, // Add DISMISSAL_MEDIA? NotificationStats.DISMISS_SENTIMENT_NEUTRAL, - NotificationVisibility.obtain( - entry.getKey(), - entry.getRanking().getRank(), - activeNotificationsCount, - /* visible= */ true, - NotificationLogger.getNotificationLocation(entry))); + mVisibilityProvider.obtain(entry, /* visible= */ true)); } private void removeEntry(NotificationEntry entry) { @@ -406,10 +398,7 @@ public class NotificationMediaManager implements Dumpable { return null; } if (mUsingNotifPipeline) { - // TODO(b/169655596): Either add O(1) lookup, or cache this icon? - return mNotifPipeline.getAllNotifs().stream() - .filter(entry -> Objects.equals(entry.getKey(), mMediaNotificationKey)) - .findAny() + return Optional.ofNullable(mNotifPipeline.getEntry(mMediaNotificationKey)) .map(entry -> entry.getIcons().getShelfIcon()) .map(StatusBarIconView::getSourceIcon) .orElse(null); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 1ce7f03500193..dd44f727c2e6b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -60,6 +60,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.StatusBar; @@ -95,6 +96,7 @@ public class NotificationRemoteInputManager implements Dumpable { // Dependencies: private final NotificationLockscreenUserManager mLockscreenUserManager; private final SmartReplyController mSmartReplyController; + private final NotificationVisibilityProvider mVisibilityProvider; private final NotificationEntryManager mEntryManager; private final Handler mMainHandler; private final ActionClickLogger mLogger; @@ -202,14 +204,7 @@ public class NotificationRemoteInputManager implements Dumpable { ViewGroup actionGroup = (ViewGroup) parent; buttonIndex = actionGroup.indexOfChild(view); } - // TODO(b/204183781): get this from the current pipeline - final int count = mEntryManager.getActiveNotificationsCount(); - final int rank = entry.getRanking().getRank(); - - NotificationVisibility.NotificationLocation location = - NotificationLogger.getNotificationLocation(entry); - final NotificationVisibility nv = - NotificationVisibility.obtain(key, rank, count, true, location); + final NotificationVisibility nv = mVisibilityProvider.obtain(entry, true); mClickNotifier.onNotificationActionClick(key, buttonIndex, action, nv, false); } @@ -263,6 +258,7 @@ public class NotificationRemoteInputManager implements Dumpable { FeatureFlags featureFlags, NotificationLockscreenUserManager lockscreenUserManager, SmartReplyController smartReplyController, + NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, RemoteInputNotificationRebuilder rebuilder, Lazy> statusBarOptionalLazy, @@ -276,6 +272,7 @@ public class NotificationRemoteInputManager implements Dumpable { mFeatureFlags = featureFlags; mLockscreenUserManager = lockscreenUserManager; mSmartReplyController = smartReplyController; + mVisibilityProvider = visibilityProvider; mEntryManager = notificationEntryManager; mStatusBarOptionalLazy = statusBarOptionalLazy; mMainHandler = mainHandler; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java index e288b1530d4a4..4ad01aab98a79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java @@ -26,9 +26,8 @@ import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dumpable; import com.android.systemui.dump.DumpManager; import com.android.systemui.statusbar.dagger.StatusBarModule; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -40,7 +39,7 @@ import java.util.Set; */ public class SmartReplyController implements Dumpable { private final IStatusBarService mBarService; - private final NotificationEntryManager mEntryManager; + private final NotificationVisibilityProvider mVisibilityProvider; private final NotificationClickNotifier mClickNotifier; private final Set mSendingKeys = new ArraySet<>(); private Callback mCallback; @@ -50,11 +49,11 @@ public class SmartReplyController implements Dumpable { */ public SmartReplyController( DumpManager dumpManager, - NotificationEntryManager entryManager, + NotificationVisibilityProvider visibilityProvider, IStatusBarService statusBarService, NotificationClickNotifier clickNotifier) { mBarService = statusBarService; - mEntryManager = entryManager; + mVisibilityProvider = visibilityProvider; mClickNotifier = clickNotifier; dumpManager.registerDumpable(this); } @@ -84,13 +83,7 @@ public class SmartReplyController implements Dumpable { public void smartActionClicked( NotificationEntry entry, int actionIndex, Notification.Action action, boolean generatedByAssistant) { - // TODO(b/204183781): get this from the current pipeline - final int count = mEntryManager.getActiveNotificationsCount(); - final int rank = entry.getRanking().getRank(); - NotificationVisibility.NotificationLocation location = - NotificationLogger.getNotificationLocation(entry); - final NotificationVisibility nv = NotificationVisibility.obtain( - entry.getKey(), rank, count, true, location); + final NotificationVisibility nv = mVisibilityProvider.obtain(entry, true); mClickNotifier.onNotificationActionClick( entry.getKey(), actionIndex, action, nv, generatedByAssistant); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java index 74ea19f4ca22a..aa86daaae1258 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java @@ -59,6 +59,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.LowPrior import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ManagedProfileController; @@ -102,6 +103,7 @@ public interface StatusBarDependenciesModule { FeatureFlags featureFlags, NotificationLockscreenUserManager lockscreenUserManager, SmartReplyController smartReplyController, + NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, RemoteInputNotificationRebuilder rebuilder, Lazy> statusBarOptionalLazy, @@ -116,6 +118,7 @@ public interface StatusBarDependenciesModule { featureFlags, lockscreenUserManager, smartReplyController, + visibilityProvider, notificationEntryManager, rebuilder, statusBarOptionalLazy, @@ -134,6 +137,7 @@ public interface StatusBarDependenciesModule { Context context, Lazy> statusBarOptionalLazy, Lazy notificationShadeWindowController, + NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, MediaArtworkProcessor mediaArtworkProcessor, KeyguardBypassController keyguardBypassController, @@ -147,6 +151,7 @@ public interface StatusBarDependenciesModule { context, statusBarOptionalLazy, notificationShadeWindowController, + visibilityProvider, notificationEntryManager, mediaArtworkProcessor, keyguardBypassController, @@ -174,10 +179,14 @@ public interface StatusBarDependenciesModule { @Provides static SmartReplyController provideSmartReplyController( DumpManager dumpManager, - NotificationEntryManager entryManager, + NotificationVisibilityProvider visibilityProvider, IStatusBarService statusBarService, NotificationClickNotifier clickNotifier) { - return new SmartReplyController(dumpManager, entryManager, statusBarService, clickNotifier); + return new SmartReplyController( + dumpManager, + visibilityProvider, + statusBarService, + clickNotifier); } 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 8bc41c20caaff..a0daf8c255697 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -808,11 +808,11 @@ public class NotificationEntryManager implements * notification doesn't exist. */ public NotificationEntry getPendingOrActiveNotif(String key) { - if (mPendingNotifications.containsKey(key)) { - return mPendingNotifications.get(key); - } else { - return mActiveNotifications.get(key); + NotificationEntry entry = mPendingNotifications.get(key); + if (entry != null) { + return entry; } + return mActiveNotifications.get(key); } private void extendLifetime(NotificationEntry entry, NotificationLifetimeExtender extender) { @@ -946,6 +946,12 @@ public class NotificationEntryManager implements return mReadOnlyAllNotifications; } + @Nullable + @Override + public NotificationEntry getEntry(String key) { + return getPendingOrActiveNotif(key); + } + /** @return A count of the active notifications */ public int getActiveNotificationsCount() { return mReadOnlyNotifications.size(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java index 27ba4c23db88a..642cca6ffcb9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java @@ -16,8 +16,6 @@ package com.android.systemui.statusbar.notification.collection; -import android.os.Handler; - import androidx.annotation.Nullable; import com.android.systemui.dagger.SysUISingleton; @@ -108,6 +106,7 @@ public class NotifPipeline implements CommonNotifCollection { /** * Returns the NotificationEntry associated with [key]. */ + @Override @Nullable public NotificationEntry getEntry(String key) { return mNotifCollection.getEntry(key); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java index 15f0d885c2fac..d013261a4193e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java @@ -134,7 +134,7 @@ public class BubbleCoordinator implements Coordinator { mInterceptedDismissalEntries.remove(entry.getKey()); mOnEndDismissInterception.onEndDismissInterception(mDismissInterceptor, entry, dismissedByUserStats); - } else if (mNotifPipeline.getAllNotifs().contains(entry)) { + } else if (mNotifPipeline.getEntry(entry.getKey()) != null) { // Bubbles are hiding the notifications from the shade, but the bubble was // deleted; therefore, the notification should be cancelled as if it were a user // dismissal (this won't re-enter handleInterceptDimissal because Bubbles diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java index 23417fe54efba..66ec30d6ee079 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java @@ -23,15 +23,13 @@ import android.os.SystemClock; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationStats; -import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.collection.NotifCollection; -import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -40,7 +38,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager; * information about the interaction to the notification pipeline. */ public class OnUserInteractionCallbackImpl implements OnUserInteractionCallback { - private final NotifPipeline mNotifPipeline; + private final NotificationVisibilityProvider mVisibilityProvider; private final NotifCollection mNotifCollection; private final HeadsUpManager mHeadsUpManager; private final StatusBarStateController mStatusBarStateController; @@ -48,14 +46,14 @@ public class OnUserInteractionCallbackImpl implements OnUserInteractionCallback private final GroupMembershipManager mGroupMembershipManager; public OnUserInteractionCallbackImpl( - NotifPipeline notifPipeline, + NotificationVisibilityProvider visibilityProvider, NotifCollection notifCollection, HeadsUpManager headsUpManager, StatusBarStateController statusBarStateController, VisualStabilityCoordinator visualStabilityCoordinator, GroupMembershipManager groupMembershipManager ) { - mNotifPipeline = notifPipeline; + mVisibilityProvider = visibilityProvider; mNotifCollection = notifCollection; mHeadsUpManager = headsUpManager; mStatusBarStateController = statusBarStateController; @@ -91,12 +89,7 @@ public class OnUserInteractionCallbackImpl implements OnUserInteractionCallback new DismissedByUserStats( dismissalSurface, DISMISS_SENTIMENT_NEUTRAL, - NotificationVisibility.obtain( - entry.getKey(), - entry.getRanking().getRank(), - mNotifPipeline.getShadeListCount(), - true, - NotificationLogger.getNotificationLocation(entry))) + mVisibilityProvider.obtain(entry, true)) ); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationVisibilityProvider.kt new file mode 100644 index 0000000000000..5c70f32dfd253 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationVisibilityProvider.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.legacy + +import com.android.internal.statusbar.NotificationVisibility +import com.android.systemui.statusbar.notification.NotificationEntryManager +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider +import com.android.systemui.statusbar.notification.logging.NotificationLogger +import javax.inject.Inject + +/** Legacy pipeline implementation for getting [NotificationVisibility]. */ +class LegacyNotificationVisibilityProvider @Inject constructor( + private val notifEntryManager: NotificationEntryManager +) : NotificationVisibilityProvider { + override fun obtain(entry: NotificationEntry, visible: Boolean): NotificationVisibility { + val count: Int = notifEntryManager.activeNotificationsCount + val rank = entry.ranking.rank + val hasRow = entry.row != null + val location = NotificationLogger.getNotificationLocation(entry) + return NotificationVisibility.obtain(entry.key, rank, count, visible && hasRow, location) + } + + override fun obtain(key: String, visible: Boolean): NotificationVisibility { + val entry: NotificationEntry? = notifEntryManager.getActiveNotificationUnfiltered(key) + val count: Int = notifEntryManager.activeNotificationsCount + val rank = entry?.ranking?.rank ?: -1 + val hasRow = entry?.row != null + val location = NotificationLogger.getNotificationLocation(entry) + return NotificationVisibility.obtain(key, rank, count, visible && hasRow, location) + } + + override fun getLocation(key: String): NotificationVisibility.NotificationLocation = + NotificationLogger.getNotificationLocation( + notifEntryManager.getActiveNotificationUnfiltered(key)) +} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java index 11f22ddf1bd07..3b114bbfd33a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java @@ -22,13 +22,12 @@ import android.annotation.Nullable; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationStats; -import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -37,6 +36,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager; */ public class OnUserInteractionCallbackImplLegacy implements OnUserInteractionCallback { private final NotificationEntryManager mNotificationEntryManager; + private final NotificationVisibilityProvider mVisibilityProvider; private final HeadsUpManager mHeadsUpManager; private final StatusBarStateController mStatusBarStateController; private final VisualStabilityManager mVisualStabilityManager; @@ -44,12 +44,14 @@ public class OnUserInteractionCallbackImplLegacy implements OnUserInteractionCal public OnUserInteractionCallbackImplLegacy( NotificationEntryManager notificationEntryManager, + NotificationVisibilityProvider visibilityProvider, HeadsUpManager headsUpManager, StatusBarStateController statusBarStateController, VisualStabilityManager visualStabilityManager, GroupMembershipManager groupMembershipManager ) { mNotificationEntryManager = notificationEntryManager; + mVisibilityProvider = visibilityProvider; mHeadsUpManager = headsUpManager; mStatusBarStateController = statusBarStateController; mVisualStabilityManager = visualStabilityManager; @@ -88,12 +90,7 @@ public class OnUserInteractionCallbackImplLegacy implements OnUserInteractionCal new DismissedByUserStats( dismissalSurface, DISMISS_SENTIMENT_NEUTRAL, - NotificationVisibility.obtain( - entry.getKey(), - entry.getRanking().getRank(), - mNotificationEntryManager.getActiveNotificationsCount(), - true, - NotificationLogger.getNotificationLocation(entry))), + mVisibilityProvider.obtain(entry, true)), cancellationReason ); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java index b4c2bb8b6d3b1..471c3571418ed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.collection.notifcollection; +import androidx.annotation.Nullable; + import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -45,4 +47,10 @@ public interface CommonNotifCollection { * The returned collection is read-only, unsorted, unfiltered, and ungrouped. */ Collection getAllNotifs(); + + /** + * Returns the notification entry for the given notification key; + * the returned entry (if present) may be in any state. + */ + @Nullable NotificationEntry getEntry(String key); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProvider.kt new file mode 100644 index 0000000000000..c492d141e07bb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProvider.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.render + +import com.android.internal.statusbar.NotificationVisibility +import com.android.systemui.statusbar.notification.collection.NotificationEntry + +/** + * An interface for getting the current [NotificationVisibility] object for a notification. + */ +interface NotificationVisibilityProvider { + /** Given a notification entry, return the visibility object */ + fun obtain(entry: NotificationEntry, visible: Boolean): NotificationVisibility + /** Given a notification key, return the visibility object */ + fun obtain(key: String, visible: Boolean): NotificationVisibility + /** Given a notification key, return the location */ + fun getLocation(key: String): NotificationVisibility.NotificationLocation +} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProviderImpl.kt new file mode 100644 index 0000000000000..51de08d539b65 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProviderImpl.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.render + +import com.android.internal.statusbar.NotificationVisibility +import com.android.systemui.statusbar.notification.collection.NotifPipeline +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.logging.NotificationLogger +import javax.inject.Inject + +/** New pipeline implementation for getting [NotificationVisibility]. */ +class NotificationVisibilityProviderImpl @Inject constructor( + private val notifPipeline: NotifPipeline +) : NotificationVisibilityProvider { + override fun obtain(entry: NotificationEntry, visible: Boolean): NotificationVisibility { + val count: Int = notifPipeline.getShadeListCount() + val rank = entry.ranking.rank + val hasRow = entry.row != null + val location = NotificationLogger.getNotificationLocation(entry) + return NotificationVisibility.obtain(entry.key, rank, count, visible && hasRow, location) + } + + override fun obtain(key: String, visible: Boolean): NotificationVisibility = + notifPipeline.getEntry(key)?.let { return obtain(it, visible) } + ?: NotificationVisibility.obtain(key, -1, notifPipeline.getShadeListCount(), false) + + override fun getLocation(key: String): NotificationVisibility.NotificationLocation = + NotificationLogger.getNotificationLocation(notifPipeline.getEntry(key)) +} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 1eb007e345ec4..a711ed0187ad1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -52,6 +52,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.NotifInf import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl; import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationPresenterExtensions; +import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationVisibilityProvider; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.OnUserInteractionCallbackImplLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; @@ -63,6 +64,8 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl; import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager; import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProviderImpl; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl; import com.android.systemui.statusbar.notification.init.NotificationsControllerStub; @@ -208,6 +211,8 @@ public interface NotificationsModule { static NotificationLogger provideNotificationLogger( NotificationListener notificationListener, @UiBackground Executor uiBgExecutor, + FeatureFlags featureFlags, + NotificationVisibilityProvider visibilityProvider, NotificationEntryManager entryManager, StatusBarStateController statusBarStateController, NotificationLogger.ExpansionStateLogger expansionStateLogger, @@ -215,6 +220,8 @@ public interface NotificationsModule { return new NotificationLogger( notificationListener, uiBgExecutor, + featureFlags, + visibilityProvider, entryManager, statusBarStateController, expansionStateLogger, @@ -277,6 +284,20 @@ public interface NotificationsModule { return featureFlags.isNewNotifPipelineRenderingEnabled() ? pipeline.get() : entryManager; } + /** + * Provide the object which can be used to obtain NotificationVisibility objects. + */ + @Provides + @SysUISingleton + static NotificationVisibilityProvider provideNotificationVisibilityProvider( + FeatureFlags featureFlags, + Lazy newProvider, + Lazy legacyProvider) { + return featureFlags.isNewNotifPipelineRenderingEnabled() + ? newProvider.get() + : legacyProvider.get(); + } + /** * Provide the active implementation for presenting notifications. */ @@ -301,15 +322,15 @@ public interface NotificationsModule { FeatureFlags featureFlags, HeadsUpManager headsUpManager, StatusBarStateController statusBarStateController, - Lazy pipeline, Lazy notifCollection, + Lazy visibilityProvider, Lazy visualStabilityCoordinator, NotificationEntryManager entryManager, VisualStabilityManager visualStabilityManager, Lazy groupMembershipManagerLazy) { return featureFlags.isNewNotifPipelineRenderingEnabled() ? new OnUserInteractionCallbackImpl( - pipeline.get(), + visibilityProvider.get(), notifCollection.get(), headsUpManager, statusBarStateController, @@ -317,6 +338,7 @@ public interface NotificationsModule { groupMembershipManagerLazy.get()) : new OnUserInteractionCallbackImplLegacy( entryManager, + visibilityProvider.get(), headsUpManager, statusBarStateController, visualStabilityManager, 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 4441270f895b0..cd82fff3e9b48 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 @@ -33,6 +33,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.dagger.qualifiers.UiBackground; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.NotificationListener; @@ -40,6 +41,7 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -70,6 +72,8 @@ public class NotificationLogger implements StateListener { // Dependencies: private final NotificationListenerService mNotificationListener; private final Executor mUiBgExecutor; + private final FeatureFlags mFeatureFlags; + private final NotificationVisibilityProvider mVisibilityProvider; private final NotificationEntryManager mEntryManager; private final NotificationPanelLogger mNotificationPanelLogger; private final ExpansionStateLogger mExpansionStateLogger; @@ -127,6 +131,8 @@ public class NotificationLogger implements StateListener { // notifications. // 3. Report newly visible and no-longer visible notifications. // 4. Keep currently visible notifications for next report. + // TODO(b/204764064): support new pipeline + mFeatureFlags.checkLegacyPipelineEnabled(); List activeNotifications = mEntryManager.getVisibleNotifications(); int N = activeNotifications.size(); for (int i = 0; i < N; i++) { @@ -202,12 +208,16 @@ public class NotificationLogger implements StateListener { */ public NotificationLogger(NotificationListener notificationListener, @UiBackground Executor uiBgExecutor, + FeatureFlags featureFlags, + NotificationVisibilityProvider visibilityProvider, NotificationEntryManager entryManager, StatusBarStateController statusBarStateController, ExpansionStateLogger expansionStateLogger, NotificationPanelLogger notificationPanelLogger) { mNotificationListener = notificationListener; mUiBgExecutor = uiBgExecutor; + mFeatureFlags = featureFlags; + mVisibilityProvider = visibilityProvider; mEntryManager = entryManager; mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); @@ -407,6 +417,8 @@ public class NotificationLogger implements StateListener { // Once we know panelExpanded and Dozing, turn logging on & off when appropriate boolean lockscreen = mLockscreen == null ? false : mLockscreen; if (mPanelExpanded && !mDozing) { + // TODO(b/204764064): support new pipeline + mFeatureFlags.checkLegacyPipelineEnabled(); mNotificationPanelLogger.logPanelShown(lockscreen, mEntryManager.getVisibleNotifications()); if (DEBUG) { @@ -440,8 +452,7 @@ public class NotificationLogger implements StateListener { * Called when the notification is expanded / collapsed. */ public void onExpansionChanged(String key, boolean isUserAction, boolean isExpanded) { - NotificationVisibility.NotificationLocation location = - getNotificationLocation(mEntryManager.getActiveNotificationUnfiltered(key)); + NotificationVisibility.NotificationLocation location = mVisibilityProvider.getLocation(key); mExpansionStateLogger.onExpansionChanged(key, isUserAction, isExpanded, location); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 8b8b64d108862..949299610dd67 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -58,7 +58,6 @@ import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; -import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.ExpandHelper; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; @@ -99,6 +98,7 @@ import com.android.systemui.statusbar.notification.collection.legacy.VisualStabi import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController; import com.android.systemui.statusbar.notification.dagger.SilentHeader; import com.android.systemui.statusbar.notification.logging.NotificationLogger; @@ -145,6 +145,7 @@ public class NotificationStackScrollLayoutController { private final boolean mAllowLongPress; private final NotificationGutsManager mNotificationGutsManager; + private final NotificationVisibilityProvider mVisibilityProvider; private final HeadsUpManagerPhone mHeadsUpManager; private final NotificationRoundnessManager mNotificationRoundnessManager; private final TunerService mTunerService; @@ -618,6 +619,7 @@ public class NotificationStackScrollLayoutController { public NotificationStackScrollLayoutController( @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, NotificationGutsManager notificationGutsManager, + NotificationVisibilityProvider visibilityProvider, HeadsUpManagerPhone headsUpManager, NotificationRoundnessManager notificationRoundnessManager, TunerService tunerService, @@ -655,6 +657,7 @@ public class NotificationStackScrollLayoutController { ShadeController shadeController) { mAllowLongPress = allowLongPress; mNotificationGutsManager = notificationGutsManager; + mVisibilityProvider = visibilityProvider; mHeadsUpManager = headsUpManager; mNotificationRoundnessManager = notificationRoundnessManager; mTunerService = tunerService; @@ -1384,19 +1387,11 @@ public class NotificationStackScrollLayoutController { mView.resetCheckSnoozeLeavebehind(); } - private DismissedByUserStats getDismissedByUserStats( - NotificationEntry entry, - int numVisibleEntries - ) { + private DismissedByUserStats getDismissedByUserStats(NotificationEntry entry) { return new DismissedByUserStats( DISMISSAL_SHADE, DISMISS_SENTIMENT_NEUTRAL, - NotificationVisibility.obtain( - entry.getKey(), - entry.getRanking().getRank(), - numVisibleEntries, - true, - NotificationLogger.getNotificationLocation(entry))); + mVisibilityProvider.obtain(entry, true)); } /** @@ -1447,13 +1442,10 @@ public class NotificationStackScrollLayoutController { } else { final List> entriesWithRowsDismissedFromShade = new ArrayList<>(); - final int numVisibleEntries = mNotifPipeline.getShadeListCount(); for (ExpandableNotificationRow row : viewsToRemove) { final NotificationEntry entry = row.getEntry(); entriesWithRowsDismissedFromShade.add( - new Pair<>( - entry, - getDismissedByUserStats(entry, numVisibleEntries))); + new Pair<>(entry, getDismissedByUserStats(entry))); } mNotifCollection.dismissNotifications(entriesWithRowsDismissedFromShade); } @@ -1462,9 +1454,7 @@ public class NotificationStackScrollLayoutController { if (canChildBeDismissed(rowToRemove)) { mNotificationEntryManager.performRemoveNotification( rowToRemove.getEntry().getSbn(), - getDismissedByUserStats( - rowToRemove.getEntry(), - mNotificationEntryManager.getActiveNotificationsCount()), + getDismissedByUserStats(rowToRemove.getEntry()), NotificationListenerService.REASON_CANCEL_ALL); } else { rowToRemove.resetTranslation(); 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 dba3b2418790c..c2e790fcc6fbf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -68,8 +68,8 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowDragController; import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; @@ -97,6 +97,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final NotificationEntryManager mEntryManager; private final NotifPipeline mNotifPipeline; + private final NotificationVisibilityProvider mVisibilityProvider; private final HeadsUpManagerPhone mHeadsUpManager; private final ActivityStarter mActivityStarter; private final NotificationClickNotifier mClickNotifier; @@ -136,6 +137,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit Executor uiBgExecutor, NotificationEntryManager entryManager, NotifPipeline notifPipeline, + NotificationVisibilityProvider visibilityProvider, HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter, NotificationClickNotifier clickNotifier, @@ -171,6 +173,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mUiBgExecutor = uiBgExecutor; mEntryManager = entryManager; mNotifPipeline = notifPipeline; + mVisibilityProvider = visibilityProvider; mHeadsUpManager = headsUpManager; mActivityStarter = activityStarter; mClickNotifier = clickNotifier; @@ -366,10 +369,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mAssistManagerLazy.get().hideAssist(); } - NotificationVisibility.NotificationLocation location = - NotificationLogger.getNotificationLocation(entry); - final NotificationVisibility nv = NotificationVisibility.obtain(entry.getKey(), - entry.getRanking().getRank(), getVisibleNotificationsCount(), true, location); + final NotificationVisibility nv = mVisibilityProvider.obtain(entry, true); // retrieve the group summary to remove with this entry before we tell NMS the // notification was clicked to avoid a race condition @@ -414,10 +414,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit public void onDragSuccess(NotificationEntry entry) { // this method is not responsible for intent sending. // will focus follow operation only after drag-and-drop that notification. - NotificationVisibility.NotificationLocation location = - NotificationLogger.getNotificationLocation(entry); - final NotificationVisibility nv = NotificationVisibility.obtain(entry.getKey(), - entry.getRanking().getRank(), getVisibleNotificationsCount(), true, location); + final NotificationVisibility nv = mVisibilityProvider.obtain(entry, true); // retrieve the group summary to remove with this entry before we tell NMS the // notification was clicked to avoid a race condition @@ -681,6 +678,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final Executor mUiBgExecutor; private final NotificationEntryManager mEntryManager; private final NotifPipeline mNotifPipeline; + private final NotificationVisibilityProvider mVisibilityProvider; private final HeadsUpManagerPhone mHeadsUpManager; private final ActivityStarter mActivityStarter; private final NotificationClickNotifier mClickNotifier; @@ -719,6 +717,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @UiBackground Executor uiBgExecutor, NotificationEntryManager entryManager, NotifPipeline notifPipeline, + NotificationVisibilityProvider visibilityProvider, HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter, NotificationClickNotifier clickNotifier, @@ -749,6 +748,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mUiBgExecutor = uiBgExecutor; mEntryManager = entryManager; mNotifPipeline = notifPipeline; + mVisibilityProvider = visibilityProvider; mHeadsUpManager = headsUpManager; mActivityStarter = activityStarter; mClickNotifier = clickNotifier; @@ -813,6 +813,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mUiBgExecutor, mEntryManager, mNotifPipeline, + mVisibilityProvider, mHeadsUpManager, mActivityStarter, mClickNotifier, diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java index 291c64dd6daf2..4aad9b6b33291 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java @@ -76,8 +76,8 @@ import com.android.systemui.statusbar.notification.collection.coordinator.Bubble import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ZenModeController; @@ -109,6 +109,7 @@ public class BubblesManager implements Dumpable { private final ShadeController mShadeController; private final IStatusBarService mBarService; private final INotificationManager mNotificationManager; + private final NotificationVisibilityProvider mVisibilityProvider; private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; private final NotificationGroupManagerLegacy mNotificationGroupManager; private final NotificationEntryManager mNotificationEntryManager; @@ -132,6 +133,7 @@ public class BubblesManager implements Dumpable { ConfigurationController configurationController, @Nullable IStatusBarService statusBarService, INotificationManager notificationManager, + NotificationVisibilityProvider visibilityProvider, NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, @@ -146,6 +148,7 @@ public class BubblesManager implements Dumpable { return new BubblesManager(context, bubblesOptional.get(), notificationShadeWindowController, statusBarStateController, shadeController, configurationController, statusBarService, notificationManager, + visibilityProvider, interruptionStateProvider, zenModeController, notifUserManager, groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager, sysuiMainExecutor); @@ -163,6 +166,7 @@ public class BubblesManager implements Dumpable { ConfigurationController configurationController, @Nullable IStatusBarService statusBarService, INotificationManager notificationManager, + NotificationVisibilityProvider visibilityProvider, NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, @@ -178,6 +182,7 @@ public class BubblesManager implements Dumpable { mNotificationShadeWindowController = notificationShadeWindowController; mShadeController = shadeController; mNotificationManager = notificationManager; + mVisibilityProvider = visibilityProvider; mNotificationInterruptStateProvider = interruptionStateProvider; mNotificationGroupManager = groupManager; mNotificationEntryManager = entryManager; @@ -598,12 +603,7 @@ public class BubblesManager implements Dumpable { return new DismissedByUserStats( DISMISSAL_BUBBLE, DISMISS_SENTIMENT_NEUTRAL, - NotificationVisibility.obtain( - entry.getKey(), - entry.getRanking().getRank(), - mNotificationEntryManager.getActiveNotificationsCount(), - isVisible, - NotificationLogger.getNotificationLocation(entry))); + mVisibilityProvider.obtain(entry, isVisible)); } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java index d8ba164851ede..99f21ad4d5087 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java @@ -21,7 +21,9 @@ import static android.view.Display.DEFAULT_DISPLAY; import static com.google.common.truth.Truth.assertThat; 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.mock; import static org.mockito.Mockito.never; @@ -43,8 +45,9 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubble; @@ -76,7 +79,9 @@ public class LaunchConversationActivityTest extends SysuiTestCase { private LaunchConversationActivity mActivity; @Mock - private NotificationEntryManager mNotificationEntryManager; + private NotificationVisibilityProvider mVisibilityProvider; + @Mock + private CommonNotifCollection mNotifCollection; @Mock private IStatusBarService mIStatusBarService; @Mock @@ -104,8 +109,13 @@ public class LaunchConversationActivityTest extends SysuiTestCase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mActivity = new LaunchConversationActivity(mNotificationEntryManager, - Optional.of(mBubblesManager), mUserManager, mCommandQueue); + mActivity = new LaunchConversationActivity( + mVisibilityProvider, + mNotifCollection, + Optional.of(mBubblesManager), + mUserManager, + mCommandQueue + ); verify(mCommandQueue, times(1)).addCallback(mCallbacksCaptor.capture()); mActivity.setIsForTesting(true, mIStatusBarService); @@ -114,19 +124,26 @@ public class LaunchConversationActivityTest extends SysuiTestCase { mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, PACKAGE_NAME); mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE, USER_HANDLE); - when(mNotificationEntryManager.getActiveNotificationsCount()).thenReturn(NOTIF_COUNT); - when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY)).thenReturn(mNotifEntry); - when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY_NO_ENTRY)) - .thenReturn(null); - when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY_NO_RANKING)) - .thenReturn(mNotifEntryNoRanking); - when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY_CAN_BUBBLE)) - .thenReturn(mNotifEntryCanBubble); + when(mNotifCollection.getEntry(NOTIF_KEY)).thenReturn(mNotifEntry); + when(mNotifCollection.getEntry(NOTIF_KEY_NO_ENTRY)).thenReturn(null); + when(mNotifCollection.getEntry(NOTIF_KEY_NO_RANKING)).thenReturn(mNotifEntryNoRanking); + when(mNotifCollection.getEntry(NOTIF_KEY_CAN_BUBBLE)).thenReturn(mNotifEntryCanBubble); + when(mVisibilityProvider.obtain(anyString(), anyBoolean())).thenAnswer( + invocation-> { + String key = invocation.getArgument(0); + boolean visible = invocation.getArgument(1); + return NotificationVisibility.obtain(key, NOTIF_RANK, NOTIF_COUNT, visible); + }); + when(mVisibilityProvider.obtain(any(NotificationEntry.class), anyBoolean())).thenAnswer( + invocation-> { + String key = invocation.getArgument(0).getKey(); + boolean visible = invocation.getArgument(1); + return NotificationVisibility.obtain(key, NOTIF_RANK, NOTIF_COUNT, visible); + }); when(mNotifEntry.getRanking()).thenReturn(mRanking); when(mNotifEntryCanBubble.getRanking()).thenReturn(mRanking); when(mNotifEntryCanBubble.canBubble()).thenReturn(true); when(mNotifEntryNoRanking.getRanking()).thenReturn(null); - when(mRanking.getRank()).thenReturn(NOTIF_RANK); when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false); } @@ -173,8 +190,12 @@ public class LaunchConversationActivityTest extends SysuiTestCase { assertThat(mActivity.isFinishing()).isTrue(); mCallbacksCaptor.getValue().appTransitionFinished(DEFAULT_DISPLAY); + // Ensure callback removed + verify(mCommandQueue).removeCallback(any()); + // Clear the notification for bubbles. verify(mIStatusBarService, times(1)).onNotificationClear(any(), anyInt(), any(), anyInt(), anyInt(), mNotificationVisibilityCaptor.capture()); + // Do not select the bubble. verify(mBubblesManager, never()).expandStackAndSelectBubble(any(Bubble.class)); verify(mBubblesManager, never()).expandStackAndSelectBubble(any(NotificationEntry.class)); @@ -194,6 +215,8 @@ public class LaunchConversationActivityTest extends SysuiTestCase { assertThat(mActivity.isFinishing()).isTrue(); mCallbacksCaptor.getValue().appTransitionFinished(DEFAULT_DISPLAY); + // Ensure callback removed + verify(mCommandQueue).removeCallback(any()); // Don't clear the notification for bubbles. verify(mIStatusBarService, never()).onNotificationClear(any(), anyInt(), any(), anyInt(), anyInt(), any()); @@ -211,10 +234,14 @@ public class LaunchConversationActivityTest extends SysuiTestCase { mActivity.onCreate(new Bundle()); assertThat(mActivity.isFinishing()).isTrue(); - mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY); + mCallbacksCaptor.getValue().appTransitionFinished(DEFAULT_DISPLAY); + // Ensure callback removed + verify(mCommandQueue).removeCallback(any()); + // Don't clear the notification for bubbles. verify(mIStatusBarService, never()).onNotificationClear(any(), anyInt(), any(), anyInt(), anyInt(), any()); + // Do not select the bubble. verify(mBubblesManager, never()).expandStackAndSelectBubble(any(Bubble.class)); verify(mBubblesManager, never()).expandStackAndSelectBubble(any(NotificationEntry.class)); } @@ -233,6 +260,9 @@ public class LaunchConversationActivityTest extends SysuiTestCase { assertThat(mActivity.isFinishing()).isTrue(); mCallbacksCaptor.getValue().appTransitionFinished(DEFAULT_DISPLAY); + // Ensure callback removed + verify(mCommandQueue).removeCallback(any()); + // Select the bubble. verify(mBubblesManager, times(1)).expandStackAndSelectBubble(eq(bubble)); } } 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 23cca727335e9..0946ffddf709b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -57,11 +57,13 @@ import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager.KeyguardNotificationSuppressor; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -84,6 +86,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { // Dependency mocks: @Mock + private NotificationVisibilityProvider mVisibilityProvider; + @Mock private NotificationEntryManager mEntryManager; @Mock private DevicePolicyManager mDevicePolicyManager; @@ -96,6 +100,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; @Mock + private FeatureFlags mFeatureFlags; + @Mock private BroadcastDispatcher mBroadcastDispatcher; @Mock private KeyguardStateController mKeyguardStateController; @@ -416,9 +422,11 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { public TestNotificationLockscreenUserManager(Context context) { super( context, + mFeatureFlags, mBroadcastDispatcher, mDevicePolicyManager, mUserManager, + (() -> mVisibilityProvider), mClickNotifier, NotificationLockscreenUserManagerTest.this.mKeyguardManager, mStatusBarStateController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java index 4ed7224703341..8e4b98f1e0486 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java @@ -47,6 +47,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager.LegacyRemot import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.RemoteInputUriController; @@ -70,7 +71,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { private static final String TEST_PACKAGE_NAME = "test"; private static final int TEST_UID = 0; - @Mock private NotificationPresenter mPresenter; + @Mock private NotificationVisibilityProvider mVisibilityProvider; @Mock private RemoteInputController.Delegate mDelegate; @Mock private NotificationRemoteInputManager.Callback mCallback; @Mock private RemoteInputController mController; @@ -101,6 +102,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { mock(FeatureFlags.class), mLockscreenUserManager, mSmartReplyController, + mVisibilityProvider, mEntryManager, mock(RemoteInputNotificationRebuilder.class), () -> Optional.of(mock(StatusBar.class)), @@ -191,6 +193,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { FeatureFlags featureFlags, NotificationLockscreenUserManager lockscreenUserManager, SmartReplyController smartReplyController, + NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, RemoteInputNotificationRebuilder rebuilder, Lazy> statusBarOptionalLazy, @@ -205,6 +208,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { featureFlags, lockscreenUserManager, smartReplyController, + visibilityProvider, notificationEntryManager, rebuilder, statusBarOptionalLazy, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java index 99c965a9e57f1..8b28fd5b48409 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java @@ -44,6 +44,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.RemoteInputUriController; @@ -71,7 +72,7 @@ public class SmartReplyControllerTest extends SysuiTestCase { private SmartReplyController mSmartReplyController; private NotificationRemoteInputManager mRemoteInputManager; - @Mock private NotificationPresenter mPresenter; + @Mock private NotificationVisibilityProvider mVisibilityProvider; @Mock private RemoteInputController.Delegate mDelegate; @Mock private NotificationRemoteInputManager.Callback mCallback; @Mock private StatusBarNotification mSbn; @@ -89,7 +90,7 @@ public class SmartReplyControllerTest extends SysuiTestCase { mSmartReplyController = new SmartReplyController( mock(DumpManager.class), - mNotificationEntryManager, + mVisibilityProvider, mIStatusBarService, mClickNotifier); mDependency.injectTestDependency(SmartReplyController.class, @@ -97,7 +98,9 @@ public class SmartReplyControllerTest extends SysuiTestCase { mRemoteInputManager = new NotificationRemoteInputManager(mContext, mock(FeatureFlags.class), - mock(NotificationLockscreenUserManager.class), mSmartReplyController, + mock(NotificationLockscreenUserManager.class), + mSmartReplyController, + mVisibilityProvider, mNotificationEntryManager, new RemoteInputNotificationRebuilder(mContext), () -> Optional.of(mock(StatusBar.class)), 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 c979dc637fde8..2165e48e57c4b 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 @@ -41,6 +41,7 @@ import com.android.internal.logging.InstanceId; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.SysuiTestCase; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateControllerImpl; @@ -48,6 +49,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.logging.nano.Notifications; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -81,6 +83,8 @@ public class NotificationLoggerTest extends SysuiTestCase { @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger; // Dependency mocks: + @Mock private FeatureFlags mFeatureFlags; + @Mock private NotificationVisibilityProvider mVisibilityProvider; @Mock private NotificationEntryManager mEntryManager; @Mock private NotificationListener mListener; @Captor private ArgumentCaptor mEntryListenerCaptor; @@ -108,9 +112,16 @@ public class NotificationLoggerTest extends SysuiTestCase { .build(); mEntry.setRow(mRow); - mLogger = new TestableNotificationLogger(mListener, mUiBgExecutor, - mEntryManager, mock(StatusBarStateControllerImpl.class), mBarService, - mExpansionStateLogger); + mLogger = new TestableNotificationLogger( + mListener, + mUiBgExecutor, + mFeatureFlags, + mVisibilityProvider, + mEntryManager, + mock(StatusBarStateControllerImpl.class), + mBarService, + mExpansionStateLogger + ); mLogger.setUpWithContainer(mListContainer); verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture()); } @@ -244,12 +255,22 @@ public class NotificationLoggerTest extends SysuiTestCase { TestableNotificationLogger(NotificationListener notificationListener, Executor uiBgExecutor, + FeatureFlags featureFlags, + NotificationVisibilityProvider visibilityProvider, NotificationEntryManager entryManager, StatusBarStateControllerImpl statusBarStateController, IStatusBarService barService, ExpansionStateLogger expansionStateLogger) { - super(notificationListener, uiBgExecutor, entryManager, statusBarStateController, - expansionStateLogger, mNotificationPanelLoggerFake); + super( + notificationListener, + uiBgExecutor, + featureFlags, + visibilityProvider, + entryManager, + statusBarStateController, + expansionStateLogger, + mNotificationPanelLoggerFake + ); mBarService = barService; // Make this on the current thread so we can wait for it during tests. mHandler = Handler.createAsync(Looper.myLooper()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index baed694e6fa0c..f26bb75f6e754 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -64,6 +64,7 @@ import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView; @@ -97,6 +98,7 @@ import org.mockito.MockitoAnnotations; public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Mock private NotificationGutsManager mNotificationGutsManager; + @Mock private NotificationVisibilityProvider mVisibilityProvider; @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock private NotificationRoundnessManager mNotificationRoundnessManager; @Mock private TunerService mTunerService; @@ -151,6 +153,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mController = new NotificationStackScrollLayoutController( true, mNotificationGutsManager, + mVisibilityProvider, mHeadsUpManager, mNotificationRoundnessManager, mTunerService, 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 72a3d664a6ce1..7791fd015441a 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 @@ -22,6 +22,7 @@ import static org.mockito.AdditionalAnswers.answerVoid; 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; @@ -68,6 +69,7 @@ import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorCon import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; @@ -123,6 +125,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { private FeatureFlags mFeatureFlags; @Mock private NotifPipeline mNotifPipeline; + @Mock + private NotificationVisibilityProvider mVisibilityProvider; @Mock private ActivityIntentHelper mActivityIntentHelper; @@ -179,6 +183,11 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false); when(mOnUserInteractionCallback.getGroupSummaryToDismiss(mNotificationRow.getEntry())) .thenReturn(null); + when(mVisibilityProvider.obtain(anyString(), anyBoolean())).thenAnswer( + invocation-> NotificationVisibility.obtain(invocation.getArgument(0), 0, 1, false)); + when(mVisibilityProvider.obtain(any(NotificationEntry.class), anyBoolean())).thenAnswer( + invocation-> NotificationVisibility.obtain( + invocation.getArgument(0).getKey(), 0, 1, false)); HeadsUpManagerPhone headsUpManager = mock(HeadsUpManagerPhone.class); NotificationLaunchAnimatorControllerProvider notificationAnimationProvider = @@ -195,6 +204,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mUiBgExecutor, mEntryManager, mNotifPipeline, + mVisibilityProvider, headsUpManager, mActivityStarter, mClickNotifier, 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 e2bd62a06d113..9180b5357075d 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 @@ -121,6 +121,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl; @@ -272,6 +273,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private StatusBarIconController mIconController; @Mock private LockscreenShadeTransitionController mLockscreenTransitionController; @Mock private FeatureFlags mFeatureFlags; + @Mock private NotificationVisibilityProvider mVisibilityProvider; @Mock private WallpaperManager mWallpaperManager; @Mock private IWallpaperManager mIWallpaperManager; @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; @@ -309,9 +311,16 @@ public class StatusBarTest extends SysuiTestCase { mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class)); mMetricsLogger = new FakeMetricsLogger(); - NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener, - mUiBgExecutor, mock(NotificationEntryManager.class), mStatusBarStateController, - mExpansionStateLogger, new NotificationPanelLoggerFake()); + NotificationLogger notificationLogger = new NotificationLogger( + mNotificationListener, + mUiBgExecutor, + mFeatureFlags, + mVisibilityProvider, + mock(NotificationEntryManager.class), + mStatusBarStateController, + mExpansionStateLogger, + new NotificationPanelLoggerFake() + ); notificationLogger.setVisibilityReporter(mock(Runnable.class)); when(mCommandQueue.asBinder()).thenReturn(new Binder()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 15a92dcf26b78..c900ad59468f5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -92,6 +92,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.phone.DozeParameters; @@ -228,6 +229,8 @@ public class BubblesTest extends SysuiTestCase { @Mock private IStatusBarService mStatusBarService; @Mock + private NotificationVisibilityProvider mVisibilityProvider; + @Mock private LauncherApps mLauncherApps; @Mock private WindowManagerShellWrapper mWindowManagerShellWrapper; @@ -354,6 +357,7 @@ public class BubblesTest extends SysuiTestCase { mConfigurationController, mStatusBarService, mock(INotificationManager.class), + mVisibilityProvider, interruptionStateProvider, mZenModeController, mLockscreenUserManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java index 43b181ed3ab94..5ab2113735ebc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java @@ -78,6 +78,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.phone.DozeParameters; @@ -204,6 +205,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { @Mock private IStatusBarService mStatusBarService; @Mock + private NotificationVisibilityProvider mVisibilityProvider; + @Mock private LauncherApps mLauncherApps; @Mock private WindowManagerShellWrapper mWindowManagerShellWrapper; @@ -319,6 +322,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { mConfigurationController, mStatusBarService, mock(INotificationManager.class), + mVisibilityProvider, interruptionStateProvider, mZenModeController, mLockscreenUserManager, From 1c8ed43c5d693dd9f2db0ae866c30b3753f5d2ee Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Tue, 2 Nov 2021 16:14:20 -0400 Subject: [PATCH 2/3] New Pipeline: LockscreenUserManager now uses the CommonNotifCollection for queries Fixes: 204764178 Test: atest NotificationLockscreenUserManagerTest NotificationLockscreenUserManagerGoogleTest Change-Id: I456135f23ee0949faec0202250e26a632dc8a5c5 --- ...NotificationLockscreenUserManagerImpl.java | 28 ++++++++----------- .../NotificationEntryManager.java | 16 +++++++++-- .../NotificationEntryManagerLogger.kt | 10 +++++++ ...NotificationLockscreenUserManagerTest.java | 8 +++--- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 1311abe971670..fa2ef30f7b02d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -51,12 +51,12 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -89,8 +89,8 @@ public class NotificationLockscreenUserManagerImpl implements // Lazy private NotificationEntryManager mEntryManager; - private final FeatureFlags mFeatureFlags; private final Lazy mVisibilityProviderLazy; + private final Lazy mCommonNotifCollectionLazy; private final DevicePolicyManager mDevicePolicyManager; private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray(); private final SparseBooleanArray mUsersWithSeperateWorkChallenge = new SparseBooleanArray(); @@ -195,11 +195,11 @@ public class NotificationLockscreenUserManagerImpl implements @Inject public NotificationLockscreenUserManagerImpl(Context context, - FeatureFlags featureFlags, BroadcastDispatcher broadcastDispatcher, DevicePolicyManager devicePolicyManager, UserManager userManager, Lazy visibilityProviderLazy, + Lazy commonNotifCollectionLazy, NotificationClickNotifier clickNotifier, KeyguardManager keyguardManager, StatusBarStateController statusBarStateController, @@ -208,12 +208,12 @@ public class NotificationLockscreenUserManagerImpl implements KeyguardStateController keyguardStateController, DumpManager dumpManager) { mContext = context; - mFeatureFlags = featureFlags; mMainHandler = mainHandler; mDevicePolicyManager = devicePolicyManager; mUserManager = userManager; mCurrentUserId = ActivityManager.getCurrentUser(); mVisibilityProviderLazy = visibilityProviderLazy; + mCommonNotifCollectionLazy = commonNotifCollectionLazy; mClickNotifier = clickNotifier; statusBarStateController.addCallback(this); mLockPatternUtils = new LockPatternUtils(context); @@ -339,22 +339,18 @@ public class NotificationLockscreenUserManagerImpl implements * package-specific override. */ public boolean shouldHideNotifications(String key) { - // TODO(b/204764178): support new pipeline - mFeatureFlags.checkLegacyPipelineEnabled(); - if (getEntryManager() == null) { - Log.wtf(TAG, "mEntryManager was null!", new Throwable()); + if (mCommonNotifCollectionLazy.get() == null) { + Log.wtf(TAG, "mCommonNotifCollectionLazy was null!", new Throwable()); return true; } - NotificationEntry visibleEntry = getEntryManager().getActiveNotificationUnfiltered(key); + NotificationEntry visibleEntry = mCommonNotifCollectionLazy.get().getEntry(key); return isLockscreenPublicMode(mCurrentUserId) && visibleEntry != null && visibleEntry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET; } public boolean shouldShowOnKeyguard(NotificationEntry entry) { - // TODO(b/204764178): support new pipeline - mFeatureFlags.checkLegacyPipelineEnabled(); - if (getEntryManager() == null) { - Log.wtf(TAG, "mEntryManager was null!", new Throwable()); + if (mCommonNotifCollectionLazy.get() == null) { + Log.wtf(TAG, "mCommonNotifCollectionLazy was null!", new Throwable()); return false; } for (int i = 0; i < mKeyguardSuppressors.size(); i++) { @@ -526,13 +522,11 @@ public class NotificationLockscreenUserManagerImpl implements } private boolean packageHasVisibilityOverride(String key) { - // TODO(b/204764178): support new pipeline - mFeatureFlags.checkLegacyPipelineEnabled(); - if (getEntryManager() == null) { + if (mCommonNotifCollectionLazy.get() == null) { Log.wtf(TAG, "mEntryManager was null!", new Throwable()); return true; } - NotificationEntry entry = getEntryManager().getActiveNotificationUnfiltered(key); + NotificationEntry entry = mCommonNotifCollectionLazy.get().getEntry(key); return entry != null && entry.getRanking().getLockscreenVisibilityOverride() == Notification.VISIBILITY_PRIVATE; 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 a0daf8c255697..82f35a814d226 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -721,8 +721,12 @@ public class NotificationEntryManager implements * @param reason why the notifications are updating */ public void updateNotifications(String reason) { + if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { + mLogger.logUseWhileNewPipelineActive("updateNotifications", reason); + return; + } reapplyFilterAndSort(reason); - if (mPresenter != null && !mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { + if (mPresenter != null) { mPresenter.updateNotificationViews(reason); } } @@ -880,11 +884,19 @@ public class NotificationEntryManager implements /** Resorts / filters the current notification set with the current RankingMap */ public void reapplyFilterAndSort(String reason) { + if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { + mLogger.logUseWhileNewPipelineActive("reapplyFilterAndSort", reason); + return; + } updateRankingAndSort(mRanker.getRankingMap(), reason); } /** Calls to NotificationRankingManager and updates mSortedAndFiltered */ private void updateRankingAndSort(@NonNull RankingMap rankingMap, String reason) { + if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { + mLogger.logUseWhileNewPipelineActive("updateRankingAndSort", reason); + return; + } mSortedAndFiltered.clear(); mSortedAndFiltered.addAll(mRanker.updateRanking( rankingMap, mActiveNotifications.values(), reason)); @@ -892,7 +904,7 @@ public class NotificationEntryManager implements /** dump the current active notification list. Called from StatusBar */ public void dump(PrintWriter pw, String indent) { - pw.println("NotificationEntryManager"); + pw.println("NotificationEntryManager (Legacy)"); int filteredLen = mSortedAndFiltered.size(); pw.print(indent); pw.println("active notifications: " + filteredLen); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt index 4382ab50390a3..2397005a1a61a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogLevel.DEBUG import com.android.systemui.log.LogLevel.INFO +import com.android.systemui.log.LogLevel.WARNING import com.android.systemui.log.dagger.NotificationLog import javax.inject.Inject @@ -95,6 +96,15 @@ class NotificationEntryManagerLogger @Inject constructor( "FILTER AND SORT reason=$str1" }) } + + fun logUseWhileNewPipelineActive(method: String, reason: String) { + buffer.log(TAG, WARNING, { + str1 = method + str2 = reason + }, { + "While running New Pipeline: $str1(reason=$str2)" + }) + } } private const val TAG = "NotificationEntryMgr" \ No newline at end of file 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 0946ffddf709b..48f820626face 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -57,12 +57,12 @@ import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager.KeyguardNotificationSuppressor; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -90,6 +90,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { @Mock private NotificationEntryManager mEntryManager; @Mock + private CommonNotifCollection mNotifCollection; + @Mock private DevicePolicyManager mDevicePolicyManager; @Mock private NotificationClickNotifier mClickNotifier; @@ -100,8 +102,6 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; @Mock - private FeatureFlags mFeatureFlags; - @Mock private BroadcastDispatcher mBroadcastDispatcher; @Mock private KeyguardStateController mKeyguardStateController; @@ -422,11 +422,11 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { public TestNotificationLockscreenUserManager(Context context) { super( context, - mFeatureFlags, mBroadcastDispatcher, mDevicePolicyManager, mUserManager, (() -> mVisibilityProvider), + (() -> mNotifCollection), mClickNotifier, NotificationLockscreenUserManagerTest.this.mKeyguardManager, mStatusBarStateController, From 5385b5c789456ae2e5c9a1ae35b4e6a21561a1ac Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Tue, 2 Nov 2021 21:34:31 -0400 Subject: [PATCH 3/3] New Pipeline: Update NotificationLogger to use NotifPipeline Fixes: 204764064 Test: atest NotifPipelineTest NotificationLoggerTest NotificationLoggerLegacyTest Change-Id: I4a4422a898c908439ba914703561e89b3ad81b21 --- .../{NotifPipeline.java => NotifPipeline.kt} | 199 ++++++------ .../dagger/NotificationsModule.java | 2 + .../logging/NotificationLogger.java | 47 ++- .../collection/NotifPipelineTest.kt | 81 +++++ .../ConversationCoordinatorTest.kt | 8 +- .../coordinator/GutsCoordinatorTest.kt | 12 +- .../coordinator/ShadeEventCoordinatorTest.kt | 12 +- .../SmartspaceDedupingCoordinatorTest.kt | 33 +- .../logging/NotificationLoggerLegacyTest.java | 283 ++++++++++++++++++ .../logging/NotificationLoggerTest.java | 30 +- .../statusbar/phone/StatusBarTest.java | 2 + .../util/mockito/KotlinMockitoHelpers.kt | 27 +- 12 files changed, 564 insertions(+), 172 deletions(-) rename packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/{NotifPipeline.java => NotifPipeline.kt} (61%) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.kt similarity index 61% rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.kt index 642cca6ffcb9b..50d7324df2b44 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.kt @@ -13,32 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package com.android.systemui.statusbar.notification.collection -package com.android.systemui.statusbar.notification.collection; - -import androidx.annotation.Nullable; - -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener; -import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; -import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener; -import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager; -import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; -import com.android.systemui.statusbar.notification.collection.notifcollection.InternalNotifUpdater; -import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; -import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor; -import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; - -import java.util.Collection; -import java.util.List; - -import javax.inject.Inject; +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener +import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener +import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener +import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection +import com.android.systemui.statusbar.notification.collection.notifcollection.InternalNotifUpdater +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender +import javax.inject.Inject /** * The system that constructs the "shade list", the filtered, grouped, and sorted list of @@ -50,42 +43,33 @@ import javax.inject.Inject; * This list differs from the canonical one we receive from system server in a few ways: * - Filtered: Some notifications are filtered out. For example, we filter out notifications whose * views haven't been inflated yet. We also filter out some notifications if we're on the lock - * screen and notifications for other users. So participate, see - * {@link #addPreGroupFilter} and similar methods. + * screen and notifications for other users. To participate, see + * [.addPreGroupFilter] and similar methods. * - Grouped: Notifications that are part of the same group are clustered together into a single * GroupEntry. These groups are then transformed in order to remove children or completely split - * them apart. To participate, see {@link #addPromoter}. + * them apart. To participate, see [.addPromoter]. * - Sorted: All top-level notifications are sorted. To participate, see - * {@link #setSections} and {@link #setComparators} + * [.setSections] and [.setComparators] * * The exact order of all hooks is as follows: - * 0. Collection listeners are fired ({@link #addCollectionListener}). - * 1. Pre-group filters are fired on each notification ({@link #addPreGroupFilter}). + * 0. Collection listeners are fired ([.addCollectionListener]). + * 1. Pre-group filters are fired on each notification ([.addPreGroupFilter]). * 2. Initial grouping is performed (NotificationEntries will have their parents set * appropriately). - * 3. OnBeforeTransformGroupListeners are fired ({@link #addOnBeforeTransformGroupsListener}) - * 4. NotifPromoters are called on each notification with a parent ({@link #addPromoter}) - * 5. OnBeforeSortListeners are fired ({@link #addOnBeforeSortListener}) - * 6. Top-level entries are assigned sections by NotifSections ({@link #setSections}) - * 7. Top-level entries within the same section are sorted by NotifComparators - * ({@link #setComparators}) - * 8. Finalize filters are fired on each notification ({@link #addFinalizeFilter}) - * 9. OnBeforeRenderListListeners are fired ({@link #addOnBeforeRenderListListener}) - * 9. The list is handed off to the view layer to be rendered + * 3. OnBeforeTransformGroupListeners are fired ([.addOnBeforeTransformGroupsListener]) + * 4. NotifPromoters are called on each notification with a parent ([.addPromoter]) + * 5. Finalize filters are fired on each notification ([.addFinalizeFilter]) + * 6. OnBeforeSortListeners are fired ([.addOnBeforeSortListener]) + * 7. Top-level entries are assigned sections by NotifSections ([.setSections]) + * 8. Top-level entries within the same section are sorted by NotifComparators ([.setComparators]) + * 9. OnBeforeRenderListListeners are fired ([.addOnBeforeRenderListListener]) + * 10. The list is handed off to the view layer to be rendered */ @SysUISingleton -public class NotifPipeline implements CommonNotifCollection { - private final NotifCollection mNotifCollection; - private final ShadeListBuilder mShadeListBuilder; - - @Inject - public NotifPipeline( - NotifCollection notifCollection, - ShadeListBuilder shadeListBuilder) { - mNotifCollection = notifCollection; - mShadeListBuilder = shadeListBuilder; - } - +class NotifPipeline @Inject constructor( + private val mNotifCollection: NotifCollection, + private val mShadeListBuilder: ShadeListBuilder +) : CommonNotifCollection { /** * Returns the list of all known notifications, i.e. the notifications that are currently posted * to the phone. In general, this tracks closely to the list maintained by NotificationManager, @@ -93,39 +77,35 @@ public class NotifPipeline implements CommonNotifCollection { * * The returned collection is read-only, unsorted, unfiltered, and ungrouped. */ - @Override - public Collection getAllNotifs() { - return mNotifCollection.getAllNotifs(); + override fun getAllNotifs(): Collection { + return mNotifCollection.allNotifs } - @Override - public void addCollectionListener(NotifCollectionListener listener) { - mNotifCollection.addCollectionListener(listener); + override fun addCollectionListener(listener: NotifCollectionListener) { + mNotifCollection.addCollectionListener(listener) } /** * Returns the NotificationEntry associated with [key]. */ - @Override - @Nullable - public NotificationEntry getEntry(String key) { - return mNotifCollection.getEntry(key); + override fun getEntry(key: String): NotificationEntry? { + return mNotifCollection.getEntry(key) } /** * Registers a lifetime extender. Lifetime extenders can cause notifications that have been * dismissed or retracted by system server to be temporarily retained in the collection. */ - public void addNotificationLifetimeExtender(NotifLifetimeExtender extender) { - mNotifCollection.addNotificationLifetimeExtender(extender); + fun addNotificationLifetimeExtender(extender: NotifLifetimeExtender) { + mNotifCollection.addNotificationLifetimeExtender(extender) } /** * Registers a dismiss interceptor. Dismiss interceptors can cause notifications that have been * dismissed by the user to be retained (won't send a dismissal to system server). */ - public void addNotificationDismissInterceptor(NotifDismissInterceptor interceptor) { - mNotifCollection.addNotificationDismissInterceptor(interceptor); + fun addNotificationDismissInterceptor(interceptor: NotifDismissInterceptor) { + mNotifCollection.addNotificationDismissInterceptor(interceptor) } /** @@ -134,16 +114,16 @@ public class NotifPipeline implements CommonNotifCollection { * returns true, the notification is removed from the pipeline (and no other filters are * called on that notif). */ - public void addPreGroupFilter(NotifFilter filter) { - mShadeListBuilder.addPreGroupFilter(filter); + fun addPreGroupFilter(filter: NotifFilter) { + mShadeListBuilder.addPreGroupFilter(filter) } /** * Called after notifications have been filtered and after the initial grouping has been * performed but before NotifPromoters have had a chance to promote children out of groups. */ - public void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener) { - mShadeListBuilder.addOnBeforeTransformGroupsListener(listener); + fun addOnBeforeTransformGroupsListener(listener: OnBeforeTransformGroupsListener) { + mShadeListBuilder.addOnBeforeTransformGroupsListener(listener) } /** @@ -153,34 +133,34 @@ public class NotifPipeline implements CommonNotifCollection { * registered. If any promoter returns true, the notification is removed from the group (and no * other promoters are called on it). */ - public void addPromoter(NotifPromoter promoter) { - mShadeListBuilder.addPromoter(promoter); + fun addPromoter(promoter: NotifPromoter) { + mShadeListBuilder.addPromoter(promoter) } /** * Called after notifs have been filtered and groups have been determined but before sections * have been determined or the notifs have been sorted. */ - public void addOnBeforeSortListener(OnBeforeSortListener listener) { - mShadeListBuilder.addOnBeforeSortListener(listener); + fun addOnBeforeSortListener(listener: OnBeforeSortListener) { + mShadeListBuilder.addOnBeforeSortListener(listener) } /** * Sections that are used to sort top-level entries. If two entries have the same section, * NotifComparators are consulted. Sections from this list are called in order for each * notification passed through the pipeline. The first NotifSection to return true for - * {@link NotifSectioner#isInSection(ListEntry)} sets the entry as part of its Section. + * [NotifSectioner.isInSection] sets the entry as part of its Section. */ - public void setSections(List sections) { - mShadeListBuilder.setSectioners(sections); + fun setSections(sections: List) { + mShadeListBuilder.setSectioners(sections) } /** * StabilityManager that is used to determine whether to suppress group and section changes. * This should only be set once. */ - public void setVisualStabilityManager(NotifStabilityManager notifStabilityManager) { - mShadeListBuilder.setNotifStabilityManager(notifStabilityManager); + fun setVisualStabilityManager(notifStabilityManager: NotifStabilityManager) { + mShadeListBuilder.setNotifStabilityManager(notifStabilityManager) } /** @@ -188,16 +168,16 @@ public class NotifPipeline implements CommonNotifCollection { * comparators are executed in order until one of them returns a non-zero result. If all return * zero, the pipeline falls back to sorting by rank (and, failing that, Notification.when). */ - public void setComparators(List comparators) { - mShadeListBuilder.setComparators(comparators); + fun setComparators(comparators: List) { + mShadeListBuilder.setComparators(comparators) } /** * Called after notifs have been filtered once, grouped, and sorted but before the final * filtering. */ - public void addOnBeforeFinalizeFilterListener(OnBeforeFinalizeFilterListener listener) { - mShadeListBuilder.addOnBeforeFinalizeFilterListener(listener); + fun addOnBeforeFinalizeFilterListener(listener: OnBeforeFinalizeFilterListener) { + mShadeListBuilder.addOnBeforeFinalizeFilterListener(listener) } /** @@ -207,21 +187,21 @@ public class NotifPipeline implements CommonNotifCollection { * true, the notification is removed from the pipeline (and no other filters are called on that * notif). */ - public void addFinalizeFilter(NotifFilter filter) { - mShadeListBuilder.addFinalizeFilter(filter); + fun addFinalizeFilter(filter: NotifFilter) { + mShadeListBuilder.addFinalizeFilter(filter) } /** * Called at the end of the pipeline after the notif list has been finalized but before it has * been handed off to the view layer. */ - public void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) { - mShadeListBuilder.addOnBeforeRenderListListener(listener); + fun addOnBeforeRenderListListener(listener: OnBeforeRenderListListener) { + mShadeListBuilder.addOnBeforeRenderListListener(listener) } /** Registers an invalidator that can be used to invalidate the entire notif list. */ - public void addPreRenderInvalidator(Invalidator invalidator) { - mShadeListBuilder.addPreRenderInvalidator(invalidator); + fun addPreRenderInvalidator(invalidator: Invalidator) { + mShadeListBuilder.addPreRenderInvalidator(invalidator) } /** @@ -231,8 +211,8 @@ public class NotifPipeline implements CommonNotifCollection { * @param name the name of the component that will update notifiations * @return an updater */ - public InternalNotifUpdater getInternalNotifUpdater(String name) { - return mNotifCollection.getInternalNotifUpdater(name); + fun getInternalNotifUpdater(name: String?): InternalNotifUpdater { + return mNotifCollection.getInternalNotifUpdater(name) } /** @@ -240,8 +220,20 @@ public class NotifPipeline implements CommonNotifCollection { * are currently present in the shade. If this method is called during pipeline execution it * will return the current state of the list, which will likely be only partially-generated. */ - public List getShadeList() { - return mShadeListBuilder.getShadeList(); + val shadeList: List + get() = mShadeListBuilder.shadeList + + /** + * Constructs a flattened representation of the notification tree, where each group will have + * the summary (if present) followed by the children. + */ + fun getFlatShadeList(): List = shadeList.flatMap { entry -> + when (entry) { + is NotificationEntry -> sequenceOf(entry) + is GroupEntry -> (entry.summary?.let { sequenceOf(it) }.orEmpty() + + entry.children) + else -> throw RuntimeException("Unexpected entry $entry") + } } /** @@ -250,20 +242,9 @@ public class NotifPipeline implements CommonNotifCollection { * will return the number of notifications in its current state, which will likely be only * partially-generated. */ - public int getShadeListCount() { - final List entries = getShadeList(); - int numNotifs = 0; - for (int i = 0; i < entries.size(); i++) { - final ListEntry entry = entries.get(i); - if (entry instanceof GroupEntry) { - final GroupEntry parentEntry = (GroupEntry) entry; - numNotifs++; // include the summary in the count - numNotifs += parentEntry.getChildren().size(); - } else { - numNotifs++; - } - } - - return numNotifs; + fun getShadeListCount(): Int = shadeList.sumOf { entry -> + // include the summary in the count + if (entry is GroupEntry) 1 + entry.children.size + else 1 } -} +} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index a711ed0187ad1..a19549c5fc10c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -214,6 +214,7 @@ public interface NotificationsModule { FeatureFlags featureFlags, NotificationVisibilityProvider visibilityProvider, NotificationEntryManager entryManager, + NotifPipeline notifPipeline, StatusBarStateController statusBarStateController, NotificationLogger.ExpansionStateLogger expansionStateLogger, NotificationPanelLogger notificationPanelLogger) { @@ -223,6 +224,7 @@ public interface NotificationsModule { featureFlags, visibilityProvider, entryManager, + notifPipeline, statusBarStateController, expansionStateLogger, notificationPanelLogger); 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 cd82fff3e9b48..993e38dc0864c 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 @@ -26,6 +26,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.GuardedBy; @@ -40,7 +41,9 @@ import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; @@ -75,6 +78,7 @@ public class NotificationLogger implements StateListener { private final FeatureFlags mFeatureFlags; private final NotificationVisibilityProvider mVisibilityProvider; private final NotificationEntryManager mEntryManager; + private final NotifPipeline mNotifPipeline; private final NotificationPanelLogger mNotificationPanelLogger; private final ExpansionStateLogger mExpansionStateLogger; @@ -131,9 +135,7 @@ public class NotificationLogger implements StateListener { // notifications. // 3. Report newly visible and no-longer visible notifications. // 4. Keep currently visible notifications for next report. - // TODO(b/204764064): support new pipeline - mFeatureFlags.checkLegacyPipelineEnabled(); - List activeNotifications = mEntryManager.getVisibleNotifications(); + List activeNotifications = getVisibleNotifications(); int N = activeNotifications.size(); for (int i = 0; i < N; i++) { NotificationEntry entry = activeNotifications.get(i); @@ -172,6 +174,14 @@ public class NotificationLogger implements StateListener { } }; + private List getVisibleNotifications() { + if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { + return mNotifPipeline.getFlatShadeList(); + } else { + return mEntryManager.getVisibleNotifications(); + } + } + /** * Returns the location of the notification referenced by the given {@link NotificationEntry}. */ @@ -211,6 +221,7 @@ public class NotificationLogger implements StateListener { FeatureFlags featureFlags, NotificationVisibilityProvider visibilityProvider, NotificationEntryManager entryManager, + NotifPipeline notifPipeline, StatusBarStateController statusBarStateController, ExpansionStateLogger expansionStateLogger, NotificationPanelLogger notificationPanelLogger) { @@ -219,6 +230,7 @@ public class NotificationLogger implements StateListener { mFeatureFlags = featureFlags; mVisibilityProvider = visibilityProvider; mEntryManager = entryManager; + mNotifPipeline = notifPipeline; mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mExpansionStateLogger = expansionStateLogger; @@ -226,7 +238,15 @@ public class NotificationLogger implements StateListener { // Not expected to be destroyed, don't need to unsubscribe statusBarStateController.addCallback(this); - entryManager.addNotificationEntryListener(new NotificationEntryListener() { + if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { + registerNewPipelineListener(); + } else { + registerLegacyListener(); + } + } + + private void registerLegacyListener() { + mEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override public void onEntryRemoved( NotificationEntry entry, @@ -250,6 +270,20 @@ public class NotificationLogger implements StateListener { }); } + private void registerNewPipelineListener() { + mNotifPipeline.addCollectionListener(new NotifCollectionListener() { + @Override + public void onEntryUpdated(@NonNull NotificationEntry entry, boolean fromSystem) { + mExpansionStateLogger.onEntryUpdated(entry.getKey()); + } + + @Override + public void onEntryRemoved(@NonNull NotificationEntry entry, int reason) { + mExpansionStateLogger.onEntryRemoved(entry.getKey()); + } + }); + } + public void setUpWithContainer(NotificationListContainer listContainer) { mListContainer = listContainer; } @@ -417,10 +451,7 @@ public class NotificationLogger implements StateListener { // Once we know panelExpanded and Dozing, turn logging on & off when appropriate boolean lockscreen = mLockscreen == null ? false : mLockscreen; if (mPanelExpanded && !mDozing) { - // TODO(b/204764064): support new pipeline - mFeatureFlags.checkLegacyPipelineEnabled(); - mNotificationPanelLogger.logPanelShown(lockscreen, - mEntryManager.getVisibleNotifications()); + mNotificationPanelLogger.logPanelShown(lockscreen, getVisibleNotifications()); if (DEBUG) { Log.i(TAG, "Notification panel shown, lockscreen=" + lockscreen); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineTest.kt new file mode 100644 index 0000000000000..cf7174eea7cfa --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineTest.kt @@ -0,0 +1,81 @@ +/* + * 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.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class NotifPipelineTest : SysuiTestCase() { + + @Mock private lateinit var notifCollection: NotifCollection + @Mock private lateinit var shadeListBuilder: ShadeListBuilder + private lateinit var notifPipeline: NotifPipeline + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + notifPipeline = NotifPipeline(notifCollection, shadeListBuilder) + whenever(shadeListBuilder.shadeList).thenReturn(listOf( + NotificationEntryBuilder().setPkg("foo").setId(1).build(), + NotificationEntryBuilder().setPkg("foo").setId(2).build(), + group( + NotificationEntryBuilder().setPkg("bar").setId(1).build(), + NotificationEntryBuilder().setPkg("bar").setId(2).build(), + NotificationEntryBuilder().setPkg("bar").setId(3).build(), + NotificationEntryBuilder().setPkg("bar").setId(4).build() + ), + NotificationEntryBuilder().setPkg("baz").setId(1).build() + )) + } + + private fun group(summary: NotificationEntry, vararg children: NotificationEntry): GroupEntry { + return GroupEntry(summary.key, summary.creationTime).also { group -> + group.summary = summary + for (it in children) { + group.addChild(it) + } + } + } + + @Test + fun testGetShadeListCount() { + assertThat(notifPipeline.getShadeListCount()).isEqualTo(7) + } + + @Test + fun testGetFlatShadeList() { + assertThat(notifPipeline.getFlatShadeList().map { it.key }).containsExactly( + "0|foo|1|null|0", + "0|foo|2|null|0", + "0|bar|1|null|0", + "0|bar|2|null|0", + "0|bar|3|null|0", + "0|bar|4|null|0", + "0|baz|1|null|0" + ).inOrder() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt index 711f0bab50685..a46b440028129 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt @@ -29,12 +29,12 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.render.NodeController import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON +import com.android.systemui.util.mockito.withArgCaptor import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -65,9 +65,9 @@ class ConversationCoordinatorTest : SysuiTestCase() { coordinator.attach(pipeline) // capture arguments: - val notifPromoterCaptor = ArgumentCaptor.forClass(NotifPromoter::class.java) - verify(pipeline).addPromoter(notifPromoterCaptor.capture()) - promoter = notifPromoterCaptor.value + promoter = withArgCaptor { + verify(pipeline).addPromoter(capture()) + } peopleSectioner = coordinator.sectioner diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt index 0cba07033c63c..0f6bd771d3528 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt @@ -28,7 +28,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager import com.android.systemui.statusbar.notification.row.NotificationGuts -import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -60,13 +60,11 @@ class GutsCoordinatorTest : SysuiTestCase() { initMocks(this) coordinator = GutsCoordinator(notifGutsViewManager, logger, dumpManager) coordinator.attach(pipeline) - notifLifetimeExtender = argumentCaptor().let { - verify(pipeline).addNotificationLifetimeExtender(it.capture()) - it.value!! + notifLifetimeExtender = withArgCaptor { + verify(pipeline).addNotificationLifetimeExtender(capture()) } - notifGutsViewListener = argumentCaptor().let { - verify(notifGutsViewManager).setGutsListener(it.capture()) - it.value!! + notifGutsViewListener = withArgCaptor { + verify(notifGutsViewManager).setGutsListener(capture()) } notifLifetimeExtender.setCallback(lifetimeExtenderCallback) entry1 = NotificationEntryBuilder().setId(1).build() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt index 5915cd7823f0d..452af21c09d76 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt @@ -26,7 +26,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener -import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.withArgCaptor import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -56,13 +56,11 @@ class ShadeEventCoordinatorTest : SysuiTestCase() { initMocks(this) coordinator = ShadeEventCoordinator(logger) coordinator.attach(pipeline) - notifCollectionListener = argumentCaptor().let { - verify(pipeline).addCollectionListener(it.capture()) - it.value!! + notifCollectionListener = withArgCaptor { + verify(pipeline).addCollectionListener(capture()) } - onBeforeRenderListListener = argumentCaptor().let { - verify(pipeline).addOnBeforeRenderListListener(it.capture()) - it.value!! + onBeforeRenderListListener = withArgCaptor { + verify(pipeline).addOnBeforeRenderListListener(capture()) } coordinator.setNotifRemovedByUserCallback(notifRemovedByUserCallback) coordinator.setShadeEmptiedCallback(shadeEmptiedCallback) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt index a8db8d7617b7c..fdff6e9a52f31 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt @@ -35,15 +35,13 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import com.android.systemui.util.concurrency.FakeExecutor -import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.withArgCaptor import com.android.systemui.util.time.FakeSystemClock import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test -import org.mockito.ArgumentCaptor -import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.Mockito.anyString @@ -69,15 +67,6 @@ class SmartspaceDedupingCoordinatorTest : SysuiTestCase() { @Mock private lateinit var pluggableListener: Pluggable.PluggableListener - @Captor - private lateinit var filterCaptor: ArgumentCaptor - @Captor - private lateinit var collectionListenerCaptor: ArgumentCaptor - @Captor - private lateinit var stateListenerCaptor: ArgumentCaptor - @Captor - private lateinit var smartspaceListenerCaptor: ArgumentCaptor - private lateinit var filter: NotifFilter private lateinit var collectionListener: NotifCollectionListener private lateinit var statusBarListener: StatusBarStateController.StateListener @@ -118,18 +107,22 @@ class SmartspaceDedupingCoordinatorTest : SysuiTestCase() { // Attach the deduper and capture the listeners/filters that it registers deduper.attach(notifPipeline) - verify(notifPipeline).addPreGroupFilter(filterCaptor.capture()) - filter = filterCaptor.value + filter = withArgCaptor { + verify(notifPipeline).addPreGroupFilter(capture()) + } filter.setInvalidationListener(pluggableListener) - verify(notifPipeline).addCollectionListener(capture(collectionListenerCaptor)) - collectionListener = collectionListenerCaptor.value + collectionListener = withArgCaptor { + verify(notifPipeline).addCollectionListener(capture()) + } - verify(statusBarStateController).addCallback(capture(stateListenerCaptor)) - statusBarListener = stateListenerCaptor.value + statusBarListener = withArgCaptor { + verify(statusBarStateController).addCallback(capture()) + } - verify(smartspaceController).addListener(capture(smartspaceListenerCaptor)) - newTargetListener = smartspaceListenerCaptor.value + newTargetListener = withArgCaptor { + verify(smartspaceController).addListener(capture()) + } // Initialize some test data entry1HasRecentlyAlerted = NotificationEntryBuilder() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java new file mode 100644 index 0000000000000..4cf530e54e437 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java @@ -0,0 +1,283 @@ +/* + * 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.logging; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Notification; +import android.os.Handler; +import android.os.Looper; +import android.os.UserHandle; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.internal.logging.InstanceId; +import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateControllerImpl; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; +import com.android.systemui.statusbar.notification.logging.nano.Notifications; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; + +import com.google.android.collect.Lists; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executor; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class NotificationLoggerLegacyTest extends SysuiTestCase { + private static final String TEST_PACKAGE_NAME = "test"; + private static final int TEST_UID = 0; + + @Mock private NotificationListContainer mListContainer; + @Mock private IStatusBarService mBarService; + @Mock private ExpandableNotificationRow mRow; + @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger; + + // Dependency mocks: + @Mock private FeatureFlags mFeatureFlags; + @Mock private NotificationVisibilityProvider mVisibilityProvider; + @Mock private NotificationEntryManager mEntryManager; + @Mock private NotifPipeline mNotifPipeline; + @Mock private NotificationListener mListener; + + private NotificationEntry mEntry; + private TestableNotificationLogger mLogger; + private ConcurrentLinkedQueue mErrorQueue = new ConcurrentLinkedQueue<>(); + private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); + private NotificationPanelLoggerFake mNotificationPanelLoggerFake = + new NotificationPanelLoggerFake(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mEntry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setNotification(new Notification()) + .setUser(UserHandle.CURRENT) + .setInstanceId(InstanceId.fakeInstanceId(1)) + .build(); + mEntry.setRow(mRow); + + mLogger = new TestableNotificationLogger( + mListener, + mUiBgExecutor, + mFeatureFlags, + mVisibilityProvider, + mEntryManager, + mNotifPipeline, + mock(StatusBarStateControllerImpl.class), + mBarService, + mExpansionStateLogger + ); + mLogger.setUpWithContainer(mListContainer); + verify(mEntryManager).addNotificationEntryListener(any()); + verify(mNotifPipeline, never()).addCollectionListener(any()); + } + + @Test + public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception { + NotificationVisibility[] newlyVisibleKeys = { + NotificationVisibility.obtain(mEntry.getKey(), 0, 1, true) + }; + NotificationVisibility[] noLongerVisibleKeys = {}; + doAnswer(invocation -> { + try { + assertArrayEquals(newlyVisibleKeys, + (NotificationVisibility[]) invocation.getArguments()[0]); + assertArrayEquals(noLongerVisibleKeys, + (NotificationVisibility[]) invocation.getArguments()[1]); + } catch (AssertionError error) { + mErrorQueue.offer(error); + } + return null; + } + ).when(mBarService).onNotificationVisibilityChanged(any(NotificationVisibility[].class), + any(NotificationVisibility[].class)); + + when(mListContainer.isInVisibleLocation(any())).thenReturn(true); + when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); + mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); + TestableLooper.get(this).processAllMessages(); + mUiBgExecutor.runAllReady(); + + if (!mErrorQueue.isEmpty()) { + throw mErrorQueue.poll(); + } + + // |mEntry| won't change visibility, so it shouldn't be reported again: + Mockito.reset(mBarService); + mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); + TestableLooper.get(this).processAllMessages(); + mUiBgExecutor.runAllReady(); + + verify(mBarService, never()).onNotificationVisibilityChanged(any(), any()); + } + + @Test + public void testStoppingNotificationLoggingReportsCurrentNotifications() + throws Exception { + when(mListContainer.isInVisibleLocation(any())).thenReturn(true); + when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); + mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); + TestableLooper.get(this).processAllMessages(); + mUiBgExecutor.runAllReady(); + Mockito.reset(mBarService); + + setStateAsleep(); + mLogger.onDozingChanged(false); // Wake to lockscreen + mLogger.onDozingChanged(true); // And go back to sleep, turning off logging + mUiBgExecutor.runAllReady(); + // The visibility objects are recycled by NotificationLogger, so we can't use specific + // matchers here. + verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any()); + } + + private void setStateAsleep() { + mLogger.onPanelExpandedChanged(true); + mLogger.onDozingChanged(true); + mLogger.onStateChanged(StatusBarState.KEYGUARD); + } + + private void setStateAwake() { + mLogger.onPanelExpandedChanged(false); + mLogger.onDozingChanged(false); + mLogger.onStateChanged(StatusBarState.SHADE); + } + + @Test + public void testLogPanelShownOnWake() { + when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); + setStateAsleep(); + mLogger.onDozingChanged(false); // Wake to lockscreen + assertEquals(1, mNotificationPanelLoggerFake.getCalls().size()); + assertTrue(mNotificationPanelLoggerFake.get(0).isLockscreen); + assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length); + Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0]; + assertEquals(TEST_PACKAGE_NAME, n.packageName); + assertEquals(TEST_UID, n.uid); + assertEquals(1, n.instanceId); + assertFalse(n.isGroupSummary); + assertEquals(Notifications.Notification.SECTION_ALERTING, n.section); + } + + @Test + public void testLogPanelShownOnShadePull() { + when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); + setStateAwake(); + // Now expand panel + mLogger.onPanelExpandedChanged(true); + assertEquals(1, mNotificationPanelLoggerFake.getCalls().size()); + assertFalse(mNotificationPanelLoggerFake.get(0).isLockscreen); + assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length); + Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0]; + assertEquals(TEST_PACKAGE_NAME, n.packageName); + assertEquals(TEST_UID, n.uid); + assertEquals(1, n.instanceId); + assertFalse(n.isGroupSummary); + assertEquals(Notifications.Notification.SECTION_ALERTING, n.section); + } + + + @Test + public void testLogPanelShownHandlesNullInstanceIds() { + // Construct a NotificationEntry like mEntry, but with a null instance id. + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setNotification(new Notification()) + .setUser(UserHandle.CURRENT) + .build(); + entry.setRow(mRow); + + when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry)); + setStateAsleep(); + mLogger.onDozingChanged(false); // Wake to lockscreen + assertEquals(1, mNotificationPanelLoggerFake.getCalls().size()); + assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length); + Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0]; + assertEquals(0, n.instanceId); + } + + private class TestableNotificationLogger extends NotificationLogger { + + TestableNotificationLogger(NotificationListener notificationListener, + Executor uiBgExecutor, + FeatureFlags featureFlags, + NotificationVisibilityProvider visibilityProvider, + NotificationEntryManager entryManager, + NotifPipeline notifPipeline, + StatusBarStateControllerImpl statusBarStateController, + IStatusBarService barService, + ExpansionStateLogger expansionStateLogger) { + super( + notificationListener, + uiBgExecutor, + featureFlags, + visibilityProvider, + entryManager, + notifPipeline, + statusBarStateController, + expansionStateLogger, + mNotificationPanelLoggerFake + ); + mBarService = barService; + // Make this on the current thread so we can wait for it during tests. + mHandler = Handler.createAsync(Looper.myLooper()); + } + + OnChildLocationsChangedListener getChildLocationsChangedListenerForTest() { + return mNotificationLocationsChangedListener; + } + } +} 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 2165e48e57c4b..ba198efa47738 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 @@ -45,8 +45,8 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.StatusBarState; 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.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; @@ -61,8 +61,6 @@ import com.google.android.collect.Lists; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -86,8 +84,8 @@ public class NotificationLoggerTest extends SysuiTestCase { @Mock private FeatureFlags mFeatureFlags; @Mock private NotificationVisibilityProvider mVisibilityProvider; @Mock private NotificationEntryManager mEntryManager; + @Mock private NotifPipeline mNotifPipeline; @Mock private NotificationListener mListener; - @Captor private ArgumentCaptor mEntryListenerCaptor; private NotificationEntry mEntry; private TestableNotificationLogger mLogger; @@ -99,8 +97,7 @@ public class NotificationLoggerTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager); - mDependency.injectTestDependency(NotificationListener.class, mListener); + when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(true); mEntry = new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_NAME) @@ -118,12 +115,14 @@ public class NotificationLoggerTest extends SysuiTestCase { mFeatureFlags, mVisibilityProvider, mEntryManager, + mNotifPipeline, mock(StatusBarStateControllerImpl.class), mBarService, mExpansionStateLogger ); mLogger.setUpWithContainer(mListContainer); - verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture()); + verify(mEntryManager, never()).addNotificationEntryListener(any()); + verify(mNotifPipeline).addCollectionListener(any()); } @Test @@ -147,12 +146,12 @@ public class NotificationLoggerTest extends SysuiTestCase { any(NotificationVisibility[].class)); when(mListContainer.isInVisibleLocation(any())).thenReturn(true); - when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); + when(mNotifPipeline.getFlatShadeList()).thenReturn(Lists.newArrayList(mEntry)); mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); TestableLooper.get(this).processAllMessages(); mUiBgExecutor.runAllReady(); - if(!mErrorQueue.isEmpty()) { + if (!mErrorQueue.isEmpty()) { throw mErrorQueue.poll(); } @@ -169,7 +168,7 @@ public class NotificationLoggerTest extends SysuiTestCase { public void testStoppingNotificationLoggingReportsCurrentNotifications() throws Exception { when(mListContainer.isInVisibleLocation(any())).thenReturn(true); - when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); + when(mNotifPipeline.getFlatShadeList()).thenReturn(Lists.newArrayList(mEntry)); mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); TestableLooper.get(this).processAllMessages(); mUiBgExecutor.runAllReady(); @@ -198,7 +197,7 @@ public class NotificationLoggerTest extends SysuiTestCase { @Test public void testLogPanelShownOnWake() { - when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); + when(mNotifPipeline.getFlatShadeList()).thenReturn(Lists.newArrayList(mEntry)); setStateAsleep(); mLogger.onDozingChanged(false); // Wake to lockscreen assertEquals(1, mNotificationPanelLoggerFake.getCalls().size()); @@ -214,7 +213,7 @@ public class NotificationLoggerTest extends SysuiTestCase { @Test public void testLogPanelShownOnShadePull() { - when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); + when(mNotifPipeline.getFlatShadeList()).thenReturn(Lists.newArrayList(mEntry)); setStateAwake(); // Now expand panel mLogger.onPanelExpandedChanged(true); @@ -242,7 +241,7 @@ public class NotificationLoggerTest extends SysuiTestCase { .build(); entry.setRow(mRow); - when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry)); + when(mNotifPipeline.getFlatShadeList()).thenReturn(Lists.newArrayList(entry)); setStateAsleep(); mLogger.onDozingChanged(false); // Wake to lockscreen assertEquals(1, mNotificationPanelLoggerFake.getCalls().size()); @@ -258,6 +257,7 @@ public class NotificationLoggerTest extends SysuiTestCase { FeatureFlags featureFlags, NotificationVisibilityProvider visibilityProvider, NotificationEntryManager entryManager, + NotifPipeline notifPipeline, StatusBarStateControllerImpl statusBarStateController, IStatusBarService barService, ExpansionStateLogger expansionStateLogger) { @@ -267,6 +267,7 @@ public class NotificationLoggerTest extends SysuiTestCase { featureFlags, visibilityProvider, entryManager, + notifPipeline, statusBarStateController, expansionStateLogger, mNotificationPanelLoggerFake @@ -276,8 +277,7 @@ public class NotificationLoggerTest extends SysuiTestCase { mHandler = Handler.createAsync(Looper.myLooper()); } - OnChildLocationsChangedListener - getChildLocationsChangedListenerForTest() { + OnChildLocationsChangedListener getChildLocationsChangedListenerForTest() { return mNotificationLocationsChangedListener; } } 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 9180b5357075d..37428624db58a 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 @@ -117,6 +117,7 @@ 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.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; @@ -317,6 +318,7 @@ public class StatusBarTest extends SysuiTestCase { mFeatureFlags, mVisibilityProvider, mock(NotificationEntryManager.class), + mock(NotifPipeline.class), mStatusBarStateController, mExpansionStateLogger, new NotificationPanelLoggerFake() diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt b/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt index 483dc9fc42b29..eb54fe0ca1919 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt @@ -66,6 +66,27 @@ inline fun argumentCaptor(): ArgumentCaptor = */ inline fun mock(): T = Mockito.mock(T::class.java) +/** + * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when + * kotlin tests are mocking kotlin objects and the methods take non-null parameters: + * + * java.lang.NullPointerException: capture() must not be null + */ +class KotlinArgumentCaptor constructor(clazz: Class) { + private val wrapped: ArgumentCaptor = ArgumentCaptor.forClass(clazz) + fun capture(): T = wrapped.capture() + val value: T + get() = wrapped.value +} + +/** + * Helper function for creating an argumentCaptor in kotlin. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +inline fun kotlinArgumentCaptor(): KotlinArgumentCaptor = + KotlinArgumentCaptor(T::class.java) + /** * Helper function for creating and using a single-use ArgumentCaptor in kotlin. * @@ -76,6 +97,8 @@ inline fun mock(): T = Mockito.mock(T::class.java) * becomes: * * val captured = withArgCaptor { verify(...).someMethod(capture()) } + * + * NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException. */ -inline fun withArgCaptor(block: ArgumentCaptor.() -> Unit): T = - argumentCaptor().apply { block() }.value \ No newline at end of file +inline fun withArgCaptor(block: KotlinArgumentCaptor.() -> Unit): T = + kotlinArgumentCaptor().apply { block() }.value