diff options
| author | 2022-07-21 12:56:26 -0400 | |
|---|---|---|
| committer | 2022-08-12 16:46:31 +0000 | |
| commit | 2fa47f38ddfb7f0ba759d1bf90efbe23cfdc2877 (patch) | |
| tree | a30f65b1db4f7730f56afda7137bab0bc4806bb2 | |
| parent | f5a7752bf27bb78e6ba0070ac429ccd41b966573 (diff) | |
Remove dead code from NotifEntryManager
All removed code is unused; since all changes are relegated to
NotificationEntryManager.java, if this CL still builds, it is proof that
the code in question was not referenced anywhere (assuming no
reflection).
Bug: 200269355
Test: atest SystemUITests
Change-Id: If24a9a92c6af5c2edd4fe1b628bb720a6a12a311
Merged-In: If24a9a92c6af5c2edd4fe1b628bb720a6a12a311
48 files changed, 60 insertions, 7014 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 5c84ff38d761..614a87fc758c 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -87,7 +87,6 @@ import com.android.systemui.statusbar.events.PrivacyDotViewController; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; -import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; @@ -102,7 +101,6 @@ import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LockscreenGestureLogger; import com.android.systemui.statusbar.phone.ManagedProfileController; -import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -313,7 +311,6 @@ public class Dependency { @Inject Lazy<AccessibilityFloatingMenuController> mAccessibilityFloatingMenuController; @Inject Lazy<StatusBarStateController> mStatusBarStateController; @Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager; - @Inject Lazy<NotificationGroupAlertTransferHelper> mNotificationGroupAlertTransferHelper; @Inject Lazy<NotificationGroupManagerLegacy> mNotificationGroupManager; @Inject Lazy<VisualStabilityManager> mVisualStabilityManager; @Inject Lazy<NotificationGutsManager> mNotificationGutsManager; @@ -322,7 +319,6 @@ public class Dependency { @Inject Lazy<SmartReplyConstants> mSmartReplyConstants; @Inject Lazy<NotificationListener> mNotificationListener; @Inject Lazy<NotificationLogger> mNotificationLogger; - @Inject Lazy<NotificationFilter> mNotificationFilter; @Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil; @Inject Lazy<SmartReplyController> mSmartReplyController; @Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler; @@ -529,8 +525,6 @@ public class Dependency { mNotificationLockscreenUserManager::get); mProviders.put(VisualStabilityManager.class, mVisualStabilityManager::get); mProviders.put(NotificationGroupManagerLegacy.class, mNotificationGroupManager::get); - mProviders.put(NotificationGroupAlertTransferHelper.class, - mNotificationGroupAlertTransferHelper::get); mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get); mProviders.put(NotificationGutsManager.class, mNotificationGutsManager::get); mProviders.put(NotificationRemoteInputManager.class, @@ -538,7 +532,6 @@ public class Dependency { mProviders.put(SmartReplyConstants.class, mSmartReplyConstants::get); mProviders.put(NotificationListener.class, mNotificationListener::get); mProviders.put(NotificationLogger.class, mNotificationLogger::get); - mProviders.put(NotificationFilter.class, mNotificationFilter::get); mProviders.put(KeyguardDismissUtil.class, mKeyguardDismissUtil::get); mProviders.put(SmartReplyController.class, mSmartReplyController::get); mProviders.put(RemoteInputQuickSettingsDisabler.class, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java index 07455a02b2cf..15c75ffb8c13 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java @@ -37,7 +37,7 @@ import java.util.stream.Stream; * remove notifications that appear on screen for a period of time and dismiss themselves at the * appropriate time. These include heads up notifications and ambient pulses. */ -public abstract class AlertingNotificationManager implements NotificationLifetimeExtender { +public abstract class AlertingNotificationManager { private static final String TAG = "AlertNotifManager"; protected final Clock mClock = new Clock(); protected final ArrayMap<String, AlertEntry> mAlertEntries = new ArrayMap<>(); @@ -47,14 +47,6 @@ public abstract class AlertingNotificationManager implements NotificationLifetim mLogger = logger; } - /** - * This is the list of entries that have already been removed from the - * NotificationManagerService side, but we keep it to prevent the UI from looking weird and - * will remove when possible. See {@link NotificationLifetimeExtender} - */ - protected final ArraySet<NotificationEntry> mExtendedLifetimeAlertEntries = new ArraySet<>(); - - protected NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback; protected int mMinimumDisplayTime; protected int mAutoDismissNotificationDecay; @VisibleForTesting @@ -210,12 +202,6 @@ public abstract class AlertingNotificationManager implements NotificationLifetim onAlertEntryRemoved(alertEntry); entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); alertEntry.reset(); - if (mExtendedLifetimeAlertEntries.contains(entry)) { - if (mNotificationLifetimeFinishedCallback != null) { - mNotificationLifetimeFinishedCallback.onSafeToRemove(key); - } - mExtendedLifetimeAlertEntries.remove(entry); - } } /** @@ -244,19 +230,6 @@ public abstract class AlertingNotificationManager implements NotificationLifetim || alertEntry.mEntry.isRowDismissed(); } - /////////////////////////////////////////////////////////////////////////////////////////////// - // NotificationLifetimeExtender Methods - - @Override - public void setCallback(NotificationSafeToRemoveCallback callback) { - mNotificationLifetimeFinishedCallback = callback; - } - - @Override - public boolean shouldExtendLifetime(NotificationEntry entry) { - return !canRemoveImmediately(entry.getKey()); - } - /** * @param key * @return true if the entry is pinned @@ -281,20 +254,6 @@ public abstract class AlertingNotificationManager implements NotificationLifetim return 0; } - @Override - public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) { - if (shouldExtend) { - mExtendedLifetimeAlertEntries.add(entry); - // We need to make sure that entries are stopping to alert eventually, let's remove - // this as soon as possible. - AlertEntry alertEntry = mAlertEntries.get(entry.getKey()); - alertEntry.removeAsSoonAsPossible(); - } else { - mExtendedLifetimeAlertEntries.remove(entry); - } - } - /////////////////////////////////////////////////////////////////////////////////////////////// - protected class AlertEntry implements Comparable<AlertEntry> { @Nullable public NotificationEntry mEntry; public long mPostTime; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java deleted file mode 100644 index 48e2923c97d9..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.android.systemui.statusbar; - -import androidx.annotation.NonNull; - -import com.android.systemui.statusbar.notification.collection.NotificationEntry; - -/** - * Interface for anything that may need to keep notifications managed even after - * {@link NotificationListener} removes it. The lifetime extender is in charge of performing the - * callback when the notification is then safe to remove. - */ -public interface NotificationLifetimeExtender { - - /** - * Set the handler to callback to when the notification is safe to remove. - * - * @param callback the handler to callback - */ - void setCallback(@NonNull NotificationSafeToRemoveCallback callback); - - /** - * Determines whether or not the extender needs the notification kept after removal. - * - * @param entry the entry containing the notification to check - * @return true if the notification lifetime should be extended - */ - boolean shouldExtendLifetime(@NonNull NotificationEntry entry); - - /** - * It's possible that a notification was canceled before it ever became visible. This callback - * gives lifetime extenders a chance to make sure it shows up. For example if a foreground - * service is canceled too quickly but we still want to make sure a FGS notification shows. - * @param pendingEntry the canceled (but pending) entry - * @return true if the notification lifetime should be extended - */ - default boolean shouldExtendLifetimeForPendingNotification( - @NonNull NotificationEntry pendingEntry) { - return false; - } - - /** - * Sets whether or not the lifetime should be managed by the extender. In practice, if - * shouldManage is true, this is where the extender starts managing the entry internally and is - * now responsible for calling {@link NotificationSafeToRemoveCallback#onSafeToRemove(String)} - * when the entry is safe to remove. If shouldManage is false, the extender no longer needs to - * worry about it (either because we will be removing it anyway or the entry is no longer - * removed due to an update). - * - * @param entry the entry that needs an extended lifetime - * @param shouldManage true if the extender should manage the entry now, false otherwise - */ - void setShouldManageLifetime(@NonNull NotificationEntry entry, boolean shouldManage); - - /** - * The callback for when the notification is now safe to remove (i.e. its lifetime has ended). - */ - interface NotificationSafeToRemoveCallback { - /** - * Called when the lifetime extender determines it's safe to remove. - * - * @param key key of the entry that is now safe to remove - */ - void onSafeToRemove(String key); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 78b3b0a65351..d74d408ae59e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -24,7 +24,6 @@ import android.app.RemoteInput; import android.content.Context; import android.content.Intent; import android.content.pm.UserInfo; -import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -32,7 +31,6 @@ import android.os.SystemProperties; import android.os.UserManager; import android.service.notification.StatusBarNotification; import android.text.TextUtils; -import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.Log; import android.util.Pair; @@ -47,12 +45,10 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dumpable; import com.android.systemui.R; -import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule; @@ -75,7 +71,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.function.Consumer; import dagger.Lazy; @@ -100,8 +95,6 @@ public class NotificationRemoteInputManager implements Dumpable { private final NotificationLockscreenUserManager mLockscreenUserManager; private final SmartReplyController mSmartReplyController; private final NotificationVisibilityProvider mVisibilityProvider; - private final NotificationEntryManager mEntryManager; - private final Handler mMainHandler; private final ActionClickLogger mLogger; private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; @@ -110,7 +103,6 @@ public class NotificationRemoteInputManager implements Dumpable { protected final NotifPipelineFlags mNotifPipelineFlags; private final UserManager mUserManager; private final KeyguardManager mKeyguardManager; - private final RemoteInputNotificationRebuilder mRebuilder; private final StatusBarStateController mStatusBarStateController; private final RemoteInputUriController mRemoteInputUriController; private final NotificationClickNotifier mClickNotifier; @@ -265,10 +257,8 @@ public class NotificationRemoteInputManager implements Dumpable { SmartReplyController smartReplyController, NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, - RemoteInputNotificationRebuilder rebuilder, Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, StatusBarStateController statusBarStateController, - @Main Handler mainHandler, RemoteInputUriController remoteInputUriController, NotificationClickNotifier clickNotifier, ActionClickLogger logger, @@ -278,14 +268,11 @@ public class NotificationRemoteInputManager implements Dumpable { mLockscreenUserManager = lockscreenUserManager; mSmartReplyController = smartReplyController; mVisibilityProvider = visibilityProvider; - mEntryManager = notificationEntryManager; mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; - mMainHandler = mainHandler; mLogger = logger; mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - mRebuilder = rebuilder; mKeyguardManager = context.getSystemService(KeyguardManager.class); mStatusBarStateController = statusBarStateController; mRemoteInputUriController = remoteInputUriController; @@ -788,238 +775,4 @@ public class NotificationRemoteInputManager implements Dumpable { /** Called when the RemoteInputController is attached to the manager */ void setRemoteInputController(@NonNull RemoteInputController remoteInputController); } - - @VisibleForTesting - protected class LegacyRemoteInputLifetimeExtender implements RemoteInputListener, Dumpable { - - /** - * How long to wait before auto-dismissing a notification that was kept for remote input, - * and has now sent a remote input. We auto-dismiss, because the app may not see a reason to - * cancel these given that they technically don't exist anymore. We wait a bit in case the - * app issues an update. - */ - private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200; - - /** - * Notifications that are already removed but are kept around because we want to show the - * remote input history. See {@link RemoteInputHistoryExtender} and - * {@link SmartReplyHistoryExtender}. - */ - protected final ArraySet<String> mKeysKeptForRemoteInputHistory = new ArraySet<>(); - - /** - * Notifications that are already removed but are kept around because the remote input is - * actively being used (i.e. user is typing in it). See {@link RemoteInputActiveExtender}. - */ - protected final ArraySet<NotificationEntry> mEntriesKeptForRemoteInputActive = - new ArraySet<>(); - - protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback - mNotificationLifetimeFinishedCallback; - - protected final ArrayList<NotificationLifetimeExtender> mLifetimeExtenders = - new ArrayList<>(); - private RemoteInputController mRemoteInputController; - - LegacyRemoteInputLifetimeExtender() { - addLifetimeExtenders(); - } - - /** - * Adds all the notification lifetime extenders. Each extender represents a reason for the - * NotificationRemoteInputManager to keep a notification lifetime extended. - */ - protected void addLifetimeExtenders() { - mLifetimeExtenders.add(new RemoteInputHistoryExtender()); - mLifetimeExtenders.add(new SmartReplyHistoryExtender()); - mLifetimeExtenders.add(new RemoteInputActiveExtender()); - } - - @Override - public void setRemoteInputController(@NonNull RemoteInputController remoteInputController) { - mRemoteInputController= remoteInputController; - } - - @Override - public void onRemoteInputSent(@NonNull NotificationEntry entry) { - if (FORCE_REMOTE_INPUT_HISTORY - && isNotificationKeptForRemoteInputHistory(entry.getKey())) { - mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey()); - } else if (mEntriesKeptForRemoteInputActive.contains(entry)) { - // We're currently holding onto this notification, but from the apps point of - // view it is already canceled, so we'll need to cancel it on the apps behalf - // after sending - unless the app posts an update in the mean time, so wait a - // bit. - mMainHandler.postDelayed(() -> { - if (mEntriesKeptForRemoteInputActive.remove(entry)) { - mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey()); - } - }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY); - } - } - - @Override - public void onPanelCollapsed() { - for (int i = 0; i < mEntriesKeptForRemoteInputActive.size(); i++) { - NotificationEntry entry = mEntriesKeptForRemoteInputActive.valueAt(i); - if (mRemoteInputController != null) { - mRemoteInputController.removeRemoteInput(entry, null); - } - if (mNotificationLifetimeFinishedCallback != null) { - mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey()); - } - } - mEntriesKeptForRemoteInputActive.clear(); - } - - @Override - public boolean isNotificationKeptForRemoteInputHistory(@NonNull String key) { - return mKeysKeptForRemoteInputHistory.contains(key); - } - - @Override - public void releaseNotificationIfKeptForRemoteInputHistory( - @NonNull NotificationEntry entry) { - final String key = entry.getKey(); - if (isNotificationKeptForRemoteInputHistory(key)) { - mMainHandler.postDelayed(() -> { - if (isNotificationKeptForRemoteInputHistory(key)) { - mNotificationLifetimeFinishedCallback.onSafeToRemove(key); - } - }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY); - } - } - - @VisibleForTesting - public Set<NotificationEntry> getEntriesKeptForRemoteInputActive() { - return mEntriesKeptForRemoteInputActive; - } - - @Override - public void dump(@NonNull PrintWriter pw, - @NonNull String[] args) { - pw.println("LegacyRemoteInputLifetimeExtender:"); - pw.print(" mKeysKeptForRemoteInputHistory: "); - pw.println(mKeysKeptForRemoteInputHistory); - pw.print(" mEntriesKeptForRemoteInputActive: "); - pw.println(mEntriesKeptForRemoteInputActive); - } - - /** - * NotificationRemoteInputManager has multiple reasons to keep notification lifetime - * extended so we implement multiple NotificationLifetimeExtenders - */ - protected abstract class RemoteInputExtender implements NotificationLifetimeExtender { - @Override - public void setCallback(NotificationSafeToRemoveCallback callback) { - if (mNotificationLifetimeFinishedCallback == null) { - mNotificationLifetimeFinishedCallback = callback; - } - } - } - - /** - * Notification is kept alive as it was cancelled in response to a remote input interaction. - * This allows us to show what you replied and allows you to continue typing into it. - */ - protected class RemoteInputHistoryExtender extends RemoteInputExtender { - @Override - public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) { - return shouldKeepForRemoteInputHistory(entry); - } - - @Override - public void setShouldManageLifetime(NotificationEntry entry, - boolean shouldExtend) { - if (shouldExtend) { - StatusBarNotification newSbn = mRebuilder.rebuildForRemoteInputReply(entry); - entry.onRemoteInputInserted(); - - if (newSbn == null) { - return; - } - - mEntryManager.updateNotification(newSbn, null); - - // Ensure the entry hasn't already been removed. This can happen if there is an - // inflation exception while updating the remote history - if (entry.isRemoved()) { - return; - } - - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Keeping notification around after sending remote input " - + entry.getKey()); - } - - mKeysKeptForRemoteInputHistory.add(entry.getKey()); - } else { - mKeysKeptForRemoteInputHistory.remove(entry.getKey()); - } - } - } - - /** - * Notification is kept alive for smart reply history. Similar to REMOTE_INPUT_HISTORY but - * with {@link SmartReplyController} specific logic - */ - protected class SmartReplyHistoryExtender extends RemoteInputExtender { - @Override - public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) { - return shouldKeepForSmartReplyHistory(entry); - } - - @Override - public void setShouldManageLifetime(NotificationEntry entry, - boolean shouldExtend) { - if (shouldExtend) { - StatusBarNotification newSbn = mRebuilder.rebuildForCanceledSmartReplies(entry); - - if (newSbn == null) { - return; - } - - mEntryManager.updateNotification(newSbn, null); - - if (entry.isRemoved()) { - return; - } - - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Keeping notification around after sending smart reply " - + entry.getKey()); - } - - mKeysKeptForRemoteInputHistory.add(entry.getKey()); - } else { - mKeysKeptForRemoteInputHistory.remove(entry.getKey()); - mSmartReplyController.stopSending(entry); - } - } - } - - /** - * Notification is kept alive because the user is still using the remote input - */ - protected class RemoteInputActiveExtender extends RemoteInputExtender { - @Override - public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) { - return isRemoteInputActive(entry); - } - - @Override - public void setShouldManageLifetime(NotificationEntry entry, - boolean shouldExtend) { - if (shouldExtend) { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Keeping notification around while remote input active " - + entry.getKey()); - } - mEntriesKeptForRemoteInputActive.add(entry); - } else { - mEntriesKeptForRemoteInputActive.remove(entry); - } - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java index 0951e821cdc2..8752f92145db 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java @@ -115,10 +115,8 @@ public interface CentralSurfacesDependenciesModule { smartReplyController, visibilityProvider, notificationEntryManager, - rebuilder, centralSurfacesOptionalLazy, statusBarStateController, - mainHandler, remoteInputUriController, clickNotifier, actionClickLogger, 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 7583a98df308..e2f87b6f4ffe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -15,66 +15,22 @@ */ package com.android.systemui.statusbar.notification; -import static android.service.notification.NotificationListenerService.REASON_ERROR; - -import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN; -import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback; - -import android.app.Notification; -import android.app.NotificationChannel; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.Trace; -import android.os.UserHandle; import android.service.notification.NotificationListenerService; -import android.service.notification.NotificationListenerService.Ranking; -import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Log; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.statusbar.IStatusBarService; -import com.android.internal.statusbar.NotificationVisibility; -import com.android.systemui.Dumpable; -import com.android.systemui.dagger.qualifiers.Background; -import com.android.systemui.dump.DumpManager; -import com.android.systemui.statusbar.NotificationLifetimeExtender; -import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.NotificationListener.NotificationHandler; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationRemoveInterceptor; -import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; -import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationRanker; -import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationRankerStub; -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.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.util.Assert; -import com.android.systemui.util.Compile; -import com.android.systemui.util.leak.LeakDetector; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Executor; - -import dagger.Lazy; /** * NotificationEntryManager is responsible for the adding, removing, and updating of @@ -90,33 +46,10 @@ import dagger.Lazy; * inflated, an entry moves into the active state, where it _could_ potentially be shown to the * user. After an entry makes its way into the active state, we sort and filter the entire set to * repopulate the visible set. - * - * There are a few different things that other classes may be interested in, and most of them - * involve the current set of notifications. Here's a brief overview of things you may want to know: - * @see #getVisibleNotifications() for the visible set - * @see #getActiveNotificationUnfiltered(String) to check if a key exists - * @see #getPendingNotificationsIterator() for an iterator over the pending notifications - * @see #getPendingOrActiveNotif(String) to find a notification exists for that key in any list - * @see #getActiveNotificationsForCurrentUser() to see every notification that the current user owns */ -public class NotificationEntryManager implements - CommonNotifCollection, - Dumpable, - VisualStabilityManager.Callback { +public class NotificationEntryManager implements VisualStabilityManager.Callback { private final NotificationEntryManagerLogger mLogger; - private final NotificationGroupManagerLegacy mGroupManager; - private final NotifPipelineFlags mNotifPipelineFlags; - private final Lazy<NotificationRowBinder> mNotificationRowBinderLazy; - private final Lazy<NotificationRemoteInputManager> mRemoteInputManagerLazy; - private final LeakDetector mLeakDetector; - private final IStatusBarService mStatusBarService; - private final DumpManager mDumpManager; - private final Executor mBgExecutor; - - private final Set<NotificationEntry> mAllNotifications = new ArraySet<>(); - private final Set<NotificationEntry> mReadOnlyAllNotifications = - Collections.unmodifiableSet(mAllNotifications); /** Pending notifications are ones awaiting inflation */ @VisibleForTesting @@ -129,96 +62,14 @@ public class NotificationEntryManager implements /** This is the list of "active notifications for this user in this context" */ @VisibleForTesting protected final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>(); - private final List<NotificationEntry> mReadOnlyNotifications = - Collections.unmodifiableList(mSortedAndFiltered); - - private final Map<NotificationEntry, NotificationLifetimeExtender> mRetainedNotifications = - new ArrayMap<>(); - private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>(); - - private LegacyNotificationRanker mRanker = new LegacyNotificationRankerStub(); - private RankingMap mLatestRankingMap; - - @VisibleForTesting - final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders - = new ArrayList<>(); private final List<NotificationEntryListener> mNotificationEntryListeners = new ArrayList<>(); - private final List<NotificationRemoveInterceptor> mRemoveInterceptors = new ArrayList<>(); /** * Injected constructor. See {@link NotificationsModule}. */ - public NotificationEntryManager( - NotificationEntryManagerLogger logger, - NotificationGroupManagerLegacy groupManager, - NotifPipelineFlags notifPipelineFlags, - Lazy<NotificationRowBinder> notificationRowBinderLazy, - Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy, - LeakDetector leakDetector, - IStatusBarService statusBarService, - DumpManager dumpManager, - @Background Executor bgExecutor - ) { + public NotificationEntryManager(NotificationEntryManagerLogger logger) { mLogger = logger; - mGroupManager = groupManager; - mNotifPipelineFlags = notifPipelineFlags; - mNotificationRowBinderLazy = notificationRowBinderLazy; - mRemoteInputManagerLazy = notificationRemoteInputManagerLazy; - mLeakDetector = leakDetector; - mStatusBarService = statusBarService; - mDumpManager = dumpManager; - mBgExecutor = bgExecutor; - } - - /** Once called, the NEM will start processing notification events from system server. */ - public void initialize( - NotificationListener notificationListener, - LegacyNotificationRanker ranker) { - mRanker = ranker; - notificationListener.addNotificationHandler(mNotifListener); - mDumpManager.registerDumpable(this); - } - - @Override - public void dump(PrintWriter pw, String[] args) { - pw.println("NotificationEntryManager state:"); - pw.println(" mAllNotifications="); - if (mAllNotifications.size() == 0) { - pw.println("null"); - } else { - int i = 0; - for (NotificationEntry entry : mAllNotifications) { - dumpEntry(pw, " ", i, entry); - i++; - } - } - pw.print(" mPendingNotifications="); - if (mPendingNotifications.size() == 0) { - pw.println("null"); - } else { - for (NotificationEntry entry : mPendingNotifications.values()) { - pw.println(entry.getSbn()); - } - } - pw.println(" Remove interceptors registered:"); - for (NotificationRemoveInterceptor interceptor : mRemoveInterceptors) { - pw.println(" " + interceptor.getClass().getSimpleName()); - } - pw.println(" Lifetime extenders registered:"); - for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) { - pw.println(" " + extender.getClass().getSimpleName()); - } - pw.println(" Lifetime-extended notifications:"); - if (mRetainedNotifications.isEmpty()) { - pw.println(" None"); - } else { - for (Map.Entry<NotificationEntry, NotificationLifetimeExtender> entry - : mRetainedNotifications.entrySet()) { - pw.println(" " + entry.getKey().getSbn() + " retained by " - + entry.getValue().getClass().getName()); - } - } } /** Adds a {@link NotificationEntryListener}. */ @@ -234,501 +85,12 @@ public class NotificationEntryManager implements mNotificationEntryListeners.remove(listener); } - /** Add a {@link NotificationRemoveInterceptor}. */ - public void addNotificationRemoveInterceptor(NotificationRemoveInterceptor interceptor) { - mRemoveInterceptors.add(interceptor); - } - - /** Remove a {@link NotificationRemoveInterceptor} */ - public void removeNotificationRemoveInterceptor(NotificationRemoveInterceptor interceptor) { - mRemoveInterceptors.remove(interceptor); - } - - /** Adds multiple {@link NotificationLifetimeExtender}s. */ - public void addNotificationLifetimeExtenders(List<NotificationLifetimeExtender> extenders) { - for (NotificationLifetimeExtender extender : extenders) { - addNotificationLifetimeExtender(extender); - } - } - - /** Adds a {@link NotificationLifetimeExtender}. */ - public void addNotificationLifetimeExtender(NotificationLifetimeExtender extender) { - mNotificationLifetimeExtenders.add(extender); - extender.setCallback(key -> removeNotification(key, mLatestRankingMap, - UNDEFINED_DISMISS_REASON)); - } - @Override public void onChangeAllowed() { updateNotifications("reordering is now allowed"); } /** - * User requests a notification to be removed. - * - * @param n the notification to remove. - * @param reason why it is being removed e.g. {@link NotificationListenerService#REASON_CANCEL}, - * or 0 if unknown. - */ - public void performRemoveNotification( - StatusBarNotification n, - @NonNull DismissedByUserStats stats, - int reason - ) { - removeNotificationInternal( - n.getKey(), - null, - stats.notificationVisibility, - false /* forceRemove */, - stats, - reason); - } - - private NotificationVisibility obtainVisibility(String key) { - NotificationEntry e = mActiveNotifications.get(key); - final int rank; - if (e != null) { - rank = e.getRanking().getRank(); - } else { - rank = 0; - } - - final int count = mActiveNotifications.size(); - NotificationVisibility.NotificationLocation location = - NotificationLogger.getNotificationLocation(getActiveNotificationUnfiltered(key)); - return NotificationVisibility.obtain(key, rank, count, true, location); - } - - private void abortExistingInflation(String key, String reason) { - if (mPendingNotifications.containsKey(key)) { - NotificationEntry entry = mPendingNotifications.get(key); - entry.abortTask(); - mPendingNotifications.remove(key); - mLogger.logInflationAborted(key, "pending", reason); - } - NotificationEntry addedEntry = getActiveNotificationUnfiltered(key); - if (addedEntry != null) { - addedEntry.abortTask(); - mLogger.logInflationAborted(key, "active", reason); - } - } - - /** - * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService - * about the failure. - * - * WARNING: this will call back into us. Don't hold any locks. - */ - private void handleInflationException(StatusBarNotification n, Exception e) { - removeNotificationInternal( - n.getKey(), - null, - null, - true /* forceRemove */, - null /* dismissedByUserStats */, - REASON_ERROR); - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onInflationError(n, e); - } - } - - private final InflationCallback mInflationCallback = new InflationCallback() { - @Override - public void handleInflationException(NotificationEntry entry, Exception e) { - Trace.beginSection("NotificationEntryManager.handleInflationException"); - NotificationEntryManager.this.handleInflationException(entry.getSbn(), e); - Trace.endSection(); - } - - @Override - public void onAsyncInflationFinished(NotificationEntry entry) { - Trace.beginSection("NotificationEntryManager.onAsyncInflationFinished"); - mPendingNotifications.remove(entry.getKey()); - // If there was an async task started after the removal, we don't want to add it back to - // the list, otherwise we might get leaks. - if (!entry.isRowRemoved()) { - boolean isNew = getActiveNotificationUnfiltered(entry.getKey()) == null; - mLogger.logNotifInflated(entry.getKey(), isNew); - if (isNew) { - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onEntryInflated(entry); - } - addActiveNotification(entry); - updateNotifications("onAsyncInflationFinished"); - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onNotificationAdded(entry); - } - } else { - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onEntryReinflated(entry); - } - } - } - Trace.endSection(); - } - }; - - private final NotificationHandler mNotifListener = new NotificationHandler() { - @Override - public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { - final boolean isUpdateToInflatedNotif = mActiveNotifications.containsKey(sbn.getKey()); - if (isUpdateToInflatedNotif) { - updateNotification(sbn, rankingMap); - } else { - addNotification(sbn, rankingMap); - } - } - - @Override - public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) { - removeNotification(sbn.getKey(), rankingMap, UNDEFINED_DISMISS_REASON); - } - - @Override - public void onNotificationRemoved( - StatusBarNotification sbn, - RankingMap rankingMap, - int reason) { - removeNotification(sbn.getKey(), rankingMap, reason); - } - - @Override - public void onNotificationRankingUpdate(RankingMap rankingMap) { - updateNotificationRanking(rankingMap); - } - - @Override - public void onNotificationsInitialized() { - } - - @Override - public void onNotificationChannelModified( - String pkgName, - UserHandle user, - NotificationChannel channel, - int modificationType) { - notifyChannelModified(pkgName, user, channel, modificationType); - } - }; - - /** - * Equivalent to the old NotificationData#add - * @param entry - an entry which is prepared for display - */ - private void addActiveNotification(NotificationEntry entry) { - Assert.isMainThread(); - - mActiveNotifications.put(entry.getKey(), entry); - mGroupManager.onEntryAdded(entry); - updateRankingAndSort(mRanker.getRankingMap(), "addEntryInternalInternal"); - } - - /** - * Available so that tests can directly manipulate the list of active notifications easily - * - * @param entry the entry to add directly to the visible notification map - */ - @VisibleForTesting - public void addActiveNotificationForTest(NotificationEntry entry) { - mActiveNotifications.put(entry.getKey(), entry); - mGroupManager.onEntryAdded(entry); - - reapplyFilterAndSort("addVisibleNotification"); - } - - @VisibleForTesting - protected void removeNotification(String key, RankingMap ranking, int reason) { - removeNotificationInternal( - key, - ranking, - obtainVisibility(key), - false /* forceRemove */, - null /* dismissedByUserStats */, - reason); - } - - /** - * Internally remove a notification because system server has reported the notification - * should be removed OR the user has manually dismissed the notification - * @param dismissedByUserStats non-null if the user manually dismissed the notification - */ - private void removeNotificationInternal( - String key, - @Nullable RankingMap ranking, - @Nullable NotificationVisibility visibility, - boolean forceRemove, - DismissedByUserStats dismissedByUserStats, - int reason) { - Trace.beginSection("NotificationEntryManager.removeNotificationInternal"); - - final NotificationEntry entry = getActiveNotificationUnfiltered(key); - - for (NotificationRemoveInterceptor interceptor : mRemoveInterceptors) { - if (interceptor.onNotificationRemoveRequested(key, entry, reason)) { - // Remove intercepted; log and skip - mLogger.logRemovalIntercepted(key); - Trace.endSection(); - return; - } - } - - boolean lifetimeExtended = false; - - // Notification was canceled before it got inflated - if (entry == null) { - NotificationEntry pendingEntry = mPendingNotifications.get(key); - if (pendingEntry != null) { - for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) { - if (extender.shouldExtendLifetimeForPendingNotification(pendingEntry)) { - extendLifetime(pendingEntry, extender); - lifetimeExtended = true; - mLogger.logLifetimeExtended(key, extender.getClass().getName(), "pending"); - } - } - if (!lifetimeExtended) { - // At this point, we are guaranteed the notification will be removed - abortExistingInflation(key, "removeNotification"); - // Fix for b/201097913: NotifCollectionListener#onEntryRemoved specifies that - // #onEntryRemoved should be called when a notification is cancelled, - // regardless of whether the notification was pending or active. - // Note that mNotificationEntryListeners are NOT notified of #onEntryRemoved - // because for that interface, #onEntryRemoved should only be called for - // active entries, NOT pending ones. - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onEntryRemoved(pendingEntry, REASON_UNKNOWN); - } - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onEntryCleanUp(pendingEntry); - } - mAllNotifications.remove(pendingEntry); - mLeakDetector.trackGarbage(pendingEntry); - } - } - } else { - // If a manager needs to keep the notification around for whatever reason, we - // keep the notification - boolean entryDismissed = entry.isRowDismissed(); - if (!forceRemove && !entryDismissed) { - for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) { - if (extender.shouldExtendLifetime(entry)) { - mLatestRankingMap = ranking; - extendLifetime(entry, extender); - lifetimeExtended = true; - mLogger.logLifetimeExtended(key, extender.getClass().getName(), "active"); - break; - } - } - } - - if (!lifetimeExtended) { - // At this point, we are guaranteed the notification will be removed - abortExistingInflation(key, "removeNotification"); - mAllNotifications.remove(entry); - - // Ensure any managers keeping the lifetime extended stop managing the entry - cancelLifetimeExtension(entry); - - if (entry.rowExists()) { - entry.removeRow(); - } - - // Let's remove the children if this was a summary - handleGroupSummaryRemoved(key); - removeVisibleNotification(key); - updateNotifications("removeNotificationInternal"); - final boolean removedByUser = dismissedByUserStats != null; - - mLogger.logNotifRemoved(entry.getKey(), removedByUser); - if (removedByUser && visibility != null) { - sendNotificationRemovalToServer(entry.getSbn(), dismissedByUserStats); - } - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onEntryRemoved(entry, visibility, removedByUser, reason); - } - for (NotifCollectionListener listener : mNotifCollectionListeners) { - // NEM doesn't have a good knowledge of reasons so defaulting to unknown. - listener.onEntryRemoved(entry, REASON_UNKNOWN); - } - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onEntryCleanUp(entry); - } - mLeakDetector.trackGarbage(entry); - } - } - Trace.endSection(); - } - - private void sendNotificationRemovalToServer( - StatusBarNotification notification, - DismissedByUserStats dismissedByUserStats) { - mBgExecutor.execute(() -> { - try { - mStatusBarService.onNotificationClear( - notification.getPackageName(), - notification.getUser().getIdentifier(), - notification.getKey(), - dismissedByUserStats.dismissalSurface, - dismissedByUserStats.dismissalSentiment, - dismissedByUserStats.notificationVisibility); - } catch (RemoteException ex) { - // system process is dead if we're here. - } - }); - } - - /** - * Ensures that the group children are cancelled immediately when the group summary is cancelled - * instead of waiting for the notification manager to send all cancels. Otherwise this could - * lead to flickers. - * - * This also ensures that the animation looks nice and only consists of a single disappear - * animation instead of multiple. - * @param key the key of the notification was removed - * - */ - private void handleGroupSummaryRemoved(String key) { - NotificationEntry entry = getActiveNotificationUnfiltered(key); - if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) { - if (entry.getSbn().getOverrideGroupKey() != null && !entry.isRowDismissed()) { - // We don't want to remove children for autobundled notifications as they are not - // always cancelled. We only remove them if they were dismissed by the user. - return; - } - List<NotificationEntry> childEntries = entry.getAttachedNotifChildren(); - if (childEntries == null) { - return; - } - for (int i = 0; i < childEntries.size(); i++) { - NotificationEntry childEntry = childEntries.get(i); - boolean isForeground = (entry.getSbn().getNotification().flags - & Notification.FLAG_FOREGROUND_SERVICE) != 0; - boolean keepForReply = - mRemoteInputManagerLazy.get().shouldKeepForRemoteInputHistory(childEntry) - || mRemoteInputManagerLazy.get().shouldKeepForSmartReplyHistory(childEntry); - if (isForeground || keepForReply) { - // the child is a foreground service notification which we can't remove or it's - // a child we're keeping around for reply! - continue; - } - childEntry.setKeepInParent(true); - // we need to set this state earlier as otherwise we might generate some weird - // animations - childEntry.removeRow(); - } - } - } - - private void addNotificationInternal( - StatusBarNotification notification, - RankingMap rankingMap) throws InflationException { - Trace.beginSection("NotificationEntryManager.addNotificationInternal"); - String key = notification.getKey(); - if (DEBUG) { - Log.d(TAG, "addNotification key=" + key); - } - - updateRankingAndSort(rankingMap, "addNotificationInternal"); - - Ranking ranking = new Ranking(); - rankingMap.getRanking(key, ranking); - - NotificationEntry entry = mPendingNotifications.get(key); - if (entry != null) { - entry.setSbn(notification); - entry.setRanking(ranking); - } else { - entry = new NotificationEntry( - notification, - ranking, - SystemClock.uptimeMillis()); - mAllNotifications.add(entry); - mLeakDetector.trackInstance(entry); - - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onEntryInit(entry); - } - } - - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onEntryBind(entry, notification); - } - - mPendingNotifications.put(key, entry); - mLogger.logNotifAdded(entry.getKey()); - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onPendingEntryAdded(entry); - } - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onEntryAdded(entry); - } - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onRankingApplied(); - } - Trace.endSection(); - } - - public void addNotification(StatusBarNotification notification, RankingMap ranking) { - try { - addNotificationInternal(notification, ranking); - } catch (InflationException e) { - handleInflationException(notification, e); - } - } - - private void updateNotificationInternal(StatusBarNotification notification, - RankingMap ranking) throws InflationException { - Trace.beginSection("NotificationEntryManager.updateNotificationInternal"); - if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")"); - - final String key = notification.getKey(); - abortExistingInflation(key, "updateNotification"); - final NotificationEntry entry = getActiveNotificationUnfiltered(key); - if (entry == null) { - Trace.endSection(); - return; - } - - // Notification is updated so it is essentially re-added and thus alive again. Don't need - // to keep its lifetime extended. - cancelLifetimeExtension(entry); - - updateRankingAndSort(ranking, "updateNotificationInternal"); - StatusBarNotification oldSbn = entry.getSbn(); - entry.setSbn(notification); - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onEntryBind(entry, notification); - } - mGroupManager.onEntryUpdated(entry, oldSbn); - - mLogger.logNotifUpdated(entry.getKey()); - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onPreEntryUpdated(entry); - } - final boolean fromSystem = ranking != null; - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onEntryUpdated(entry, fromSystem); - } - - updateNotifications("updateNotificationInternal"); - - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onPostEntryUpdated(entry); - } - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onRankingApplied(); - } - Trace.endSection(); - } - - public void updateNotification(StatusBarNotification notification, RankingMap ranking) { - try { - updateNotificationInternal(notification, ranking); - } catch (InflationException e) { - handleInflationException(notification, e); - } - } - - /** * Update the notifications * @param reason why the notifications are updating */ @@ -736,128 +98,6 @@ public class NotificationEntryManager implements mLogger.logUseWhileNewPipelineActive("updateNotifications", reason); } - public void updateNotificationRanking(RankingMap rankingMap) { - Trace.beginSection("NotificationEntryManager.updateNotificationRanking"); - List<NotificationEntry> entries = new ArrayList<>(); - entries.addAll(getVisibleNotifications()); - entries.addAll(mPendingNotifications.values()); - - // Has a copy of the current UI adjustments. - ArrayMap<String, NotificationUiAdjustment> oldAdjustments = new ArrayMap<>(); - ArrayMap<String, Integer> oldImportances = new ArrayMap<>(); - for (NotificationEntry entry : entries) { - NotificationUiAdjustment adjustment = - NotificationUiAdjustment.extractFromNotificationEntry(entry); - oldAdjustments.put(entry.getKey(), adjustment); - oldImportances.put(entry.getKey(), entry.getImportance()); - } - - // Populate notification entries from the new rankings. - updateRankingAndSort(rankingMap, "updateNotificationRanking"); - updateRankingOfPendingNotifications(rankingMap); - - // By comparing the old and new UI adjustments, reinflate the view accordingly. - for (NotificationEntry entry : entries) { - mNotificationRowBinderLazy.get() - .onNotificationRankingUpdated( - entry, - oldImportances.get(entry.getKey()), - oldAdjustments.get(entry.getKey()), - NotificationUiAdjustment.extractFromNotificationEntry(entry), - mInflationCallback); - } - - updateNotifications("updateNotificationRanking"); - - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onNotificationRankingUpdated(rankingMap); - } - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onRankingUpdate(rankingMap); - } - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onRankingApplied(); - } - Trace.endSection(); - } - - void notifyChannelModified( - String pkgName, - UserHandle user, - NotificationChannel channel, - int modificationType) { - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onNotificationChannelModified(pkgName, user, channel, modificationType); - } - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onNotificationChannelModified(pkgName, user, channel, modificationType); - } - } - - private void updateRankingOfPendingNotifications(@Nullable RankingMap rankingMap) { - if (rankingMap == null) { - return; - } - for (NotificationEntry pendingNotification : mPendingNotifications.values()) { - Ranking ranking = new Ranking(); - if (rankingMap.getRanking(pendingNotification.getKey(), ranking)) { - pendingNotification.setRanking(ranking); - } - } - } - - /** - * @return An iterator for all "pending" notifications. Pending notifications are newly-posted - * notifications whose views have not yet been inflated. In general, the system pretends like - * these don't exist, although there are a couple exceptions. - */ - public Iterable<NotificationEntry> getPendingNotificationsIterator() { - mNotifPipelineFlags.checkLegacyPipelineEnabled(); - return mPendingNotifications.values(); - } - - /** - * Use this method to retrieve a notification entry that has been prepared for presentation. - * Note that the notification may be filtered out and never shown to the user. - * - * @see #getVisibleNotifications() for the currently sorted and filtered list - * - * @return a {@link NotificationEntry} if it has been prepared, else null - */ - public NotificationEntry getActiveNotificationUnfiltered(String key) { - mNotifPipelineFlags.checkLegacyPipelineEnabled(); - return mActiveNotifications.get(key); - } - - /** - * Gets the pending or visible notification entry with the given key. Returns null if - * notification doesn't exist. - */ - public NotificationEntry getPendingOrActiveNotif(String key) { - mNotifPipelineFlags.checkLegacyPipelineEnabled(); - NotificationEntry entry = mPendingNotifications.get(key); - if (entry != null) { - return entry; - } - return mActiveNotifications.get(key); - } - - private void extendLifetime(NotificationEntry entry, NotificationLifetimeExtender extender) { - NotificationLifetimeExtender activeExtender = mRetainedNotifications.get(entry); - if (activeExtender != null && activeExtender != extender) { - activeExtender.setShouldManageLifetime(entry, false); - } - mRetainedNotifications.put(entry, extender); - extender.setShouldManageLifetime(entry, true); - } - - private void cancelLifetimeExtension(NotificationEntry entry) { - NotificationLifetimeExtender activeExtender = mRetainedNotifications.remove(entry); - if (activeExtender != null) { - activeExtender.setShouldManageLifetime(entry, false); - } - } - /* * ----- * Annexed from NotificationData below: @@ -865,59 +105,11 @@ public class NotificationEntryManager implements * we'll try to keep the behavior the same and can simplify these interfaces in another pass */ - /** Internalization of NotificationData#remove */ - private void removeVisibleNotification(String key) { - // no need to synchronize if we're on the main thread dawg - Assert.isMainThread(); - - NotificationEntry removed = mActiveNotifications.remove(key); - - if (removed == null) return; - mGroupManager.onEntryRemoved(removed); - } - - /** @return list of active notifications filtered for the current user */ - public List<NotificationEntry> getActiveNotificationsForCurrentUser() { - Trace.beginSection("NotificationEntryManager.getActiveNotificationsForCurrentUser"); - Assert.isMainThread(); - ArrayList<NotificationEntry> filtered = new ArrayList<>(); - - final int len = mActiveNotifications.size(); - for (int i = 0; i < len; i++) { - NotificationEntry entry = mActiveNotifications.valueAt(i); - if (!mRanker.isNotificationForCurrentProfiles(entry)) { - continue; - } - filtered.add(entry); - } - Trace.endSection(); - return filtered; - } - - //TODO: Get rid of this in favor of NotificationUpdateHandler#updateNotificationRanking - /** - * @param rankingMap the {@link RankingMap} to apply to the current notification list - * @param reason the reason for calling this method, which will be logged - */ - public void updateRanking(RankingMap rankingMap, String reason) { - Trace.beginSection("NotificationEntryManager.updateRanking"); - updateRankingAndSort(rankingMap, reason); - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onRankingApplied(); - } - Trace.endSection(); - } - /** Resorts / filters the current notification set with the current RankingMap */ public void reapplyFilterAndSort(String reason) { mLogger.logUseWhileNewPipelineActive("reapplyFilterAndSort", reason); } - /** Calls to NotificationRankingManager and updates mSortedAndFiltered */ - private void updateRankingAndSort(RankingMap rankingMap, String reason) { - mLogger.logUseWhileNewPipelineActive("updateRankingAndSort", reason); - } - /** dump the current active notification list. Called from CentralSurfaces */ public void dump(PrintWriter pw, String indent) { pw.println("NotificationEntryManager (Legacy)"); @@ -955,55 +147,10 @@ public class NotificationEntryManager implements pw.println(" notification=" + n.getNotification()); } - /** - * This is the answer to the question "what notifications should the user be seeing right now?" - * These are sorted and filtered, and directly inform the notification shade what to show - * - * @return A read-only list of the currently active notifications - */ - public List<NotificationEntry> getVisibleNotifications() { - mNotifPipelineFlags.checkLegacyPipelineEnabled(); - return mReadOnlyNotifications; - } - - /** - * Returns a collections containing ALL notifications we know about, including ones that are - * hidden or for other users. See {@link CommonNotifCollection#getAllNotifs()}. - */ - @NonNull - @Override - public Collection<NotificationEntry> getAllNotifs() { - mNotifPipelineFlags.checkLegacyPipelineEnabled(); - return mReadOnlyAllNotifications; - } - - @Nullable - @Override - public NotificationEntry getEntry(@NonNull String key) { - mNotifPipelineFlags.checkLegacyPipelineEnabled(); - return getPendingOrActiveNotif(key); - } - - /** @return A count of the active notifications */ - public int getActiveNotificationsCount() { - mNotifPipelineFlags.checkLegacyPipelineEnabled(); - return mReadOnlyNotifications.size(); - } - - /** - * @return {@code true} if there is at least one notification that should be visible right now - */ - public boolean hasActiveNotifications() { - mNotifPipelineFlags.checkLegacyPipelineEnabled(); - return mReadOnlyNotifications.size() != 0; - } - - @Override public void addCollectionListener(@NonNull NotifCollectionListener listener) { mNotifCollectionListeners.add(listener); } - @Override public void removeCollectionListener(@NonNull NotifCollectionListener listener) { mNotifCollectionListeners.remove(listener); } @@ -1024,9 +171,6 @@ public class NotificationEntryManager implements boolean isNotificationForCurrentProfiles(StatusBarNotification sbn); } - private static final String TAG = "NotificationEntryMgr"; - private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG); - /** * Used when a notification is removed and it doesn't have a reason that maps to one of the * reasons defined in NotificationListenerService diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java deleted file mode 100644 index 54f13808cdad..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification; - -import static com.android.systemui.media.MediaDataManagerKt.isMediaNotification; - -import android.Manifest; -import android.app.AppGlobals; -import android.app.Notification; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.os.RemoteException; -import android.service.notification.StatusBarNotification; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.ForegroundServiceController; -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.media.MediaFeatureFlag; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.provider.DebugModeFilterProvider; - -import javax.inject.Inject; - -/** Component which manages the various reasons a notification might be filtered out.*/ -// TODO: delete NotificationFilter.java after migrating to new NotifPipeline b/145659174. -// Notification filtering is taken care of across the different Coordinators (mostly -// KeyguardCoordinator.java) -@SysUISingleton -public class NotificationFilter { - - private final DebugModeFilterProvider mDebugNotificationFilter; - private final StatusBarStateController mStatusBarStateController; - private final KeyguardEnvironment mKeyguardEnvironment; - private final ForegroundServiceController mForegroundServiceController; - private final NotificationLockscreenUserManager mUserManager; - private final Boolean mIsMediaFlagEnabled; - - @Inject - public NotificationFilter( - DebugModeFilterProvider debugNotificationFilter, - StatusBarStateController statusBarStateController, - KeyguardEnvironment keyguardEnvironment, - ForegroundServiceController foregroundServiceController, - NotificationLockscreenUserManager userManager, - MediaFeatureFlag mediaFeatureFlag) { - mDebugNotificationFilter = debugNotificationFilter; - mStatusBarStateController = statusBarStateController; - mKeyguardEnvironment = keyguardEnvironment; - mForegroundServiceController = foregroundServiceController; - mUserManager = userManager; - mIsMediaFlagEnabled = mediaFeatureFlag.getEnabled(); - } - - /** - * @return true if the provided notification should NOT be shown right now. - */ - public boolean shouldFilterOut(NotificationEntry entry) { - final StatusBarNotification sbn = entry.getSbn(); - if (mDebugNotificationFilter.shouldFilterOut(entry)) { - return true; - } - - if (!(mKeyguardEnvironment.isDeviceProvisioned() - || showNotificationEvenIfUnprovisioned(sbn))) { - return true; - } - - if (!mKeyguardEnvironment.isNotificationForCurrentProfiles(sbn)) { - return true; - } - - if (mUserManager.isLockscreenPublicMode(sbn.getUserId()) - && (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET - || mUserManager.shouldHideNotifications(sbn.getUserId()) - || mUserManager.shouldHideNotifications(sbn.getKey()))) { - return true; - } - - if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) { - return true; - } - - if (!mStatusBarStateController.isDozing() && entry.shouldSuppressNotificationList()) { - return true; - } - - if (entry.getRanking().isSuspended()) { - return true; - } - - if (mForegroundServiceController.isDisclosureNotification(sbn) - && !mForegroundServiceController.isDisclosureNeededForUser(sbn.getUserId())) { - // this is a foreground-service disclosure for a user that does not need to show one - return true; - } - - if (mIsMediaFlagEnabled && isMediaNotification(sbn)) { - return true; - } - return false; - } - - // Q: What kinds of notifications should show during setup? - // A: Almost none! Only things coming from packages with permission - // android.permission.NOTIFICATION_DURING_SETUP that also have special "kind" tags marking them - // as relevant for setup (see below). - private static boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) { - return showNotificationEvenIfUnprovisioned(AppGlobals.getPackageManager(), sbn); - } - - @VisibleForTesting - static boolean showNotificationEvenIfUnprovisioned(IPackageManager packageManager, - StatusBarNotification sbn) { - return checkUidPermission(packageManager, Manifest.permission.NOTIFICATION_DURING_SETUP, - sbn.getUid()) == PackageManager.PERMISSION_GRANTED - && sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP); - } - - private static int checkUidPermission(IPackageManager packageManager, String permission, - int uid) { - try { - return packageManager.checkUidPermission(permission, uid); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index b6392f705c49..585d871bad4e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -61,11 +61,11 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.ContrastColorUtil; import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; -import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; 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.notifcollection.NotifDismissInterceptor; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.icon.IconPack; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; @@ -421,7 +421,7 @@ public final class NotificationEntry extends ListEntry { * Get the children that are actually attached to this notification's row. * * TODO: Seems like most callers here should probably be using - * {@link NotificationGroupManagerLegacy#getChildren} + * {@link GroupMembershipManager#getChildren(ListEntry)} */ public @Nullable List<NotificationEntry> getAttachedNotifChildren() { if (row == null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt deleted file mode 100644 index a92cff886b53..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification.collection - -import android.app.Notification -import android.app.NotificationManager.IMPORTANCE_HIGH -import android.app.NotificationManager.IMPORTANCE_MIN -import android.service.notification.NotificationListenerService.Ranking -import android.service.notification.NotificationListenerService.RankingMap -import android.service.notification.StatusBarNotification -import com.android.systemui.statusbar.NotificationMediaManager -import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment -import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger -import com.android.systemui.statusbar.notification.NotificationFilter -import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager -import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationRanker -import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy -import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON -import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING -import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE -import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE -import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT -import com.android.systemui.statusbar.notification.stack.PriorityBucket -import com.android.systemui.statusbar.policy.HeadsUpManager -import dagger.Lazy -import java.util.Objects -import javax.inject.Inject - -private const val TAG = "NotifRankingManager" - -/** - * NotificationRankingManager is responsible for holding on to the most recent [RankingMap], and - * updating SystemUI's set of [NotificationEntry]s with their own ranking. It also sorts and filters - * a set of entries (but retains none of them). We also set buckets on the entries here since - * bucketing is tied closely to sorting. - * - * For the curious: this class is one iteration closer to null of what used to be called - * NotificationData.java. - */ -open class NotificationRankingManager @Inject constructor( - private val mediaManagerLazy: Lazy<NotificationMediaManager>, - private val groupManager: NotificationGroupManagerLegacy, - private val headsUpManager: HeadsUpManager, - private val notifFilter: NotificationFilter, - private val logger: NotificationEntryManagerLogger, - private val sectionsFeatureManager: NotificationSectionsFeatureManager, - private val peopleNotificationIdentifier: PeopleNotificationIdentifier, - private val highPriorityProvider: HighPriorityProvider, - private val keyguardEnvironment: KeyguardEnvironment -) : LegacyNotificationRanker { - - override var rankingMap: RankingMap? = null - protected set - private val mediaManager by lazy { - mediaManagerLazy.get() - } - private val usePeopleFiltering: Boolean - get() = sectionsFeatureManager.isFilteringEnabled() - private val rankingComparator: Comparator<NotificationEntry> = Comparator { a, b -> - val na = a.sbn - val nb = b.sbn - val aRank = a.ranking.rank - val bRank = b.ranking.rank - - val aIsFsn = a.isColorizedForegroundService() - val bIsFsn = b.isColorizedForegroundService() - - val aCall = a.isImportantCall() - val bCall = b.isImportantCall() - - val aPersonType = a.getPeopleNotificationType() - val bPersonType = b.getPeopleNotificationType() - - val aMedia = a.isImportantMedia() - val bMedia = b.isImportantMedia() - - val aSystemMax = a.isSystemMax() - val bSystemMax = b.isSystemMax() - - val aHeadsUp = a.isRowHeadsUp - val bHeadsUp = b.isRowHeadsUp - - val aIsHighPriority = a.isHighPriority() - val bIsHighPriority = b.isHighPriority() - when { - aHeadsUp != bHeadsUp -> if (aHeadsUp) -1 else 1 - // Provide consistent ranking with headsUpManager - aHeadsUp -> headsUpManager.compare(a, b) - aIsFsn != bIsFsn -> if (aIsFsn) -1 else 1 - aCall != bCall -> if (aCall) -1 else 1 - usePeopleFiltering && aPersonType != bPersonType -> - peopleNotificationIdentifier.compareTo(aPersonType, bPersonType) - // Upsort current media notification. - aMedia != bMedia -> if (aMedia) -1 else 1 - // Upsort PRIORITY_MAX system notifications - aSystemMax != bSystemMax -> if (aSystemMax) -1 else 1 - aIsHighPriority != bIsHighPriority -> - -1 * aIsHighPriority.compareTo(bIsHighPriority) - aRank != bRank -> aRank - bRank - else -> nb.notification.`when`.compareTo(na.notification.`when`) - } - } - - override fun updateRanking( - newRankingMap: RankingMap?, - entries: Collection<NotificationEntry>, - reason: String - ): List<NotificationEntry> { - // TODO: may not be ideal to guard on null here, but this code is implementing exactly what - // NotificationData used to do - if (newRankingMap != null) { - rankingMap = newRankingMap - updateRankingForEntries(entries) - } - return synchronized(this) { - filterAndSortLocked(entries, reason) - } - } - - override fun isNotificationForCurrentProfiles( - entry: NotificationEntry - ): Boolean { - return keyguardEnvironment.isNotificationForCurrentProfiles(entry.sbn) - } - - /** Uses the [rankingComparator] to sort notifications which aren't filtered */ - private fun filterAndSortLocked( - entries: Collection<NotificationEntry>, - reason: String - ): List<NotificationEntry> { - logger.logFilterAndSort(reason) - val filtered = entries.asSequence() - .filterNot(this::filter) - .sortedWith(rankingComparator) - .toList() - entries.forEach { it.bucket = getBucketForEntry(it) } - return filtered - } - - private fun filter(entry: NotificationEntry): Boolean { - val filtered = notifFilter.shouldFilterOut(entry) - if (filtered) { - // notification is removed from the list, so we reset its initialization time - entry.resetInitializationTime() - } - return filtered - } - - @PriorityBucket - private fun getBucketForEntry(entry: NotificationEntry): Int { - val isImportantCall = entry.isImportantCall() - val isHeadsUp = entry.isRowHeadsUp - val isMedia = entry.isImportantMedia() - val isSystemMax = entry.isSystemMax() - return when { - entry.isColorizedForegroundService() || isImportantCall -> BUCKET_FOREGROUND_SERVICE - usePeopleFiltering && entry.isConversation() -> BUCKET_PEOPLE - isHeadsUp || isMedia || isSystemMax || entry.isHighPriority() -> BUCKET_ALERTING - else -> BUCKET_SILENT - } - } - - private fun updateRankingForEntries(entries: Iterable<NotificationEntry>) { - rankingMap?.let { rankingMap -> - synchronized(entries) { - for (entry in entries) { - val newRanking = Ranking() - if (!rankingMap.getRanking(entry.key, newRanking)) { - continue - } - entry.ranking = newRanking - - val newOverrideGroupKey = newRanking.overrideGroupKey - if (!Objects.equals(entry.sbn.overrideGroupKey, newOverrideGroupKey)) { - val oldGroupKey = entry.sbn.groupKey - val oldIsGroup = entry.sbn.isGroup - val oldIsGroupSummary = entry.sbn.notification.isGroupSummary - entry.sbn.overrideGroupKey = newOverrideGroupKey - groupManager.onEntryUpdated(entry, oldGroupKey, oldIsGroup, - oldIsGroupSummary) - } - } - } - } - } - - private fun NotificationEntry.isImportantMedia() = - key == mediaManager.mediaNotificationKey && importance > IMPORTANCE_MIN - - private fun NotificationEntry.isConversation() = getPeopleNotificationType() != TYPE_NON_PERSON - - private fun NotificationEntry.getPeopleNotificationType() = - peopleNotificationIdentifier.getPeopleNotificationType(this) - - private fun NotificationEntry.isHighPriority() = - highPriorityProvider.isHighPriority(this) -} - -// Convenience functions -private fun NotificationEntry.isSystemMax() = - importance >= IMPORTANCE_HIGH && sbn.isSystemNotification() - -private fun StatusBarNotification.isSystemNotification() = - "android" == packageName || "com.android.systemui" == packageName - -private fun NotificationEntry.isImportantCall() = - sbn.notification.isStyle(Notification.CallStyle::class.java) && importance > IMPORTANCE_MIN - -private fun NotificationEntry.isColorizedForegroundService() = sbn.notification.run { - isForegroundService && isColorized && importance > IMPORTANCE_MIN -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt index 9d5b859ef29c..496266f8831e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt @@ -17,8 +17,6 @@ package com.android.systemui.statusbar.notification.collection.inflation import com.android.systemui.dagger.SysUISingleton -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.inflation.BindEventManager.Listener import javax.inject.Inject @@ -31,12 +29,4 @@ class BindEventManagerImpl @Inject constructor() : BindEventManager() { /** Emit the [Listener.onViewBound] event to all registered listeners. */ fun notifyViewBound(entry: NotificationEntry) = listeners.forEach { listener -> listener.onViewBound(entry) } - - /** Initialize this for the legacy pipeline. */ - fun attachToLegacyPipeline(notificationEntryManager: NotificationEntryManager) { - notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener { - override fun onEntryInflated(entry: NotificationEntry) = notifyViewBound(entry) - override fun onEntryReinflated(entry: NotificationEntry) = notifyViewBound(entry) - }) - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRanker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRanker.kt deleted file mode 100644 index 49bc48efda00..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRanker.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 android.service.notification.NotificationListenerService -import com.android.systemui.statusbar.notification.collection.NotificationEntry - -interface LegacyNotificationRanker { - val rankingMap: NotificationListenerService.RankingMap? - - fun updateRanking( - newRankingMap: NotificationListenerService.RankingMap?, - entries: Collection<NotificationEntry>, - reason: String - ): List<NotificationEntry> - - fun isNotificationForCurrentProfiles( - entry: NotificationEntry - ): Boolean -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRankerStub.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRankerStub.java deleted file mode 100644 index 12353f80c0d1..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRankerStub.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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 android.service.notification.NotificationListenerService.Ranking; -import android.service.notification.NotificationListenerService.RankingMap; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.systemui.statusbar.notification.collection.NotificationEntry; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; - -/** - * Stub implementation that we use until we get passed the "real" one in the form of - * {@link com.android.systemui.statusbar.notification.collection.NotificationRankingManager} - */ -public class LegacyNotificationRankerStub implements LegacyNotificationRanker { - private RankingMap mRankingMap = new RankingMap(new Ranking[] {}); - - @NonNull - @Override - public List<NotificationEntry> updateRanking( - @Nullable RankingMap newRankingMap, - @NonNull Collection<NotificationEntry> entries, - @NonNull String reason) { - if (newRankingMap != null) { - mRankingMap = newRankingMap; - } - List<NotificationEntry> ranked = new ArrayList<>(entries); - ranked.sort(mEntryComparator); - return ranked; - } - - @Nullable - @Override - public RankingMap getRankingMap() { - return mRankingMap; - } - - private final Comparator<NotificationEntry> mEntryComparator = Comparator.comparingLong( - o -> o.getSbn().getNotification().when); - - @Override - public boolean isNotificationForCurrentProfiles(@NonNull NotificationEntry entry) { - return true; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java index ae4f2bbc0453..89445a5c6467 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java @@ -19,9 +19,6 @@ package com.android.systemui.statusbar.notification.collection.legacy; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.RowContentBindParams; -import com.android.systemui.statusbar.notification.row.RowContentBindStage; import javax.inject.Inject; @@ -32,44 +29,17 @@ import javax.inject.Inject; @SysUISingleton public class LowPriorityInflationHelper { private final NotificationGroupManagerLegacy mGroupManager; - private final RowContentBindStage mRowContentBindStage; private final NotifPipelineFlags mNotifPipelineFlags; @Inject LowPriorityInflationHelper( NotificationGroupManagerLegacy groupManager, - RowContentBindStage rowContentBindStage, NotifPipelineFlags notifPipelineFlags) { mGroupManager = groupManager; - mRowContentBindStage = rowContentBindStage; mNotifPipelineFlags = notifPipelineFlags; } /** - * Check if we inflated the wrong version of the view and if we need to reinflate the - * content views to be their low priority version or not. - * - * Whether we inflate the low priority view or not depends on the notification being visually - * part of a group. Since group membership is determined AFTER inflation, we're forced to check - * again at a later point in the pipeline to see if we inflated the wrong view and reinflate - * the correct one here. - * - * TODO: The group manager should run before inflation so that we don't deal with this - */ - public void recheckLowPriorityViewAndInflate( - NotificationEntry entry, - ExpandableNotificationRow row) { - mNotifPipelineFlags.checkLegacyPipelineEnabled(); - RowContentBindParams params = mRowContentBindStage.getStageParams(entry); - final boolean shouldBeLowPriority = shouldUseLowPriorityView(entry); - if (!row.isRemoved() && row.isLowPriority() != shouldBeLowPriority) { - params.setUseLowPriority(shouldBeLowPriority); - mRowContentBindStage.requestRebind(entry, - en -> row.setIsLowPriority(shouldBeLowPriority)); - } - } - - /** * Whether the notification should inflate a low priority version of its content views. */ public boolean shouldUseLowPriorityView(NotificationEntry entry) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java index b8da9a83da3f..d41f6fe7bdde 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java @@ -33,13 +33,9 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; -import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager.OnGroupExpansionChangeListener; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.util.Compile; import com.android.wm.shell.bubbles.Bubbles; @@ -47,7 +43,6 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -65,12 +60,7 @@ import dagger.Lazy; * 2. Tracking group expansion states */ @SysUISingleton -public class NotificationGroupManagerLegacy implements - OnHeadsUpChangedListener, - StateListener, - GroupMembershipManager, - GroupExpansionManager, - Dumpable { +public class NotificationGroupManagerLegacy implements StateListener, Dumpable { private static final String TAG = "LegacyNotifGroupManager"; private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG); @@ -81,14 +71,10 @@ public class NotificationGroupManagerLegacy implements */ private static final long POST_BATCH_MAX_AGE = 5000; private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>(); - private final ArraySet<OnGroupExpansionChangeListener> mExpansionChangeListeners = - new ArraySet<>(); private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier; private final Optional<Bubbles> mBubblesOptional; private final GroupEventDispatcher mEventDispatcher = new GroupEventDispatcher(mGroupMap::get); - private int mBarState = -1; - private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>(); - private HeadsUpManager mHeadsUpManager; + private final HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>(); private boolean mIsUpdatingUnchangedGroup; @Inject @@ -111,47 +97,8 @@ public class NotificationGroupManagerLegacy implements mEventDispatcher.registerGroupChangeListener(listener); } - @Override - public void registerGroupExpansionChangeListener(OnGroupExpansionChangeListener listener) { - mExpansionChangeListeners.add(listener); - } - - @Override - public boolean isGroupExpanded(NotificationEntry entry) { - NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn())); - if (group == null) { - return false; - } - return group.expanded; - } - - /** - * @return if the group that this notification is associated with logically is expanded - */ - public boolean isLogicalGroupExpanded(StatusBarNotification sbn) { - NotificationGroup group = mGroupMap.get(sbn.getGroupKey()); - if (group == null) { - return false; - } - return group.expanded; - } - - @Override - public void setGroupExpanded(NotificationEntry entry, boolean expanded) { - NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn())); - if (group == null) { - return; - } - setGroupExpanded(group, expanded); - } - private void setGroupExpanded(NotificationGroup group, boolean expanded) { group.expanded = expanded; - if (group.summary != null) { - for (OnGroupExpansionChangeListener listener : mExpansionChangeListeners) { - listener.onGroupExpansionChange(group.summary.getRow(), expanded); - } - } } /** @@ -212,19 +159,6 @@ public class NotificationGroupManagerLegacy implements } } - /** - * Notify the group manager that a new entry was added - */ - public void onEntryAdded(final NotificationEntry added) { - if (SPEW) { - Log.d(TAG, "onEntryAdded: entry=" + logKey(added)); - } - mEventDispatcher.openBufferScope(); - updateIsolation(added); - onEntryAddedInternal(added); - mEventDispatcher.closeBufferScope(); - } - private void onEntryAddedInternal(final NotificationEntry added) { if (added.isRowRemoved()) { added.setDebugThrowable(new Throwable()); @@ -499,106 +433,13 @@ public class NotificationGroupManagerLegacy implements return result; } - /** - * Update an entry's group information - * @param entry notification entry to update - * @param oldNotification previous notification info before this update - */ - public void onEntryUpdated(NotificationEntry entry, StatusBarNotification oldNotification) { - if (SPEW) { - Log.d(TAG, "onEntryUpdated: entry=" + logKey(entry)); - } - onEntryUpdated(entry, oldNotification.getGroupKey(), oldNotification.isGroup(), - oldNotification.getNotification().isGroupSummary()); - } - - /** - * Updates an entry's group information - * @param entry notification entry to update - * @param oldGroupKey the notification's previous group key before this update - * @param oldIsGroup whether this notification was a group before this update - * @param oldIsGroupSummary whether this notification was a group summary before this update - */ - public void onEntryUpdated(NotificationEntry entry, String oldGroupKey, boolean oldIsGroup, - boolean oldIsGroupSummary) { - String newGroupKey = entry.getSbn().getGroupKey(); - boolean groupKeysChanged = !oldGroupKey.equals(newGroupKey); - boolean wasGroupChild = isGroupChild(entry.getKey(), oldIsGroup, oldIsGroupSummary); - boolean isGroupChild = isGroupChild(entry.getSbn()); - mEventDispatcher.openBufferScope(); - mIsUpdatingUnchangedGroup = !groupKeysChanged && wasGroupChild == isGroupChild; - if (mGroupMap.get(getGroupKey(entry.getKey(), oldGroupKey)) != null) { - onEntryRemovedInternal(entry, oldGroupKey, oldIsGroup, oldIsGroupSummary); - } - onEntryAddedInternal(entry); - mIsUpdatingUnchangedGroup = false; - if (isIsolated(entry.getSbn().getKey())) { - mIsolatedEntries.put(entry.getKey(), entry.getSbn()); - if (groupKeysChanged) { - updateSuppression(mGroupMap.get(oldGroupKey)); - } - // Always update the suppression of the group from which you're isolated, in case - // this entry was or now is the alertOverride for that group. - updateSuppression(mGroupMap.get(newGroupKey)); - } else if (!wasGroupChild && isGroupChild) { - onEntryBecomingChild(entry); - } - mEventDispatcher.closeBufferScope(); - } - - /** - * Whether the given notification is the summary of a group that is being suppressed - */ - public boolean isSummaryOfSuppressedGroup(StatusBarNotification sbn) { - return sbn.getNotification().isGroupSummary() && isGroupSuppressed(getGroupKey(sbn)); - } - - /** - * If the given notification is a summary, get the group for it. - */ - public NotificationGroup getGroupForSummary(StatusBarNotification sbn) { - if (sbn.getNotification().isGroupSummary()) { - return mGroupMap.get(getGroupKey(sbn)); - } - return null; - } - - private boolean isOnlyChild(StatusBarNotification sbn) { - return !sbn.getNotification().isGroupSummary() - && getTotalNumberOfChildren(sbn) == 1; - } - - @Override - public boolean isOnlyChildInGroup(NotificationEntry entry) { - final StatusBarNotification sbn = entry.getSbn(); - if (!isOnlyChild(sbn)) { - return false; - } - NotificationEntry logicalGroupSummary = getLogicalGroupSummary(entry); - return logicalGroupSummary != null && !logicalGroupSummary.getSbn().equals(sbn); - } - - private int getTotalNumberOfChildren(StatusBarNotification sbn) { - int isolatedChildren = getNumberOfIsolatedChildren(sbn.getGroupKey()); - NotificationGroup group = mGroupMap.get(sbn.getGroupKey()); - int realChildren = group != null ? group.children.size() : 0; - return isolatedChildren + realChildren; - } - - private boolean isGroupSuppressed(String groupKey) { - NotificationGroup group = mGroupMap.get(groupKey); - return group != null && group.suppressed; - } - private void setStatusBarState(int newState) { - mBarState = newState; - if (mBarState == StatusBarState.KEYGUARD) { + if (newState == StatusBarState.KEYGUARD) { collapseGroups(); } } - @Override - public void collapseGroups() { + private void collapseGroups() { // Because notifications can become isolated when the group becomes suppressed it can // lead to concurrent modifications while looping. We need to make a copy. ArrayList<NotificationGroup> groupCopy = new ArrayList<>(mGroupMap.values()); @@ -612,7 +453,6 @@ public class NotificationGroupManagerLegacy implements } } - @Override public boolean isChildInGroup(NotificationEntry entry) { final StatusBarNotification sbn = entry.getSbn(); if (!isGroupChild(sbn)) { @@ -631,67 +471,6 @@ public class NotificationGroupManagerLegacy implements return true; } - @Override - public boolean isGroupSummary(NotificationEntry entry) { - final StatusBarNotification sbn = entry.getSbn(); - if (!isGroupSummary(sbn)) { - return false; - } - NotificationGroup group = mGroupMap.get(getGroupKey(sbn)); - if (group == null || group.summary == null) { - return false; - } - return !group.children.isEmpty() && Objects.equals(group.summary.getSbn(), sbn); - } - - @Override - public NotificationEntry getGroupSummary(NotificationEntry entry) { - return getGroupSummary(getGroupKey(entry.getSbn())); - } - - @Override - public NotificationEntry getLogicalGroupSummary(NotificationEntry entry) { - return getGroupSummary(entry.getSbn().getGroupKey()); - } - - @Nullable - private NotificationEntry getGroupSummary(String groupKey) { - NotificationGroup group = mGroupMap.get(groupKey); - //TODO: see if this can become an Entry - return group == null ? null - : group.summary; - } - - /** - * Get the children that are logically in the summary's group, whether or not they are isolated. - * - * @param summary summary of a group - * @return list of the children - */ - public ArrayList<NotificationEntry> getLogicalChildren(StatusBarNotification summary) { - NotificationGroup group = mGroupMap.get(summary.getGroupKey()); - if (group == null) { - return null; - } - ArrayList<NotificationEntry> children = new ArrayList<>(group.children.values()); - for (StatusBarNotification sbn : mIsolatedEntries.values()) { - if (sbn.getGroupKey().equals(summary.getGroupKey())) { - children.add(mGroupMap.get(sbn.getKey()).summary); - } - } - return children; - } - - @Override - public @Nullable List<NotificationEntry> getChildren(ListEntry listEntrySummary) { - NotificationEntry summary = listEntrySummary.getRepresentativeEntry(); - NotificationGroup group = mGroupMap.get(summary.getSbn().getGroupKey()); - if (group == null) { - return null; - } - return new ArrayList<>(group.children.values()); - } - /** * If there is a {@link NotificationGroup} associated with the provided entry, this method * will update the suppression of that group. @@ -710,7 +489,7 @@ public class NotificationGroupManagerLegacy implements * @param sbn notification to check * @return the key of the notification */ - public String getGroupKey(StatusBarNotification sbn) { + private String getGroupKey(StatusBarNotification sbn) { return getGroupKey(sbn.getKey(), sbn.getGroupKey()); } @@ -721,37 +500,17 @@ public class NotificationGroupManagerLegacy implements return groupKey; } - @Override - public boolean toggleGroupExpansion(NotificationEntry entry) { - NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn())); - if (group == null) { - return false; - } - setGroupExpanded(group, !group.expanded); - return group.expanded; - } - private boolean isIsolated(String sbnKey) { return mIsolatedEntries.containsKey(sbnKey); } /** - * Is this notification the summary of a group? - */ - public boolean isGroupSummary(StatusBarNotification sbn) { - if (isIsolated(sbn.getKey())) { - return true; - } - return sbn.getNotification().isGroupSummary(); - } - - /** * Whether a notification is visually a group child. * * @param sbn notification to check * @return true if it is visually a group child */ - public boolean isGroupChild(StatusBarNotification sbn) { + private boolean isGroupChild(StatusBarNotification sbn) { return isGroupChild(sbn.getKey(), sbn.isGroup(), sbn.getNotification().isGroupSummary()); } @@ -762,11 +521,6 @@ public class NotificationGroupManagerLegacy implements return isGroup && !isGroupSummary; } - @Override - public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { - updateIsolation(entry); - } - /** * Whether a notification that is normally part of a group should be temporarily isolated from * the group and put in their own group visually. This generally happens when the notification @@ -783,9 +537,6 @@ public class NotificationGroupManagerLegacy implements if (isImportantConversation(entry)) { return true; } - if (mHeadsUpManager != null && !mHeadsUpManager.isAlerting(entry.getKey())) { - return false; - } NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey()); return (sbn.getNotification().fullScreenIntent != null || notificationGroup == null @@ -825,7 +576,7 @@ public class NotificationGroupManagerLegacy implements /** * Update the isolation of an entry, splitting it from the group. */ - public void updateIsolation(NotificationEntry entry) { + private void updateIsolation(NotificationEntry entry) { // We need to buffer a few events because we do isolation changes in 3 steps: // removeInternal, update mIsolatedEntries, addInternal. This means that often the // alertOverride will update on the removal, however processing the event in that case can @@ -866,13 +617,6 @@ public class NotificationGroupManagerLegacy implements || notificationGroup.summary.isGroupNotFullyVisible(); } - /** - * Directly set the heads up manager to avoid circular dependencies - */ - public void setHeadsUpManager(HeadsUpManager headsUpManager) { - mHeadsUpManager = headsUpManager; - } - @Override public void dump(PrintWriter pw, String[] args) { pw.println("GroupManagerLegacy state:"); @@ -893,7 +637,7 @@ public class NotificationGroupManagerLegacy implements } /** Get the group key, reformatted for logging, for the (optional) group */ - public static String logGroupKey(NotificationGroup group) { + private static String logGroupKey(NotificationGroup group) { if (group == null) { return "null"; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java index 456bf5148f7c..bb8c0e0d3b77 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java @@ -16,84 +16,32 @@ package com.android.systemui.statusbar.notification.collection.legacy; -import android.os.Handler; -import android.os.SystemClock; -import android.view.View; - -import androidx.collection.ArraySet; - -import com.android.systemui.Dumpable; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.notification.NotificationEntryListener; -import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.VisibilityLocationProvider; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; - -import java.io.PrintWriter; -import java.util.ArrayList; /** * A manager that ensures that notifications are visually stable. It will suppress reorderings * and reorder at the right time when they are out of view. */ -public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpable { +public class VisualStabilityManager { - private static final long TEMPORARY_REORDERING_ALLOWED_DURATION = 1000; - - private final ArrayList<Callback> mReorderingAllowedCallbacks = new ArrayList<>(); - private final ArraySet<Callback> mPersistentReorderingCallbacks = new ArraySet<>(); - private final ArrayList<Callback> mGroupChangesAllowedCallbacks = new ArrayList<>(); - private final ArraySet<Callback> mPersistentGroupCallbacks = new ArraySet<>(); - private final Handler mHandler; private final VisualStabilityProvider mVisualStabilityProvider; private boolean mPanelExpanded; private boolean mScreenOn; - private boolean mReorderingAllowed; - private boolean mGroupChangedAllowed; - private boolean mIsTemporaryReorderingAllowed; - private long mTemporaryReorderingStart; - private VisibilityLocationProvider mVisibilityLocationProvider; - private ArraySet<View> mAllowedReorderViews = new ArraySet<>(); - private ArraySet<NotificationEntry> mLowPriorityReorderingViews = new ArraySet<>(); - private ArraySet<View> mAddedChildren = new ArraySet<>(); private boolean mPulsing; /** * Injected constructor. See {@link NotificationsModule}. */ public VisualStabilityManager( - NotificationEntryManager notificationEntryManager, VisualStabilityProvider visualStabilityProvider, - @Main Handler handler, StatusBarStateController statusBarStateController, - WakefulnessLifecycle wakefulnessLifecycle, - DumpManager dumpManager) { + WakefulnessLifecycle wakefulnessLifecycle) { mVisualStabilityProvider = visualStabilityProvider; - mHandler = handler; - dumpManager.registerDumpable(this); - - if (notificationEntryManager != null) { - notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { - @Override - public void onPreEntryUpdated(NotificationEntry entry) { - final boolean ambientStateHasChanged = - entry.isAmbient() != entry.getRow().isLowPriority(); - if (ambientStateHasChanged) { - // note: entries are removed in onReorderingFinished - mLowPriorityReorderingViews.add(entry); - } - } - }); - } if (statusBarStateController != null) { setPulsing(statusBarStateController.isPulsing()); @@ -116,40 +64,6 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl } /** - * Add a callback to invoke when reordering is allowed again. - * - * @param callback the callback to add - * @param persistent {@code true} if this callback should this callback be persisted, otherwise - * it will be removed after a single invocation - */ - public void addReorderingAllowedCallback(Callback callback, boolean persistent) { - if (persistent) { - mPersistentReorderingCallbacks.add(callback); - } - if (mReorderingAllowedCallbacks.contains(callback)) { - return; - } - mReorderingAllowedCallbacks.add(callback); - } - - /** - * Add a callback to invoke when group changes are allowed again. - * - * @param callback the callback to add - * @param persistent {@code true} if this callback should this callback be persisted, otherwise - * it will be removed after a single invocation - */ - public void addGroupChangesAllowedCallback(Callback callback, boolean persistent) { - if (persistent) { - mPersistentGroupCallbacks.add(callback); - } - if (mGroupChangesAllowedCallbacks.contains(callback)) { - return; - } - mGroupChangesAllowedCallbacks.add(callback); - } - - /** * @param screenOn whether the screen is on */ private void setScreenOn(boolean screenOn) { @@ -177,133 +91,8 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl } private void updateAllowedStates() { - boolean reorderingAllowed = - (!mScreenOn || !mPanelExpanded || mIsTemporaryReorderingAllowed) && !mPulsing; - boolean changedToTrue = reorderingAllowed && !mReorderingAllowed; - mReorderingAllowed = reorderingAllowed; - if (changedToTrue) { - notifyChangeAllowed(mReorderingAllowedCallbacks, mPersistentReorderingCallbacks); - } + boolean reorderingAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing; mVisualStabilityProvider.setReorderingAllowed(reorderingAllowed); - boolean groupChangesAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing; - changedToTrue = groupChangesAllowed && !mGroupChangedAllowed; - mGroupChangedAllowed = groupChangesAllowed; - if (changedToTrue) { - notifyChangeAllowed(mGroupChangesAllowedCallbacks, mPersistentGroupCallbacks); - } - } - - private void notifyChangeAllowed(ArrayList<Callback> callbacks, - ArraySet<Callback> persistentCallbacks) { - for (int i = 0; i < callbacks.size(); i++) { - Callback callback = callbacks.get(i); - callback.onChangeAllowed(); - if (!persistentCallbacks.contains(callback)) { - callbacks.remove(callback); - i--; - } - } - } - - /** - * @return whether reordering is currently allowed in general. - */ - public boolean isReorderingAllowed() { - return mReorderingAllowed; - } - - /** - * @return whether changes in the grouping should be allowed right now. - */ - public boolean areGroupChangesAllowed() { - return mGroupChangedAllowed; - } - - /** - * @return whether a specific notification is allowed to reorder. Certain notifications are - * allowed to reorder even if {@link #isReorderingAllowed()} returns false, like newly added - * notifications or heads-up notifications that are out of view. - */ - public boolean canReorderNotification(ExpandableNotificationRow row) { - if (mReorderingAllowed) { - return true; - } - if (mAddedChildren.contains(row)) { - return true; - } - if (mLowPriorityReorderingViews.contains(row.getEntry())) { - return true; - } - if (mAllowedReorderViews.contains(row) - && !mVisibilityLocationProvider.isInVisibleLocation(row.getEntry())) { - return true; - } - return false; - } - - public void setVisibilityLocationProvider( - VisibilityLocationProvider visibilityLocationProvider) { - mVisibilityLocationProvider = visibilityLocationProvider; - } - - /** - * Notifications have been reordered, so reset all the allowed list of views that are allowed - * to reorder. - */ - public void onReorderingFinished() { - mAllowedReorderViews.clear(); - mAddedChildren.clear(); - mLowPriorityReorderingViews.clear(); - } - - @Override - public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { - if (isHeadsUp) { - // Heads up notifications should in general be allowed to reorder if they are out of - // view and stay at the current location if they aren't. - mAllowedReorderViews.add(entry.getRow()); - } - } - - /** - * Temporarily allows reordering of the entire shade for a period of 1000ms. Subsequent calls - * to this method will extend the timer. - */ - public void temporarilyAllowReordering() { - mHandler.removeCallbacks(mOnTemporaryReorderingExpired); - mHandler.postDelayed(mOnTemporaryReorderingExpired, TEMPORARY_REORDERING_ALLOWED_DURATION); - if (!mIsTemporaryReorderingAllowed) { - mTemporaryReorderingStart = SystemClock.elapsedRealtime(); - } - mIsTemporaryReorderingAllowed = true; - updateAllowedStates(); - } - - private final Runnable mOnTemporaryReorderingExpired = () -> { - mIsTemporaryReorderingAllowed = false; - updateAllowedStates(); - }; - - /** - * Notify the visual stability manager that a new view was added and should be allowed to - * reorder next time. - */ - public void notifyViewAddition(View view) { - mAddedChildren.add(view); - } - - @Override - public void dump(PrintWriter pw, String[] args) { - pw.println("VisualStabilityManager state:"); - pw.print(" mIsTemporaryReorderingAllowed="); pw.println(mIsTemporaryReorderingAllowed); - pw.print(" mTemporaryReorderingStart="); pw.println(mTemporaryReorderingStart); - - long now = SystemClock.elapsedRealtime(); - pw.print(" Temporary reordering window has been open for "); - pw.print(now - (mIsTemporaryReorderingAllowed ? mTemporaryReorderingStart : now)); - pw.println("ms"); - - pw.println(); } final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { 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 fac234c58850..eda2eeca0620 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 @@ -30,7 +30,6 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; -import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.people.widget.PeopleSpaceWidgetManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -53,7 +52,6 @@ import com.android.systemui.statusbar.notification.collection.coordinator.dagger import com.android.systemui.statusbar.notification.collection.inflation.BindEventManager; import com.android.systemui.statusbar.notification.collection.inflation.BindEventManagerImpl; import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater; -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.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; @@ -123,22 +121,13 @@ public interface NotificationsModule { NotificationEntryManagerLogger logger, NotificationGroupManagerLegacy groupManager, NotifPipelineFlags notifPipelineFlags, - Lazy<NotificationRowBinder> notificationRowBinderLazy, Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy, LeakDetector leakDetector, IStatusBarService statusBarService, - DumpManager dumpManager, @Background Executor bgExecutor) { return new NotificationEntryManager( - logger, - groupManager, - notifPipelineFlags, - notificationRowBinderLazy, - notificationRemoteInputManagerLazy, - leakDetector, - statusBarService, - dumpManager, - bgExecutor); + logger + ); } /** Provides an instance of {@link NotificationGutsManager} */ @@ -162,8 +151,7 @@ public interface NotificationsModule { Optional<BubblesManager> bubblesManagerOptional, UiEventLogger uiEventLogger, OnUserInteractionCallback onUserInteractionCallback, - ShadeController shadeController, - DumpManager dumpManager) { + ShadeController shadeController) { return new NotificationGutsManager( context, centralSurfacesOptionalLazy, @@ -181,8 +169,8 @@ public interface NotificationsModule { bubblesManagerOptional, uiEventLogger, onUserInteractionCallback, - shadeController, - dumpManager); + shadeController + ); } /** Provides an instance of {@link NotifGutsViewManager} */ @@ -193,19 +181,14 @@ public interface NotificationsModule { @SysUISingleton @Provides static VisualStabilityManager provideVisualStabilityManager( - NotificationEntryManager notificationEntryManager, VisualStabilityProvider visualStabilityProvider, - @Main Handler handler, StatusBarStateController statusBarStateController, - WakefulnessLifecycle wakefulnessLifecycle, - DumpManager dumpManager) { + WakefulnessLifecycle wakefulnessLifecycle) { return new VisualStabilityManager( - notificationEntryManager, visualStabilityProvider, - handler, statusBarStateController, - wakefulnessLifecycle, - dumpManager); + wakefulnessLifecycle + ); } /** Provides an instance of {@link NotificationLogger} */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java deleted file mode 100644 index 74fb3f7f9f66..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification.interruption; - -import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY; - -import android.app.Notification; -import android.service.notification.StatusBarNotification; -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; - -import javax.inject.Inject; - -/** - * Controller class for old pipeline heads up logic. It listens to {@link NotificationEntryManager} - * entry events and appropriately binds or unbinds the heads up view and promotes it to the top - * of the screen. - */ -@SysUISingleton -public class HeadsUpController { - private final HeadsUpViewBinder mHeadsUpViewBinder; - private final NotificationInterruptStateProvider mInterruptStateProvider; - private final NotificationRemoteInputManager mRemoteInputManager; - private final VisualStabilityManager mVisualStabilityManager; - private final StatusBarStateController mStatusBarStateController; - private final NotificationListener mNotificationListener; - private final HeadsUpManager mHeadsUpManager; - - @Inject - HeadsUpController( - HeadsUpViewBinder headsUpViewBinder, - NotificationInterruptStateProvider notificationInterruptStateProvider, - HeadsUpManager headsUpManager, - NotificationRemoteInputManager remoteInputManager, - StatusBarStateController statusBarStateController, - VisualStabilityManager visualStabilityManager, - NotificationListener notificationListener) { - mHeadsUpViewBinder = headsUpViewBinder; - mHeadsUpManager = headsUpManager; - mInterruptStateProvider = notificationInterruptStateProvider; - mRemoteInputManager = remoteInputManager; - mStatusBarStateController = statusBarStateController; - mVisualStabilityManager = visualStabilityManager; - mNotificationListener = notificationListener; - } - - /** - * Attach this controller and add its listeners. - */ - public void attach( - NotificationEntryManager entryManager, - HeadsUpManager headsUpManager) { - entryManager.addCollectionListener(mCollectionListener); - headsUpManager.addListener(mOnHeadsUpChangedListener); - } - - private NotifCollectionListener mCollectionListener = new NotifCollectionListener() { - @Override - public void onEntryAdded(NotificationEntry entry) { - if (mInterruptStateProvider.shouldHeadsUp(entry)) { - mHeadsUpViewBinder.bindHeadsUpView( - entry, HeadsUpController.this::showAlertingView); - } - } - - @Override - public void onEntryUpdated(NotificationEntry entry) { - updateHunState(entry); - } - - @Override - public void onEntryRemoved(NotificationEntry entry, int reason) { - stopAlerting(entry); - } - - @Override - public void onEntryCleanUp(NotificationEntry entry) { - mHeadsUpViewBinder.abortBindCallback(entry); - } - }; - - /** - * Adds the entry to the HUN manager and show it for the first time. - */ - private void showAlertingView(NotificationEntry entry) { - mHeadsUpManager.showNotification(entry); - if (!mStatusBarStateController.isDozing()) { - // Mark as seen immediately - setNotificationShown(entry.getSbn()); - } - } - - private void updateHunState(NotificationEntry entry) { - boolean hunAgain = alertAgain(entry, entry.getSbn().getNotification()); - // includes check for whether this notification should be filtered: - boolean shouldHeadsUp = mInterruptStateProvider.shouldHeadsUp(entry); - final boolean wasHeadsUp = mHeadsUpManager.isAlerting(entry.getKey()); - if (wasHeadsUp) { - if (shouldHeadsUp) { - mHeadsUpManager.updateNotification(entry.getKey(), hunAgain); - } else { - // We don't want this to be interrupting anymore, let's remove it - mHeadsUpManager.removeNotification(entry.getKey(), false /* removeImmediately */); - } - } else if (shouldHeadsUp && hunAgain) { - mHeadsUpViewBinder.bindHeadsUpView(entry, mHeadsUpManager::showNotification); - } - } - - private void setNotificationShown(StatusBarNotification n) { - try { - mNotificationListener.setNotificationsShown(new String[]{n.getKey()}); - } catch (RuntimeException e) { - Log.d(TAG, "failed setNotificationsShown: ", e); - } - } - - private void stopAlerting(NotificationEntry entry) { - // Attempt to remove notifications from their HUN manager. - // Though the remove itself may fail, it lets the manager know to remove as soon as - // possible. - String key = entry.getKey(); - if (mHeadsUpManager.isAlerting(key)) { - // A cancel() in response to a remote input shouldn't be delayed, as it makes the - // sending look longer than it takes. - // Also we should not defer the removal if reordering isn't allowed since otherwise - // some notifications can't disappear before the panel is closed. - boolean ignoreEarliestRemovalTime = - mRemoteInputManager.isSpinning(key) - && !FORCE_REMOTE_INPUT_HISTORY - || !mVisualStabilityManager.isReorderingAllowed(); - mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime); - } - } - - /** - * Checks whether an update for a notification warrants an alert for the user. - * - * @param oldEntry the entry for this notification. - * @param newNotification the new notification for this entry. - * @return whether this notification should alert the user. - */ - public static boolean alertAgain( - NotificationEntry oldEntry, Notification newNotification) { - return oldEntry == null || !oldEntry.hasInterrupted() - || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0; - } - - private OnHeadsUpChangedListener mOnHeadsUpChangedListener = new OnHeadsUpChangedListener() { - @Override - public void onHeadsUpStateChanged(@NonNull NotificationEntry entry, boolean isHeadsUp) { - if (!isHeadsUp && !entry.getRow().isRemoved()) { - mHeadsUpViewBinder.unbindHeadsUpView(entry); - } - } - }; - - private static final String TAG = "HeadsUpBindController"; -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java index 5ef2b9e55d9e..6f41425b506d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java @@ -41,8 +41,7 @@ import javax.inject.Inject; * figuring out the right heads up inflation parameters and inflating/freeing the heads up * content view. * - * TODO: This should be moved into {@link HeadsUpCoordinator} when the old pipeline is deprecated - * (i.e. when {@link HeadsUpController} is removed). + * TODO: This should be moved into {@link HeadsUpCoordinator} when the old pipeline is deprecated. */ @SysUISingleton public class HeadsUpViewBinder { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 3c018022085d..9ad906c83e10 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -94,7 +94,6 @@ import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.logging.NotificationCounters; @@ -904,21 +903,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mChildrenContainer == null ? null : mChildrenContainer.getAttachedChildren(); } - /** - * Apply the order given in the list to the children. - * - * @param childOrder the new list order - * @param visualStabilityManager - * @param callback the callback to invoked in case it is not allowed - * @return whether the list order has changed - */ - public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder, - VisualStabilityManager visualStabilityManager, - VisualStabilityManager.Callback callback) { - return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder, - visualStabilityManager, callback); - } - /** Updates states of all children. */ public void updateChildrenStates(AmbientState ambientState) { if (mIsSummaryWithChildren) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index c4ff2599c2ce..7b0b0ce3a691 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -55,7 +55,6 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.settings.UserContextProvider; import com.android.systemui.shade.ShadeController; -import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.StatusBarState; @@ -81,8 +80,7 @@ import dagger.Lazy; * Handles various NotificationGuts related tasks, such as binding guts to a row, opening and * closing guts, and keeping track of the currently exposed notification guts. */ -public class NotificationGutsManager implements Dumpable, NotificationLifetimeExtender, - NotifGutsViewManager { +public class NotificationGutsManager implements NotifGutsViewManager { private static final String TAG = "NotificationGutsManager"; // Must match constant in Settings. Used to highlight preferences when linking to Settings. @@ -107,13 +105,10 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx // which notification is currently being longpress-examined by the user private NotificationGuts mNotificationGutsExposed; private NotificationMenuRowPlugin.MenuItem mGutsMenuItem; - private NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback; private NotificationPresenter mPresenter; private NotificationActivityStarter mNotificationActivityStarter; private NotificationListContainer mListContainer; private OnSettingsClickListener mOnSettingsClickListener; - @VisibleForTesting - protected String mKeyToRemoveOnGutsClosed; private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final Handler mMainHandler; @@ -148,8 +143,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx Optional<BubblesManager> bubblesManagerOptional, UiEventLogger uiEventLogger, OnUserInteractionCallback onUserInteractionCallback, - ShadeController shadeController, - DumpManager dumpManager) { + ShadeController shadeController) { mContext = context; mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mMainHandler = mainHandler; @@ -167,8 +161,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mUiEventLogger = uiEventLogger; mOnUserInteractionCallback = onUserInteractionCallback; mShadeController = shadeController; - - dumpManager.registerDumpable(this); } public void setUpWithPresenter(NotificationPresenter presenter, @@ -266,12 +258,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mGutsListener.onGutsClose(entry); } String key = entry.getKey(); - if (key.equals(mKeyToRemoveOnGutsClosed)) { - mKeyToRemoveOnGutsClosed = null; - if (mNotificationLifetimeFinishedCallback != null) { - mNotificationLifetimeFinishedCallback.onSafeToRemove(key); - } - } }); View gutsView = item.getGutsView(); @@ -658,46 +644,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx return true; } - @Override - public void setCallback(NotificationSafeToRemoveCallback callback) { - mNotificationLifetimeFinishedCallback = callback; - } - - @Override - public boolean shouldExtendLifetime(NotificationEntry entry) { - return entry != null - &&(mNotificationGutsExposed != null - && entry.getGuts() != null - && mNotificationGutsExposed == entry.getGuts() - && !mNotificationGutsExposed.isLeavebehind()); - } - - @Override - public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) { - if (shouldExtend) { - mKeyToRemoveOnGutsClosed = entry.getKey(); - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Keeping notification because it's showing guts. " + entry.getKey()); - } - } else { - if (mKeyToRemoveOnGutsClosed != null - && mKeyToRemoveOnGutsClosed.equals(entry.getKey())) { - mKeyToRemoveOnGutsClosed = null; - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Notification that was kept for guts was updated. " - + entry.getKey()); - } - } - } - } - - @Override - public void dump(PrintWriter pw, String[] args) { - pw.println("NotificationGutsManager state:"); - pw.print(" mKeyToRemoveOnGutsClosed (legacy): "); - pw.println(mKeyToRemoveOnGutsClosed); - } - /** * @param gutsListener the listener for open and close guts events */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index a76f0827fc18..d77e03fd043d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -43,7 +43,6 @@ import com.android.systemui.statusbar.NotificationGroupingUtil; import com.android.systemui.statusbar.notification.FeedbackIcon; import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.NotificationUtils; -import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.row.HybridGroupManager; @@ -462,39 +461,6 @@ public class NotificationChildrenContainer extends ViewGroup return mAttachedChildren; } - /** - * Apply the order given in the list to the children. - * - * @param childOrder the new list order - * @param visualStabilityManager - * @param callback - * @return whether the list order has changed - */ - public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder, - VisualStabilityManager visualStabilityManager, - VisualStabilityManager.Callback callback) { - if (childOrder == null) { - return false; - } - boolean result = false; - for (int i = 0; i < mAttachedChildren.size() && i < childOrder.size(); i++) { - ExpandableNotificationRow child = mAttachedChildren.get(i); - ExpandableNotificationRow desiredChild = childOrder.get(i); - if (child != desiredChild) { - if (visualStabilityManager.canReorderNotification(desiredChild)) { - mAttachedChildren.remove(desiredChild); - mAttachedChildren.add(i, desiredChild); - result = true; - } else { - visualStabilityManager.addReorderingAllowedCallback(callback, - false /* persistent */); - } - } - } - updateExpansionStates(); - return result; - } - /** To be called any time the rows have been updated */ public void updateExpansionStates() { if (mChildrenExpanded || mUserLocked) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt index 54e26c34522d..91a28139c775 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt @@ -20,9 +20,6 @@ import android.util.Log import android.view.View import com.android.internal.annotations.VisibleForTesting import com.android.systemui.media.KeyguardMediaController -import com.android.systemui.plugins.statusbar.StatusBarStateController -import com.android.systemui.statusbar.StatusBarState -import com.android.systemui.statusbar.notification.NotifPipelineFlags import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager import com.android.systemui.statusbar.notification.collection.render.MediaContainerController import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController @@ -33,32 +30,20 @@ import com.android.systemui.statusbar.notification.dagger.PeopleHeader import com.android.systemui.statusbar.notification.dagger.SilentHeader import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView -import com.android.systemui.statusbar.notification.row.StackScrollerDecorView import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider import com.android.systemui.statusbar.policy.ConfigurationController -import com.android.systemui.util.children import com.android.systemui.util.foldToSparseArray -import com.android.systemui.util.takeUntil -import com.android.systemui.util.traceSection import javax.inject.Inject /** - * Manages the boundaries of the notification sections (incoming, conversations, high priority, and - * low priority). - * - * In the legacy notification pipeline, this is responsible for correctly positioning all section - * headers after the [NotificationStackScrollLayout] has had notifications added/removed/changed. In - * the new pipeline, this is handled as part of the [ShadeViewManager]. + * Manages section headers in the NSSL. * * TODO: Move remaining sections logic from NSSL into this class. */ class NotificationSectionsManager @Inject internal constructor( - private val statusBarStateController: StatusBarStateController, private val configurationController: ConfigurationController, private val keyguardMediaController: KeyguardMediaController, private val sectionsFeatureManager: NotificationSectionsFeatureManager, - private val logger: NotificationSectionsLogger, - private val notifPipelineFlags: NotifPipelineFlags, private val mediaContainerController: MediaContainerController, @IncomingHeader private val incomingHeaderController: SectionHeaderController, @PeopleHeader private val peopleHeaderController: SectionHeaderController, @@ -139,205 +124,6 @@ class NotificationSectionsManager @Inject internal constructor( else -> null } - private fun logShadeChild(i: Int, child: View) { - when { - child === incomingHeaderView -> logger.logIncomingHeader(i) - child === mediaControlsView -> logger.logMediaControls(i) - child === peopleHeaderView -> logger.logConversationsHeader(i) - child === alertingHeaderView -> logger.logAlertingHeader(i) - child === silentHeaderView -> logger.logSilentHeader(i) - child !is ExpandableNotificationRow -> logger.logOther(i, child.javaClass) - else -> { - val isHeadsUp = child.isHeadsUp - when (child.entry.bucket) { - BUCKET_HEADS_UP -> logger.logHeadsUp(i, isHeadsUp) - BUCKET_PEOPLE -> logger.logConversation(i, isHeadsUp) - BUCKET_ALERTING -> logger.logAlerting(i, isHeadsUp) - BUCKET_SILENT -> logger.logSilent(i, isHeadsUp) - } - } - } - } - private fun logShadeContents() = traceSection("NotifSectionsManager.logShadeContents") { - parent.children.forEachIndexed(::logShadeChild) - } - - private val isUsingMultipleSections: Boolean - get() = sectionsFeatureManager.getNumberOfBuckets() > 1 - - @VisibleForTesting - fun updateSectionBoundaries() = updateSectionBoundaries("test") - - private interface SectionUpdateState<out T : ExpandableView> { - val header: T - var currentPosition: Int? - var targetPosition: Int? - fun adjustViewPosition() - } - - private fun <T : ExpandableView> expandableViewHeaderState(header: T): SectionUpdateState<T> = - object : SectionUpdateState<T> { - override val header = header - override var currentPosition: Int? = null - override var targetPosition: Int? = null - - override fun adjustViewPosition() { - notifPipelineFlags.checkLegacyPipelineEnabled() - val target = targetPosition - val current = currentPosition - if (target == null) { - if (current != null) { - parent.removeView(header) - } - } else { - if (current == null) { - // If the header is animating away, it will still have a parent, so - // detach it first - // TODO: We should really cancel the active animations here. This will - // happen automatically when the view's intro animation starts, but - // it's a fragile link. - header.removeFromTransientContainer() - parent.addView(header, target) - } else { - parent.changeViewPosition(header, target) - } - } - } - } - - private fun <T : StackScrollerDecorView> decorViewHeaderState( - header: T - ): SectionUpdateState<T> { - notifPipelineFlags.checkLegacyPipelineEnabled() - val inner = expandableViewHeaderState(header) - return object : SectionUpdateState<T> by inner { - override fun adjustViewPosition() { - inner.adjustViewPosition() - if (targetPosition != null && currentPosition == null) { - header.isContentVisible = true - } - } - } - } - - /** - * Should be called whenever notifs are added, removed, or updated. Updates section boundary - * bookkeeping and adds/moves/removes section headers if appropriate. - */ - fun updateSectionBoundaries(reason: String) = traceSection("NotifSectionsManager.update") { - notifPipelineFlags.checkLegacyPipelineEnabled() - if (!isUsingMultipleSections) { - return@traceSection - } - logger.logStartSectionUpdate(reason) - - // The overall strategy here is to iterate over the current children of mParent, looking - // for where the sections headers are currently positioned, and where each section begins. - // Then, once we find the start of a new section, we track that position as the "target" for - // the section header, adjusted for the case where existing headers are in front of that - // target, but won't be once they are moved / removed after the pass has completed. - - val showHeaders = statusBarStateController.state != StatusBarState.KEYGUARD - val usingMediaControls = sectionsFeatureManager.isMediaControlsEnabled() - - val mediaState = mediaControlsView?.let(::expandableViewHeaderState) - val incomingState = incomingHeaderView?.let(::decorViewHeaderState) - val peopleState = peopleHeaderView?.let(::decorViewHeaderState) - val alertingState = alertingHeaderView?.let(::decorViewHeaderState) - val gentleState = silentHeaderView?.let(::decorViewHeaderState) - - fun getSectionState(view: View): SectionUpdateState<ExpandableView>? = when { - view === mediaControlsView -> mediaState - view === incomingHeaderView -> incomingState - view === peopleHeaderView -> peopleState - view === alertingHeaderView -> alertingState - view === silentHeaderView -> gentleState - else -> null - } - - val headersOrdered = sequenceOf( - mediaState, incomingState, peopleState, alertingState, gentleState - ).filterNotNull() - - var peopleNotifsPresent = false - var nextBucket: Int? = null - var inIncomingSection = false - - // Iterating backwards allows for easier construction of the Incoming section, as opposed - // to backtracking when a discontinuity in the sections is discovered. - // Iterating to -1 in order to support the case where a header is at the very top of the - // shade. - for (i in parent.childCount - 1 downTo -1) { - val child: View? = parent.getChildAt(i) - - child?.let { - logShadeChild(i, child) - // If this child is a header, update the tracked positions - getSectionState(child)?.let { state -> - state.currentPosition = i - // If headers that should appear above this one in the shade already have a - // target index, then we need to decrement them in order to account for this one - // being either removed, or moved below them. - headersOrdered.takeUntil { it === state } - .forEach { it.targetPosition = it.targetPosition?.minus(1) } - } - } - - val row = (child as? ExpandableNotificationRow) - ?.takeUnless { it.visibility == View.GONE } - - // Is there a section discontinuity? This usually occurs due to HUNs - inIncomingSection = inIncomingSection || nextBucket?.let { next -> - row?.entry?.bucket?.let { curr -> next < curr } - } == true - - if (inIncomingSection) { - // Update the bucket to reflect that it's being placed in the Incoming section - row?.entry?.bucket = BUCKET_HEADS_UP - } - - // Insert a header in front of the next row, if there's a boundary between it and this - // row, or if it is the topmost row. - val isSectionBoundary = nextBucket != null && - (child == null || row != null && nextBucket != row.entry.bucket) - if (isSectionBoundary && showHeaders) { - when (nextBucket) { - BUCKET_SILENT -> gentleState?.targetPosition = i + 1 - } - } - - row ?: continue - - // Check if there are any people notifications - peopleNotifsPresent = peopleNotifsPresent || row.entry.bucket == BUCKET_PEOPLE - nextBucket = row.entry.bucket - } - - mediaState?.targetPosition = if (usingMediaControls) 0 else null - - logger.logStr("New header target positions:") - logger.logMediaControls(mediaState?.targetPosition ?: -1) - logger.logIncomingHeader(incomingState?.targetPosition ?: -1) - logger.logConversationsHeader(peopleState?.targetPosition ?: -1) - logger.logAlertingHeader(alertingState?.targetPosition ?: -1) - logger.logSilentHeader(gentleState?.targetPosition ?: -1) - - // Update headers in reverse order to preserve indices, otherwise movements earlier in the - // list will affect the target indices of the headers later in the list. - headersOrdered.asIterable().reversed().forEach { it.adjustViewPosition() } - - logger.logStr("Final order:") - logShadeContents() - logger.logStr("Section boundary update complete") - - // Update headers to reflect state of section contents - silentHeaderView?.run { - val hasActiveClearableNotifications = this@NotificationSectionsManager.parent - .hasActiveClearableNotifications(NotificationStackScrollLayout.ROWS_GENTLE) - setClearSectionButtonEnabled(hasActiveClearableNotifications) - } - } - private sealed class SectionBounds { data class Many( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 427004e71425..952bafbe6eb3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -5822,12 +5822,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mSpeedBumpIndexDirty = true; } - /** Updates the indices of the boundaries between sections. */ - @ShadeViewRefactor(RefactorComponent.INPUT) - public void updateSectionBoundaries(String reason) { - mSectionsManager.updateSectionBoundaries(reason); - } - void updateContinuousBackgroundDrawing() { boolean continuousBackground = !mAmbientState.isFullyAwake() && mSwipeHelper.isSwiping(); 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 cc539b01b894..9998fe41b775 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 @@ -90,7 +90,6 @@ import com.android.systemui.statusbar.notification.collection.PipelineDumpable; import com.android.systemui.statusbar.notification.collection.PipelineDumper; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener; -import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; 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; @@ -162,7 +161,6 @@ public class NotificationStackScrollLayoutController { private final NotificationEntryManager mNotificationEntryManager; private final UiEventLogger mUiEventLogger; private final NotificationRemoteInputManager mRemoteInputManager; - private final VisualStabilityManager mVisualStabilityManager; private final ShadeController mShadeController; private final KeyguardMediaController mKeyguardMediaController; private final SysuiStatusBarStateController mStatusBarStateController; @@ -646,7 +644,6 @@ public class NotificationStackScrollLayoutController { ShadeTransitionController shadeTransitionController, UiEventLogger uiEventLogger, NotificationRemoteInputManager remoteInputManager, - VisualStabilityManager visualStabilityManager, ShadeController shadeController, InteractionJankMonitor jankMonitor, StackStateLogger stackLogger, @@ -693,7 +690,6 @@ public class NotificationStackScrollLayoutController { mNotificationEntryManager = notificationEntryManager; mUiEventLogger = uiEventLogger; mRemoteInputManager = remoteInputManager; - mVisualStabilityManager = visualStabilityManager; mShadeController = shadeController; updateResources(); } @@ -765,8 +761,6 @@ public class NotificationStackScrollLayoutController { mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate); mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded); - mVisualStabilityManager.setVisibilityLocationProvider(this::isInVisibleLocation); - mTunerService.addTunable( (key, newValue) -> { switch (key) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 896e3e53946a..7da1d6c085b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -207,7 +207,6 @@ import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; -import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; @@ -705,7 +704,6 @@ public class CentralSurfacesImpl extends CoreStartable implements WakefulnessLifecycle wakefulnessLifecycle, SysuiStatusBarStateController statusBarStateController, Optional<Bubbles> bubblesOptional, - VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, AccessibilityFloatingMenuController accessibilityFloatingMenuController, @@ -793,7 +791,6 @@ public class CentralSurfacesImpl extends CoreStartable implements mWakefulnessLifecycle = wakefulnessLifecycle; mStatusBarStateController = statusBarStateController; mBubblesOptional = bubblesOptional; - mVisualStabilityManager = visualStabilityManager; mDeviceProvisionedController = deviceProvisionedController; mNavigationBarController = navigationBarController; mAccessibilityFloatingMenuController = accessibilityFloatingMenuController; @@ -3931,9 +3928,6 @@ public class CentralSurfacesImpl extends CoreStartable implements // all notifications protected NotificationStackScrollLayout mStackScroller; - // handling reordering - private final VisualStabilityManager mVisualStabilityManager; - protected AccessibilityManager mAccessibilityManager; protected boolean mDeviceInteractive; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 80432dbd277c..51536c310dc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -326,14 +326,6 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, dumpInternal(pw, args); } - @Override - public boolean shouldExtendLifetime(NotificationEntry entry) { - // We should not defer the removal if reordering isn't allowed since otherwise - // these won't disappear until reordering is allowed again, which happens only once - // the notification panel is collapsed again. - return mVisualStabilityProvider.isReorderingAllowed() && super.shouldExtendLifetime(entry); - } - /////////////////////////////////////////////////////////////////////////////////////////////// // OnReorderingAllowedListener: diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java deleted file mode 100644 index ca6e67ec4a83..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java +++ /dev/null @@ -1,717 +0,0 @@ -/* - * Copyright (C) 2018 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.phone; - -import static com.android.systemui.statusbar.notification.NotificationUtils.logKey; -import static com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.logGroupKey; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.Notification; -import android.os.SystemClock; -import android.service.notification.StatusBarNotification; -import android.util.ArrayMap; -import android.util.Log; - -import com.android.internal.statusbar.NotificationVisibility; -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; -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.legacy.NotificationGroupManagerLegacy; -import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup; -import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; -import com.android.systemui.statusbar.notification.row.RowContentBindParams; -import com.android.systemui.statusbar.notification.row.RowContentBindStage; -import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; -import com.android.systemui.util.Compile; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import javax.inject.Inject; - -/** - * A helper class dealing with the alert interactions between {@link NotificationGroupManagerLegacy} - * and {@link HeadsUpManager}. In particular, this class deals with keeping - * the correct notification in a group alerting based off the group suppression and alertOverride. - */ -@SysUISingleton -public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener, - StateListener { - - private static final long ALERT_TRANSFER_TIMEOUT = 300; - private static final String TAG = "NotifGroupAlertTransfer"; - private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG); - private static final boolean SPEW = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE); - - /** - * The list of entries containing group alert metadata for each group. Keyed by group key. - */ - private final ArrayMap<String, GroupAlertEntry> mGroupAlertEntries = new ArrayMap<>(); - - /** - * The list of entries currently inflating that should alert after inflation. Keyed by - * notification key. - */ - private final ArrayMap<String, PendingAlertInfo> mPendingAlerts = new ArrayMap<>(); - - private HeadsUpManager mHeadsUpManager; - private final RowContentBindStage mRowContentBindStage; - private final NotificationGroupManagerLegacy mGroupManager; - - private NotificationEntryManager mEntryManager; - - private boolean mIsDozing; - - /** - * Injected constructor. See {@link StatusBarPhoneModule}. - */ - @Inject - public NotificationGroupAlertTransferHelper( - RowContentBindStage bindStage, - StatusBarStateController statusBarStateController, - NotificationGroupManagerLegacy notificationGroupManagerLegacy) { - mRowContentBindStage = bindStage; - mGroupManager = notificationGroupManagerLegacy; - statusBarStateController.addCallback(this); - } - - /** Causes the TransferHelper to register itself as a listener to the appropriate classes. */ - public void bind(NotificationEntryManager entryManager, - NotificationGroupManagerLegacy groupManager) { - if (mEntryManager != null) { - throw new IllegalStateException("Already bound."); - } - - // TODO(b/119637830): It would be good if GroupManager already had all pending notifications - // as normal children (i.e. add notifications to GroupManager before inflation) so that we - // don't have to have this dependency. We'd also have to worry less about the suppression - // not being up to date. - mEntryManager = entryManager; - - mEntryManager.addNotificationEntryListener(mNotificationEntryListener); - groupManager.registerGroupChangeListener(mOnGroupChangeListener); - } - - /** - * Whether or not a notification has transferred its alert state to the notification and - * the notification should alert after inflating. - * - * @param entry notification to check - * @return true if the entry was transferred to and should inflate + alert - */ - public boolean isAlertTransferPending(@NonNull NotificationEntry entry) { - PendingAlertInfo alertInfo = mPendingAlerts.get(entry.getKey()); - return alertInfo != null && alertInfo.isStillValid(); - } - - public void setHeadsUpManager(HeadsUpManager headsUpManager) { - mHeadsUpManager = headsUpManager; - } - - @Override - public void onStateChanged(int newState) {} - - @Override - public void onDozingChanged(boolean isDozing) { - if (mIsDozing != isDozing) { - for (GroupAlertEntry groupAlertEntry : mGroupAlertEntries.values()) { - groupAlertEntry.mLastAlertTransferTime = 0; - groupAlertEntry.mAlertSummaryOnNextAddition = false; - } - } - mIsDozing = isDozing; - } - - private final NotificationGroupManagerLegacy.OnGroupChangeListener mOnGroupChangeListener = - new NotificationGroupManagerLegacy.OnGroupChangeListener() { - @Override - public void onGroupCreated(NotificationGroup group, String groupKey) { - mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group)); - } - - @Override - public void onGroupRemoved(NotificationGroup group, String groupKey) { - mGroupAlertEntries.remove(groupKey); - } - - @Override - public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) { - if (DEBUG) { - Log.d(TAG, "!! onGroupSuppressionChanged:" - + " group=" + logGroupKey(group) - + " group.summary=" + logKey(group.summary) - + " suppressed=" + suppressed); - } - NotificationEntry oldAlertOverride = group.alertOverride; - onGroupChanged(group, oldAlertOverride); - } - - @Override - public void onGroupAlertOverrideChanged(NotificationGroup group, - @Nullable NotificationEntry oldAlertOverride, - @Nullable NotificationEntry newAlertOverride) { - if (DEBUG) { - Log.d(TAG, "!! onGroupAlertOverrideChanged:" - + " group=" + logGroupKey(group) - + " group.summary=" + logKey(group.summary) - + " oldAlertOverride=" + logKey(oldAlertOverride) - + " newAlertOverride=" + logKey(newAlertOverride)); - } - onGroupChanged(group, oldAlertOverride); - } - }; - - /** - * Called when either the suppressed or alertOverride fields of the group changed - * - * @param group the group which changed - * @param oldAlertOverride the previous value of group.alertOverride - */ - private void onGroupChanged(NotificationGroup group, - NotificationEntry oldAlertOverride) { - // Group summary can be null if we are no longer suppressed because the summary was - // removed. In that case, we don't need to alert the summary. - if (group.summary == null) { - if (DEBUG) { - Log.d(TAG, "onGroupChanged: summary is null"); - } - return; - } - if (group.suppressed || group.alertOverride != null) { - checkForForwardAlertTransfer(group.summary, oldAlertOverride); - } else { - if (DEBUG) { - Log.d(TAG, "onGroupChanged: maybe transfer back"); - } - GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey( - group.summary.getSbn())); - // Group is no longer suppressed or overridden. - // We should check if we need to transfer the alert back to the summary. - if (groupAlertEntry.mAlertSummaryOnNextAddition) { - if (!mHeadsUpManager.isAlerting(group.summary.getKey())) { - alertNotificationWhenPossible(group.summary); - } - groupAlertEntry.mAlertSummaryOnNextAddition = false; - } else { - checkShouldTransferBack(groupAlertEntry); - } - } - } - - @Override - public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { - if (DEBUG) { - Log.d(TAG, "!! onHeadsUpStateChanged:" - + " entry=" + logKey(entry) - + " isHeadsUp=" + isHeadsUp); - } - if (isHeadsUp && entry.getSbn().getNotification().isGroupSummary()) { - // a group summary is alerting; trigger the forward transfer checks - checkForForwardAlertTransfer(entry, /* oldAlertOverride */ null); - } - } - - /** - * Handles changes in a group's suppression or alertOverride, but where at least one of those - * conditions is still true (either the group is suppressed, the group has an alertOverride, - * or both). The method determined which kind of child needs to receive the alert, finds the - * entry currently alerting, and makes the transfer. - * - * Internally, this is handled with two main cases: the override needs the alert, or there is - * no override but the summary is suppressed (so an isolated child needs the alert). - * - * @param summary the notification entry of the summary of the logical group. - * @param oldAlertOverride the former value of group.alertOverride, before whatever event - * required us to check for for a transfer condition. - */ - private void checkForForwardAlertTransfer(NotificationEntry summary, - NotificationEntry oldAlertOverride) { - if (DEBUG) { - Log.d(TAG, "checkForForwardAlertTransfer: enter"); - } - NotificationGroup group = mGroupManager.getGroupForSummary(summary.getSbn()); - if (group != null && group.alertOverride != null) { - handleOverriddenSummaryAlerted(summary); - } else if (mGroupManager.isSummaryOfSuppressedGroup(summary.getSbn())) { - handleSuppressedSummaryAlerted(summary, oldAlertOverride); - } - if (DEBUG) { - Log.d(TAG, "checkForForwardAlertTransfer: done"); - } - } - - private final NotificationEntryListener mNotificationEntryListener = - new NotificationEntryListener() { - // Called when a new notification has been posted but is not inflated yet. We use this to - // see as early as we can if we need to abort a transfer. - @Override - public void onPendingEntryAdded(NotificationEntry entry) { - if (DEBUG) { - Log.d(TAG, "!! onPendingEntryAdded: entry=" + logKey(entry)); - } - String groupKey = mGroupManager.getGroupKey(entry.getSbn()); - GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey); - if (groupAlertEntry != null && groupAlertEntry.mGroup.alertOverride == null) { - // new pending group entries require us to transfer back from the child to the - // group, but alertOverrides are only present in very limited circumstances, so - // while it's possible the group should ALSO alert, the previous detection which set - // this alertOverride won't be invalidated by this notification added to this group. - checkShouldTransferBack(groupAlertEntry); - } - } - - @Override - public void onEntryRemoved( - @Nullable NotificationEntry entry, - NotificationVisibility visibility, - boolean removedByUser, - int reason) { - // Removes any alerts pending on this entry. Note that this will not stop any inflation - // tasks started by a transfer, so this should only be used as clean-up for when - // inflation is stopped and the pending alert no longer needs to happen. - mPendingAlerts.remove(entry.getKey()); - } - }; - - /** - * Gets the number of new notifications pending inflation that will be added to the group - * but currently aren't and should not alert. - * - * @param group group to check - * @return the number of new notifications that will be added to the group - */ - private int getPendingChildrenNotAlerting(@NonNull NotificationGroup group) { - if (mEntryManager == null) { - return 0; - } - int number = 0; - Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator(); - for (NotificationEntry entry : values) { - if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) { - number++; - } - } - return number; - } - - /** - * Checks if the pending inflations will add children to this group. - * - * @param group group to check - * @return true if a pending notification will add to this group - */ - private boolean pendingInflationsWillAddChildren(@NonNull NotificationGroup group) { - if (mEntryManager == null) { - return false; - } - Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator(); - for (NotificationEntry entry : values) { - if (isPendingNotificationInGroup(entry, group)) { - return true; - } - } - return false; - } - - /** - * Checks if a new pending notification will be added to the group. - * - * @param entry pending notification - * @param group group to check - * @return true if the notification will add to the group, false o/w - */ - private boolean isPendingNotificationInGroup(@NonNull NotificationEntry entry, - @NonNull NotificationGroup group) { - String groupKey = mGroupManager.getGroupKey(group.summary.getSbn()); - return mGroupManager.isGroupChild(entry.getSbn()) - && Objects.equals(mGroupManager.getGroupKey(entry.getSbn()), groupKey) - && !group.children.containsKey(entry.getKey()); - } - - /** - * Handles the scenario where a summary that has been suppressed is itself, or has a former - * alertOverride (in the form of an isolated logical child) which was alerted. A suppressed - * summary should for all intents and purposes be invisible to the user and as a result should - * not alert. When this is the case, it is our responsibility to pass the alert to the - * appropriate child which will be the representative notification alerting for the group. - * - * @param summary the summary that is suppressed and (potentially) alerting - * @param oldAlertOverride the alertOverride before whatever event triggered this method. If - * the alert override was removed, this will be the entry that should - * be transferred back from. - */ - private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary, - NotificationEntry oldAlertOverride) { - if (DEBUG) { - Log.d(TAG, "handleSuppressedSummaryAlerted: summary=" + logKey(summary)); - } - GroupAlertEntry groupAlertEntry = - mGroupAlertEntries.get(mGroupManager.getGroupKey(summary.getSbn())); - - if (!mGroupManager.isSummaryOfSuppressedGroup(summary.getSbn()) - || groupAlertEntry == null) { - if (DEBUG) { - Log.d(TAG, "handleSuppressedSummaryAlerted: invalid state"); - } - return; - } - boolean summaryIsAlerting = mHeadsUpManager.isAlerting(summary.getKey()); - boolean priorityIsAlerting = oldAlertOverride != null - && mHeadsUpManager.isAlerting(oldAlertOverride.getKey()); - if (!summaryIsAlerting && !priorityIsAlerting) { - if (DEBUG) { - Log.d(TAG, "handleSuppressedSummaryAlerted: no summary or override alerting"); - } - return; - } - - if (pendingInflationsWillAddChildren(groupAlertEntry.mGroup)) { - // New children will actually be added to this group, let's not transfer the alert. - if (DEBUG) { - Log.d(TAG, "handleSuppressedSummaryAlerted: pending inflations"); - } - return; - } - - NotificationEntry child = - mGroupManager.getLogicalChildren(summary.getSbn()).iterator().next(); - if (summaryIsAlerting) { - if (DEBUG) { - Log.d(TAG, "handleSuppressedSummaryAlerted: transfer summary -> child"); - } - tryTransferAlertState(summary, /*from*/ summary, /*to*/ child, groupAlertEntry); - return; - } - // Summary didn't have the alert, so we're in "transfer back" territory. First, make sure - // it's not too late to transfer back, then transfer the alert from the oldAlertOverride to - // the isolated child which should receive the alert. - if (!canStillTransferBack(groupAlertEntry)) { - if (DEBUG) { - Log.d(TAG, "handleSuppressedSummaryAlerted: transfer from override: too late"); - } - return; - } - - if (DEBUG) { - Log.d(TAG, "handleSuppressedSummaryAlerted: transfer override -> child"); - } - tryTransferAlertState(summary, /*from*/ oldAlertOverride, /*to*/ child, groupAlertEntry); - } - - /** - * Checks for and handles the scenario where the given entry is the summary of a group which - * has an alertOverride, and either the summary itself or one of its logical isolated children - * is currently alerting (which happens if the summary is suppressed). - */ - private void handleOverriddenSummaryAlerted(NotificationEntry summary) { - if (DEBUG) { - Log.d(TAG, "handleOverriddenSummaryAlerted: summary=" + logKey(summary)); - } - GroupAlertEntry groupAlertEntry = - mGroupAlertEntries.get(mGroupManager.getGroupKey(summary.getSbn())); - NotificationGroup group = mGroupManager.getGroupForSummary(summary.getSbn()); - if (group == null || group.alertOverride == null || groupAlertEntry == null) { - if (DEBUG) { - Log.d(TAG, "handleOverriddenSummaryAlerted: invalid state"); - } - return; - } - boolean summaryIsAlerting = mHeadsUpManager.isAlerting(summary.getKey()); - if (summaryIsAlerting) { - if (DEBUG) { - Log.d(TAG, "handleOverriddenSummaryAlerted: transfer summary -> override"); - } - tryTransferAlertState(summary, /*from*/ summary, group.alertOverride, groupAlertEntry); - return; - } - // Summary didn't have the alert, so we're in "transfer back" territory. First, make sure - // it's not too late to transfer back, then remove the alert from any of the logical - // children, and if one of them was alerting, we can alert the override. - if (!canStillTransferBack(groupAlertEntry)) { - if (DEBUG) { - Log.d(TAG, "handleOverriddenSummaryAlerted: transfer from child: too late"); - } - return; - } - List<NotificationEntry> children = mGroupManager.getLogicalChildren(summary.getSbn()); - if (children == null) { - if (DEBUG) { - Log.d(TAG, "handleOverriddenSummaryAlerted: no children"); - } - return; - } - children.remove(group.alertOverride); // do not release the alert on our desired destination - boolean releasedChild = releaseChildAlerts(children); - if (releasedChild) { - if (DEBUG) { - Log.d(TAG, "handleOverriddenSummaryAlerted: transfer child -> override"); - } - tryTransferAlertState(summary, /*from*/ null, group.alertOverride, groupAlertEntry); - } else { - if (DEBUG) { - Log.d(TAG, "handleOverriddenSummaryAlerted: no child alert released"); - } - } - } - - /** - * Transfers the alert state one entry to another. We remove the alert from the first entry - * immediately to have the incorrect one up as short as possible. The second should alert - * when possible. - * - * @param summary entry of the summary - * @param fromEntry entry to transfer alert from - * @param toEntry entry to transfer to - */ - private void tryTransferAlertState( - NotificationEntry summary, - NotificationEntry fromEntry, - NotificationEntry toEntry, - GroupAlertEntry groupAlertEntry) { - if (toEntry != null) { - if (toEntry.getRow().keepInParent() - || toEntry.isRowRemoved() - || toEntry.isRowDismissed()) { - // The notification is actually already removed. No need to alert it. - return; - } - if (!mHeadsUpManager.isAlerting(toEntry.getKey()) && onlySummaryAlerts(summary)) { - groupAlertEntry.mLastAlertTransferTime = SystemClock.elapsedRealtime(); - } - if (DEBUG) { - Log.d(TAG, "transferAlertState:" - + " fromEntry=" + logKey(fromEntry) - + " toEntry=" + logKey(toEntry)); - } - transferAlertState(fromEntry, toEntry); - } - } - private void transferAlertState(@Nullable NotificationEntry fromEntry, - @NonNull NotificationEntry toEntry) { - if (fromEntry != null) { - mHeadsUpManager.removeNotification(fromEntry.getKey(), true /* releaseImmediately */); - } - alertNotificationWhenPossible(toEntry); - } - - /** - * Determines if we need to transfer the alert back to the summary from the child and does - * so if needed. - * - * This can happen since notification groups are not delivered as a whole unit and it is - * possible we erroneously transfer the alert from the summary to the child even though - * more children are coming. Thus, if a child is added within a certain timeframe after we - * transfer, we back out and alert the summary again. - * - * An alert can only transfer back within a small window of time after a transfer away from the - * summary to a child happened. - * - * @param groupAlertEntry group alert entry to check - */ - private void checkShouldTransferBack(@NonNull GroupAlertEntry groupAlertEntry) { - if (canStillTransferBack(groupAlertEntry)) { - NotificationEntry summary = groupAlertEntry.mGroup.summary; - - if (!onlySummaryAlerts(summary)) { - return; - } - ArrayList<NotificationEntry> children = mGroupManager.getLogicalChildren( - summary.getSbn()); - int numActiveChildren = children.size(); - int numPendingChildren = getPendingChildrenNotAlerting(groupAlertEntry.mGroup); - int numChildren = numActiveChildren + numPendingChildren; - if (numChildren <= 1) { - return; - } - boolean releasedChild = releaseChildAlerts(children); - if (releasedChild && !mHeadsUpManager.isAlerting(summary.getKey())) { - boolean notifyImmediately = numActiveChildren > 1; - if (notifyImmediately) { - alertNotificationWhenPossible(summary); - } else { - // Should wait until the pending child inflates before alerting. - groupAlertEntry.mAlertSummaryOnNextAddition = true; - } - groupAlertEntry.mLastAlertTransferTime = 0; - } - } - } - - private boolean canStillTransferBack(@NonNull GroupAlertEntry groupAlertEntry) { - return SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime - < ALERT_TRANSFER_TIMEOUT; - } - - private boolean releaseChildAlerts(List<NotificationEntry> children) { - boolean releasedChild = false; - if (SPEW) { - Log.d(TAG, "releaseChildAlerts: numChildren=" + children.size()); - } - for (int i = 0; i < children.size(); i++) { - NotificationEntry entry = children.get(i); - if (SPEW) { - Log.d(TAG, "releaseChildAlerts: checking i=" + i + " entry=" + entry - + " onlySummaryAlerts=" + onlySummaryAlerts(entry) - + " isAlerting=" + mHeadsUpManager.isAlerting(entry.getKey()) - + " isPendingAlert=" + mPendingAlerts.containsKey(entry.getKey())); - } - if (onlySummaryAlerts(entry) && mHeadsUpManager.isAlerting(entry.getKey())) { - releasedChild = true; - mHeadsUpManager.removeNotification( - entry.getKey(), true /* releaseImmediately */); - } - if (mPendingAlerts.containsKey(entry.getKey())) { - // This is the child that would've been removed if it was inflated. - releasedChild = true; - mPendingAlerts.get(entry.getKey()).mAbortOnInflation = true; - } - } - if (SPEW) { - Log.d(TAG, "releaseChildAlerts: didRelease=" + releasedChild); - } - return releasedChild; - } - - /** - * Tries to alert the notification. If its content view is not inflated, we inflate and continue - * when the entry finishes inflating the view. - * - * @param entry entry to show - */ - private void alertNotificationWhenPossible(@NonNull NotificationEntry entry) { - @InflationFlag int contentFlag = mHeadsUpManager.getContentFlag(); - final RowContentBindParams params = mRowContentBindStage.getStageParams(entry); - if ((params.getContentViews() & contentFlag) == 0) { - if (DEBUG) { - Log.d(TAG, "alertNotificationWhenPossible:" - + " async requestRebind entry=" + logKey(entry)); - } - mPendingAlerts.put(entry.getKey(), new PendingAlertInfo(entry)); - params.requireContentViews(contentFlag); - mRowContentBindStage.requestRebind(entry, en -> { - PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.getKey()); - if (alertInfo != null) { - if (alertInfo.isStillValid()) { - alertNotificationWhenPossible(entry); - } else { - if (DEBUG) { - Log.d(TAG, "alertNotificationWhenPossible:" - + " markContentViewsFreeable entry=" + logKey(entry)); - } - // The transfer is no longer valid. Free the content. - mRowContentBindStage.getStageParams(entry).markContentViewsFreeable( - contentFlag); - mRowContentBindStage.requestRebind(entry, null); - } - } - }); - return; - } - if (mHeadsUpManager.isAlerting(entry.getKey())) { - if (DEBUG) { - Log.d(TAG, "alertNotificationWhenPossible:" - + " continue alerting entry=" + logKey(entry)); - } - mHeadsUpManager.updateNotification(entry.getKey(), true /* alert */); - } else { - if (DEBUG) { - Log.d(TAG, "alertNotificationWhenPossible:" - + " start alerting entry=" + logKey(entry)); - } - mHeadsUpManager.showNotification(entry); - } - } - - private boolean onlySummaryAlerts(NotificationEntry entry) { - return entry.getSbn().getNotification().getGroupAlertBehavior() - == Notification.GROUP_ALERT_SUMMARY; - } - - /** - * Information about a pending alert used to determine if the alert is still needed when - * inflation completes. - */ - private class PendingAlertInfo { - - /** - * The original notification when the transfer is initiated. This is used to determine if - * the transfer is still valid if the notification is updated. - */ - final StatusBarNotification mOriginalNotification; - final NotificationEntry mEntry; - - /** - * The notification is still pending inflation but we've decided that we no longer need - * the content view (e.g. suppression might have changed and we decided we need to transfer - * back). - * - * TODO: Replace this entire structure with {@link RowContentBindStage#requestRebind)}. - */ - boolean mAbortOnInflation; - - PendingAlertInfo(NotificationEntry entry) { - mOriginalNotification = entry.getSbn(); - mEntry = entry; - } - - /** - * Whether or not the pending alert is still valid and should still alert after inflation. - * - * @return true if the pending alert should still occur, false o/w - */ - private boolean isStillValid() { - if (mAbortOnInflation) { - // Notification is aborted due to the transfer being explicitly cancelled - return false; - } - if (!mEntry.getSbn().getGroupKey().equals(mOriginalNotification.getGroupKey())) { - // Groups have changed - return false; - } - if (mEntry.getSbn().getNotification().isGroupSummary() - != mOriginalNotification.getNotification().isGroupSummary()) { - // Notification has changed from group summary to not or vice versa - return false; - } - return true; - } - } - - /** - * Contains alert metadata for the notification group used to determine when/how the alert - * should be transferred. - */ - private static class GroupAlertEntry { - /** - * The time when the last alert transfer from summary to child happened. - */ - long mLastAlertTransferTime; - boolean mAlertSummaryOnNextAddition; - final NotificationGroup mGroup; - - GroupAlertEntry(NotificationGroup group) { - this.mGroup = group; - } - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java index d414660018a8..2aab9e82986e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java @@ -43,7 +43,6 @@ import android.widget.TextView; import androidx.core.graphics.drawable.IconCompat; import androidx.test.filters.SmallTest; -import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.bluetooth.LocalBluetoothManager; @@ -54,7 +53,7 @@ import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.media.nearby.NearbyMediaDevicesManager; import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import org.junit.Before; import org.junit.Test; @@ -83,8 +82,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase { LocalBluetoothLeBroadcast.class); private ActivityStarter mStarter = mock(ActivityStarter.class); private BroadcastSender mBroadcastSender = mock(BroadcastSender.class); - private NotificationEntryManager mNotificationEntryManager = - mock(NotificationEntryManager.class); + private final CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class); private NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock( NearbyMediaDevicesManager.class); private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); @@ -120,7 +118,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase { mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, mMediaSessionManager, mLocalBluetoothManager, mStarter, - mNotificationEntryManager, mDialogLaunchAnimator, + mNotifCollection, mDialogLaunchAnimator, Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager); mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext, mBroadcastSender, mMediaOutputController); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java index 6afed1a846b0..4779d322a90e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java @@ -47,7 +47,7 @@ import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.media.nearby.NearbyMediaDevicesManager; import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import org.junit.After; import org.junit.Before; @@ -78,8 +78,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class); private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class); private final MediaDevice mMediaDevice = mock(MediaDevice.class); - private final NotificationEntryManager mNotificationEntryManager = - mock(NotificationEntryManager.class); + private final CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class); private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class); private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock( @@ -104,7 +103,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, mMediaSessionManager, mLocalBluetoothManager, mStarter, - mNotificationEntryManager, mDialogLaunchAnimator, + mNotifCollection, mDialogLaunchAnimator, Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager); mMediaOutputController.mLocalMediaManager = mLocalMediaManager; mMediaOutputDialog = new MediaOutputDialog(mContext, false, mBroadcastSender, diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java index fba19861b006..bd913bab6f65 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java @@ -63,7 +63,6 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.people.widget.PeopleSpaceWidgetManager; import com.android.systemui.people.widget.PeopleTileKey; import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; @@ -196,8 +195,6 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { @Mock private PackageManager mPackageManager; @Mock - private NotificationEntryManager mNotificationEntryManager; - @Mock private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager; @Mock private BackupManager mBackupManager; @@ -234,8 +231,6 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { when(mMockContext.getString(R.string.over_two_weeks_timestamp)).thenReturn( mContext.getString(R.string.over_two_weeks_timestamp)); when(mPackageManager.getApplicationIcon(anyString())).thenReturn(null); - when(mNotificationEntryManager.getVisibleNotifications()) - .thenReturn(List.of(mNotificationEntry1, mNotificationEntry2, mNotificationEntry3)); } @After diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java index 8a388479c0e7..98de1763825f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java @@ -25,7 +25,6 @@ import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; import android.app.ActivityManager; import android.app.Notification; @@ -218,41 +217,4 @@ public class AlertingNotificationManagerTest extends SysuiTestCase { // The entry has just been added so we should not remove immediately. assertFalse(mAlertingNotificationManager.canRemoveImmediately(mEntry.getKey())); } - - @Test - public void testShouldExtendLifetime() { - mAlertingNotificationManager.showNotification(mEntry); - - // While the entry is alerting, it should not be removable. - assertTrue(mAlertingNotificationManager.shouldExtendLifetime(mEntry)); - } - - @Test - public void testSetShouldManageLifetime_setShouldManage() { - mAlertingNotificationManager.showNotification(mEntry); - - mAlertingNotificationManager.setShouldManageLifetime(mEntry, true /* shouldManage */); - - assertTrue(mAlertingNotificationManager.mExtendedLifetimeAlertEntries.contains(mEntry)); - } - - @Test - public void testSetShouldManageLifetime_setShouldManageCallsRemoval() { - mAlertingNotificationManager.showNotification(mEntry); - mAlertingNotificationManager.setShouldManageLifetime(mEntry, true /* shouldManage */); - if (mAlertingNotificationManager instanceof TestableAlertingNotificationManager) { - TestableAlertingNotificationManager testableManager = - (TestableAlertingNotificationManager) mAlertingNotificationManager; - verify(testableManager.mLastCreatedEntry).removeAsSoonAsPossible(); - } - } - - @Test - public void testSetShouldManageLifetime_setShouldNotManage() { - mAlertingNotificationManager.mExtendedLifetimeAlertEntries.add(mEntry); - - mAlertingNotificationManager.setShouldManageLifetime(mEntry, false /* shouldManage */); - - assertFalse(mAlertingNotificationManager.mExtendedLifetimeAlertEntries.contains(mEntry)); - } } 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 34d13c76399a..6e29669a227b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java @@ -161,10 +161,8 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { smartReplyController, visibilityProvider, notificationEntryManager, - rebuilder, centralSurfacesOptionalLazy, statusBarStateController, - mainHandler, remoteInputUriController, clickNotifier, actionClickLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java deleted file mode 100644 index 842f057b96fc..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ /dev/null @@ -1,684 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.notification; - -import static android.app.NotificationManager.IMPORTANCE_DEFAULT; -import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; -import static android.service.notification.NotificationListenerService.REASON_CANCEL; -import static android.service.notification.NotificationStats.DISMISSAL_SHADE; -import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL; - -import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON; - -import static com.google.common.truth.Truth.assertThat; - -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import android.app.ActivityManager; -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.PendingIntent; -import android.content.Intent; -import android.graphics.drawable.Icon; -import android.os.Handler; -import android.os.RemoteException; -import android.os.UserHandle; -import android.service.notification.NotificationListenerService.Ranking; -import android.service.notification.NotificationListenerService.RankingMap; -import android.service.notification.StatusBarNotification; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.util.ArraySet; - -import androidx.annotation.NonNull; -import androidx.test.filters.SmallTest; - -import com.android.internal.statusbar.IStatusBarService; -import com.android.internal.statusbar.NotificationVisibility; -import com.android.systemui.Dependency; -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.dump.DumpManager; -import com.android.systemui.statusbar.NotificationLifetimeExtender; -import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.NotificationPresenter; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationRemoveInterceptor; -import com.android.systemui.statusbar.SmartReplyController; -import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; -import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; -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.provider.HighPriorityProvider; -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.RowInflaterTask; -import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.util.concurrency.FakeExecutor; -import com.android.systemui.util.leak.LeakDetector; -import com.android.systemui.util.time.FakeSystemClock; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Set; - -/** - * Unit tests for {@link NotificationEntryManager}. - */ -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper() -public class NotificationEntryManagerTest extends SysuiTestCase { - private static final String TEST_PACKAGE_NAME = "test"; - private static final int TEST_UID = 0; - - @Mock private NotificationPresenter mPresenter; - @Mock private KeyguardEnvironment mEnvironment; - @Mock private ExpandableNotificationRow mRow; - @Mock private NotificationEntryListener mEntryListener; - @Mock private NotifCollectionListener mNotifCollectionListener; - @Mock private NotificationRemoveInterceptor mRemoveInterceptor; - @Mock private HeadsUpManager mHeadsUpManager; - @Mock private RankingMap mRankingMap; - @Mock private NotificationGroupManagerLegacy mGroupManager; - @Mock private NotificationRemoteInputManager mRemoteInputManager; - @Mock private DeviceProvisionedController mDeviceProvisionedController; - @Mock private RowInflaterTask mAsyncInflationTask; - @Mock private NotificationEntryManagerLogger mLogger; - @Mock private NotifPipelineFlags mNotifPipelineFlags; - @Mock private LeakDetector mLeakDetector; - @Mock private NotificationMediaManager mNotificationMediaManager; - @Mock private NotificationRowBinder mNotificationRowBinder; - @Mock private NotificationListener mNotificationListener; - @Mock private IStatusBarService mStatusBarService; - - private FakeSystemClock mFakeSystemClock = new FakeSystemClock(); - private FakeExecutor mBgExecutor = new FakeExecutor(mFakeSystemClock); - - private int mId; - private NotificationEntry mEntry; - private DismissedByUserStats mStats; - private StatusBarNotification mSbn; - private NotificationEntryManager mEntryManager; - - private void setUserSentiment(String key, int sentiment) { - doAnswer(invocationOnMock -> { - Ranking ranking = (Ranking) - invocationOnMock.getArguments()[1]; - ranking.populate( - key, - 0, - false, - 0, - 0, - IMPORTANCE_DEFAULT, - null, null, - null, null, null, true, sentiment, false, -1, false, null, null, false, false, - false, null, 0, false); - return true; - }).when(mRankingMap).getRanking(eq(key), any(Ranking.class)); - } - - private void setSmartActions(String key, ArrayList<Notification.Action> smartActions) { - doAnswer(invocationOnMock -> { - Ranking ranking = (Ranking) - invocationOnMock.getArguments()[1]; - ranking.populate( - key, - 0, - false, - 0, - 0, - IMPORTANCE_DEFAULT, - null, null, - null, null, null, true, - Ranking.USER_SENTIMENT_NEUTRAL, false, -1, - false, smartActions, null, false, false, false, null, 0, false); - return true; - }).when(mRankingMap).getRanking(eq(key), any(Ranking.class)); - } - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mDependency.injectMockDependency(SmartReplyController.class); - - allowTestableLooperAsMainThread(); - mDependency.injectTestDependency(Dependency.MAIN_HANDLER, - Handler.createAsync(TestableLooper.get(this).getLooper())); - - mEntry = createNotification(); - mStats = defaultStats(mEntry); - mSbn = mEntry.getSbn(); - - mEntryManager = new NotificationEntryManager( - mLogger, - mGroupManager, - mNotifPipelineFlags, - () -> mNotificationRowBinder, - () -> mRemoteInputManager, - mLeakDetector, - mStatusBarService, - mock(DumpManager.class), - mBgExecutor - ); - mEntryManager.initialize( - mNotificationListener, - new NotificationRankingManager( - () -> mNotificationMediaManager, - mGroupManager, - mHeadsUpManager, - mock(NotificationFilter.class), - mLogger, - mock(NotificationSectionsFeatureManager.class), - mock(PeopleNotificationIdentifier.class), - mock(HighPriorityProvider.class), - mEnvironment)); - mEntryManager.addNotificationEntryListener(mEntryListener); - mEntryManager.addCollectionListener(mNotifCollectionListener); - mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor); - - setUserSentiment(mSbn.getKey(), Ranking.USER_SENTIMENT_NEUTRAL); - } - - @Test - public void testAddNotification_noDuplicateEntriesCreated() { - // GIVEN a notification has been added - mEntryManager.addNotification(mSbn, mRankingMap); - - // WHEN the same notification is added multiple times before the previous entry (with - // the same key) didn't finish inflating - mEntryManager.addNotification(mSbn, mRankingMap); - mEntryManager.addNotification(mSbn, mRankingMap); - mEntryManager.addNotification(mSbn, mRankingMap); - - // THEN getAllNotifs() only contains exactly one notification with this key - int count = 0; - for (NotificationEntry entry : mEntryManager.getAllNotifs()) { - if (entry.getKey().equals(mSbn.getKey())) { - count++; - } - } - assertEquals("Should only be one entry with key=" + mSbn.getKey() + " in mAllNotifs. " - + "Instead there are " + count, 1, count); - } - - @Test - public void testAddNotification_setsUserSentiment() { - mEntryManager.addNotification(mSbn, mRankingMap); - - ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass( - NotificationEntry.class); - verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture()); - NotificationEntry entry = entryCaptor.getValue(); - - assertEquals(entry.getUserSentiment(), Ranking.USER_SENTIMENT_NEUTRAL); - } - - @Test - public void testUpdateNotification_prePostEntryOrder() throws Exception { - TestableLooper.get(this).processAllMessages(); - - mEntryManager.addActiveNotificationForTest(mEntry); - - mEntryManager.updateNotification(mSbn, mRankingMap); - - // Ensure that update callbacks happen in correct order - InOrder order = inOrder(mEntryListener, mPresenter, mEntryListener); - order.verify(mEntryListener).onPreEntryUpdated(mEntry); - order.verify(mEntryListener).onPostEntryUpdated(mEntry); - } - - @Test - public void testRemoveNotification() { - mEntry.setRow(mRow); - mEntryManager.addActiveNotificationForTest(mEntry); - - mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); - - verify(mEntryListener).onEntryRemoved( - argThat(matchEntryOnKey()), any(), - eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON)); - verify(mRow).setRemoved(); - - assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); - } - - @Test - public void testRemoveUninflatedNotification_removesNotificationFromAllNotifsList() { - // GIVEN an uninflated entry is added - mEntryManager.addNotification(mSbn, mRankingMap); - assertTrue(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey())); - - // WHEN the uninflated entry is removed - mEntryManager.performRemoveNotification(mSbn, mock(DismissedByUserStats.class), - UNDEFINED_DISMISS_REASON); - - // THEN the entry is still removed from the allNotifications list - assertFalse(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey())); - } - - @Test - public void testPerformRemoveNotification_sendRemovalToServer() throws RemoteException { - // GIVEN an entry manager with a notification - mEntryManager.addActiveNotificationForTest(mEntry); - - // GIVEN interceptor that doesn't intercept - when(mRemoveInterceptor.onNotificationRemoveRequested( - eq(mEntry.getKey()), argThat(matchEntryOnKey()), anyInt())) - .thenReturn(false); - - // WHEN the notification entry is removed - mEntryManager.performRemoveNotification(mSbn, mStats, REASON_CANCEL); - - // THEN notification removal is sent to the server - FakeExecutor.exhaustExecutors(mBgExecutor); - verify(mStatusBarService).onNotificationClear( - mSbn.getPackageName(), - mSbn.getUser().getIdentifier(), - mSbn.getKey(), - mStats.dismissalSurface, - mStats.dismissalSentiment, - mStats.notificationVisibility); - verifyNoMoreInteractions(mStatusBarService); - } - - @Test - public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() { - - mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON); - - verify(mEntryListener, never()).onEntryRemoved(argThat(matchEntryOnKey()), any(), - eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON)); - } - - /** Regression test for b/201097913. */ - @Test - public void testRemoveNotification_whilePending_onlyCollectionListenerNotified() { - // Add and then remove a pending entry (entry that hasn't been inflated). - mEntryManager.addNotification(mSbn, mRankingMap); - mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); - - // Verify that only the listener for the NEW pipeline is notified. - // Old pipeline: - verify(mEntryListener, never()).onEntryRemoved( - argThat(matchEntryOnKey()), any(), anyBoolean(), anyInt()); - // New pipeline: - verify(mNotifCollectionListener).onEntryRemoved( - argThat(matchEntryOnKey()), anyInt()); - } - - @Test - public void testUpdateNotificationRanking_noChange() { - when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); - when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); - - mEntry.setRow(mRow); - mEntryManager.addActiveNotificationForTest(mEntry); - setSmartActions(mEntry.getKey(), null); - - mEntryManager.updateNotificationRanking(mRankingMap); - assertThat(mEntry.getSmartActions()).isEmpty(); - } - - @Test - public void testUpdateNotificationRanking_pendingNotification() { - when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); - when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); - - mEntry.setRow(null); - mEntryManager.mPendingNotifications.put(mEntry.getKey(), mEntry); - setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction()))); - - mEntryManager.updateNotificationRanking(mRankingMap); - assertEquals(1, mEntry.getSmartActions().size()); - assertEquals("action", mEntry.getSmartActions().get(0).title); - } - - @Test - public void testUpdatePendingNotification_rankingUpdated() { - // GIVEN a notification with ranking is pending - final Ranking originalRanking = mEntry.getRanking(); - mEntryManager.mPendingNotifications.put(mEntry.getKey(), mEntry); - - // WHEN the same notification has been updated with a new ranking - final int newRank = 2345; - doAnswer(invocationOnMock -> { - Ranking ranking = (Ranking) - invocationOnMock.getArguments()[1]; - ranking.populate( - mEntry.getKey(), - newRank, /* this changed!! */ - false, - 0, - 0, - IMPORTANCE_DEFAULT, - null, null, - null, null, null, true, - Ranking.USER_SENTIMENT_NEUTRAL, false, -1, - false, null, null, false, false, false, null, 0, false); - return true; - }).when(mRankingMap).getRanking(eq(mEntry.getKey()), any(Ranking.class)); - mEntryManager.addNotification(mSbn, mRankingMap); - - // THEN ranking for the entry has been updated with new ranking - assertEquals(newRank, mEntry.getRanking().getRank()); - } - - @Test - public void testNotifyChannelModified_notifiesListeners() { - NotificationChannel channel = mock(NotificationChannel.class); - String pkg = "PKG"; - mEntryManager.notifyChannelModified(pkg, UserHandle.CURRENT, channel, - NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); - verify(mNotifCollectionListener).onNotificationChannelModified(eq(pkg), - eq(UserHandle.CURRENT), eq(channel), eq(NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); - verify(mEntryListener).onNotificationChannelModified(eq(pkg), - eq(UserHandle.CURRENT), eq(channel), eq(NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); - } - - @Test - public void testLifetimeExtenders_ifNotificationIsRetainedItIsntRemoved() { - // GIVEN an entry manager with a notification - mEntryManager.addActiveNotificationForTest(mEntry); - - // GIVEN a lifetime extender that always tries to extend lifetime - NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class); - when(extender.shouldExtendLifetime(mEntry)).thenReturn(true); - mEntryManager.addNotificationLifetimeExtender(extender); - - // WHEN the notification is removed - mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); - - // THEN the extender is asked to manage the lifetime - verify(extender).setShouldManageLifetime(mEntry, true); - // THEN the notification is retained - assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); - verify(mEntryListener, never()).onEntryRemoved( - argThat(matchEntryOnKey()), any(), eq(false), eq(UNDEFINED_DISMISS_REASON)); - } - - @Test - public void testLifetimeExtenders_whenRetentionEndsNotificationIsRemoved() { - // GIVEN an entry manager with a notification whose life has been extended - mEntryManager.addActiveNotificationForTest(mEntry); - final FakeNotificationLifetimeExtender extender = new FakeNotificationLifetimeExtender(); - mEntryManager.addNotificationLifetimeExtender(extender); - mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); - assertTrue(extender.isManaging(mEntry.getKey())); - - // WHEN the extender finishes its extension - extender.setExtendLifetimes(false); - extender.getCallback().onSafeToRemove(mEntry.getKey()); - - // THEN the notification is removed - assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); - verify(mEntryListener).onEntryRemoved( - argThat(matchEntryOnKey()), any(), eq(false), eq(UNDEFINED_DISMISS_REASON)); - } - - @Test - public void testLifetimeExtenders_whenNotificationUpdatedRetainersAreCanceled() { - // GIVEN an entry manager with a notification whose life has been extended - mEntryManager.addActiveNotificationForTest(mEntry); - NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class); - when(extender.shouldExtendLifetime(mEntry)).thenReturn(true); - mEntryManager.addNotificationLifetimeExtender(extender); - mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); - - // WHEN the notification is updated - mEntryManager.updateNotification(mEntry.getSbn(), mRankingMap); - - // THEN the lifetime extension is canceled - verify(extender).setShouldManageLifetime(mEntry, false); - } - - @Test - public void testLifetimeExtenders_whenNewExtenderTakesPrecedenceOldExtenderIsCanceled() { - // GIVEN an entry manager with a notification - mEntryManager.addActiveNotificationForTest(mEntry); - - // GIVEN two lifetime extenders, the first which never extends and the second which - // always extends - NotificationLifetimeExtender extender1 = mock(NotificationLifetimeExtender.class); - when(extender1.shouldExtendLifetime(mEntry)).thenReturn(false); - NotificationLifetimeExtender extender2 = mock(NotificationLifetimeExtender.class); - when(extender2.shouldExtendLifetime(mEntry)).thenReturn(true); - mEntryManager.addNotificationLifetimeExtender(extender1); - mEntryManager.addNotificationLifetimeExtender(extender2); - - // GIVEN a notification was lifetime-extended and extender2 is managing it - mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); - verify(extender1, never()).setShouldManageLifetime(mEntry, true); - verify(extender2).setShouldManageLifetime(mEntry, true); - - // WHEN the extender1 changes its mind and wants to extend the lifetime of the notif - when(extender1.shouldExtendLifetime(mEntry)).thenReturn(true); - mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); - - // THEN extender2 stops managing the notif and extender1 starts managing it - verify(extender1).setShouldManageLifetime(mEntry, true); - verify(extender2).setShouldManageLifetime(mEntry, false); - } - - /** - * Ensure that calling NotificationEntryManager.performRemoveNotification() doesn't crash when - * given a notification that has already been removed from NotificationData. - */ - @Test - public void testPerformRemoveNotification_removedEntry() { - mEntryManager.removeNotification(mSbn.getKey(), null, 0); - mEntryManager.performRemoveNotification(mSbn, mock(DismissedByUserStats.class), - REASON_CANCEL); - } - - @Test - public void testRemoveInterceptor_interceptsDontGetRemoved() throws InterruptedException { - // GIVEN an entry manager with a notification - mEntryManager.addActiveNotificationForTest(mEntry); - - // GIVEN interceptor that intercepts that entry - when(mRemoveInterceptor.onNotificationRemoveRequested( - eq(mEntry.getKey()), argThat(matchEntryOnKey()), anyInt())) - .thenReturn(true); - - // WHEN the notification is removed - mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); - - // THEN the interceptor intercepts & the entry is not removed & no listeners are called - assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); - verify(mEntryListener, never()).onEntryRemoved(argThat(matchEntryOnKey()), - any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON)); - } - - @Test - public void testRemoveInterceptor_notInterceptedGetsRemoved() { - // GIVEN an entry manager with a notification - mEntryManager.addActiveNotificationForTest(mEntry); - - // GIVEN interceptor that doesn't intercept - when(mRemoveInterceptor.onNotificationRemoveRequested( - eq(mEntry.getKey()), argThat(matchEntryOnKey()), anyInt())) - .thenReturn(false); - - // WHEN the notification is removed - mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); - - // THEN the interceptor intercepts & the entry is not removed & no listeners are called - assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); - verify(mEntryListener, atLeastOnce()).onEntryRemoved(argThat(matchEntryOnKey()), - any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON)); - } - - /* Tests annexed from NotificationDataTest go here */ - - @Test - public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications() { - Notification.Builder n = new Notification.Builder(mContext, "di") - .setSmallIcon(R.drawable.ic_person) - .setContentTitle("Title") - .setContentText("Text"); - - NotificationEntry e2 = new NotificationEntryBuilder() - .setPkg(TEST_PACKAGE_NAME) - .setOpPkg(TEST_PACKAGE_NAME) - .setUid(TEST_UID) - .setId(mId++) - .setNotification(n.build()) - .setUser(new UserHandle(ActivityManager.getCurrentUser())) - .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT)) - .build(); - - mEntryManager.addActiveNotificationForTest(mEntry); - mEntryManager.addActiveNotificationForTest(e2); - - when(mEnvironment.isNotificationForCurrentProfiles(mEntry.getSbn())).thenReturn(false); - when(mEnvironment.isNotificationForCurrentProfiles(e2.getSbn())).thenReturn(true); - - List<NotificationEntry> result = mEntryManager.getActiveNotificationsForCurrentUser(); - assertEquals(result.size(), 1); - junit.framework.Assert.assertEquals(result.get(0), e2); - } - - /* End annex */ - - private boolean entriesContainKey(Collection<NotificationEntry> entries, String key) { - for (NotificationEntry entry : entries) { - if (entry.getSbn().getKey().equals(key)) { - return true; - } - } - return false; - } - - private Notification.Action createAction() { - return new Notification.Action.Builder( - Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon), - "action", - PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), - PendingIntent.FLAG_IMMUTABLE)).build(); - } - - private ArgumentMatcher<NotificationEntry> matchEntryOnKey() { - return e -> e.getKey().equals(mEntry.getKey()); - } - - private static class FakeNotificationLifetimeExtender implements NotificationLifetimeExtender { - private NotificationSafeToRemoveCallback mCallback; - private boolean mExtendLifetimes = true; - private Set<String> mManagedNotifs = new ArraySet<>(); - - @Override - public void setCallback(@NonNull NotificationSafeToRemoveCallback callback) { - mCallback = callback; - } - - @Override - public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) { - return mExtendLifetimes; - } - - @Override - public void setShouldManageLifetime( - @NonNull NotificationEntry entry, - boolean shouldManage) { - final boolean hasEntry = mManagedNotifs.contains(entry.getKey()); - if (shouldManage) { - if (hasEntry) { - throw new RuntimeException("Already managing this entry: " + entry.getKey()); - } - mManagedNotifs.add(entry.getKey()); - } else { - if (!hasEntry) { - throw new RuntimeException("Not managing this entry: " + entry.getKey()); - } - mManagedNotifs.remove(entry.getKey()); - } - } - - public void setExtendLifetimes(boolean extendLifetimes) { - mExtendLifetimes = extendLifetimes; - } - - public NotificationSafeToRemoveCallback getCallback() { - return mCallback; - } - - public boolean isManaging(String notificationKey) { - return mManagedNotifs.contains(notificationKey); - } - } - - private NotificationEntry createNotification() { - Notification.Builder n = new Notification.Builder(mContext, "id") - .setSmallIcon(R.drawable.ic_person) - .setContentTitle("Title") - .setContentText("Text"); - - return new NotificationEntryBuilder() - .setPkg(TEST_PACKAGE_NAME) - .setOpPkg(TEST_PACKAGE_NAME) - .setUid(TEST_UID) - .setId(mId++) - .setNotification(n.build()) - .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT)) - .setUser(new UserHandle(ActivityManager.getCurrentUser())) - .build(); - } - - private static DismissedByUserStats defaultStats(NotificationEntry entry) { - return new DismissedByUserStats( - DISMISSAL_SHADE, - DISMISS_SENTIMENT_NEUTRAL, - NotificationVisibility.obtain(entry.getKey(), 7, 2, true)); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java deleted file mode 100644 index 2cacaf78479d..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -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.when; - -import android.Manifest; -import android.app.Notification; -import android.app.Notification.MediaStyle; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.media.session.MediaSession; -import android.os.Bundle; -import android.service.notification.StatusBarNotification; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.testing.TestableLooper.RunWithLooper; - -import androidx.annotation.NonNull; -import androidx.test.annotation.UiThreadTest; -import androidx.test.filters.SmallTest; - -import com.android.systemui.ForegroundServiceController; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.dump.DumpManager; -import com.android.systemui.media.MediaFeatureFlag; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shade.ShadeController; -import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; -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.provider.DebugModeFilterProvider; -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.NotificationTestHelper; -import com.android.wm.shell.bubbles.Bubbles; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.Optional; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@RunWithLooper -public class NotificationFilterTest extends SysuiTestCase { - - private static final int UID_NORMAL = 123; - private static final int UID_ALLOW_DURING_SETUP = 456; - private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey"; - - private final StatusBarNotification mMockStatusBarNotification = - mock(StatusBarNotification.class); - - @Mock - DebugModeFilterProvider mDebugModeFilterProvider; - @Mock - StatusBarStateController mStatusBarStateController; - @Mock - KeyguardEnvironment mEnvironment; - @Mock - ForegroundServiceController mFsc; - @Mock - NotificationLockscreenUserManager mUserManager; - @Mock - MediaFeatureFlag mMediaFeatureFlag; - - private final IPackageManager mMockPackageManager = mock(IPackageManager.class); - - private NotificationFilter mNotificationFilter; - private ExpandableNotificationRow mRow; - private NotificationEntry mMediaEntry; - private MediaSession mMediaSession; - - @Before - public void setUp() throws Exception { - allowTestableLooperAsMainThread(); - MockitoAnnotations.initMocks(this); - when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL); - - mMediaSession = new MediaSession(mContext, "TEST_MEDIA_SESSION"); - NotificationEntryBuilder builder = new NotificationEntryBuilder(); - builder.modifyNotification(mContext).setStyle( - new MediaStyle().setMediaSession(mMediaSession.getSessionToken())); - mMediaEntry = builder.build(); - - when(mMockPackageManager.checkUidPermission( - eq(Manifest.permission.NOTIFICATION_DURING_SETUP), - eq(UID_NORMAL))) - .thenReturn(PackageManager.PERMISSION_DENIED); - when(mMockPackageManager.checkUidPermission( - eq(Manifest.permission.NOTIFICATION_DURING_SETUP), - eq(UID_ALLOW_DURING_SETUP))) - .thenReturn(PackageManager.PERMISSION_GRANTED); - mDependency.injectTestDependency(ForegroundServiceController.class, mFsc); - mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, - new NotificationGroupManagerLegacy( - mock(StatusBarStateController.class), - () -> mock(PeopleNotificationIdentifier.class), - Optional.of(mock(Bubbles.class)), - mock(DumpManager.class))); - mDependency.injectMockDependency(ShadeController.class); - mDependency.injectMockDependency(NotificationLockscreenUserManager.class); - mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment); - when(mEnvironment.isDeviceProvisioned()).thenReturn(true); - when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); - NotificationTestHelper testHelper = new NotificationTestHelper( - mContext, - mDependency, - TestableLooper.get(this)); - mRow = testHelper.createRow(); - mNotificationFilter = newNotificationFilter(); - } - - @NonNull - private NotificationFilter newNotificationFilter() { - return new NotificationFilter( - mDebugModeFilterProvider, - mStatusBarStateController, - mEnvironment, - mFsc, - mUserManager, - mMediaFeatureFlag); - } - - @After - public void tearDown() { - mMediaSession.release(); - } - - @Test - @UiThreadTest - public void testShowNotificationEvenIfUnprovisioned_FalseIfNoExtra() { - initStatusBarNotification(false); - when(mMockStatusBarNotification.getUid()).thenReturn(UID_ALLOW_DURING_SETUP); - - assertFalse( - NotificationFilter.showNotificationEvenIfUnprovisioned( - mMockPackageManager, - mMockStatusBarNotification)); - } - - @Test - @UiThreadTest - public void testShowNotificationEvenIfUnprovisioned_FalseIfNoPermission() { - initStatusBarNotification(true); - - assertFalse( - NotificationFilter.showNotificationEvenIfUnprovisioned( - mMockPackageManager, - mMockStatusBarNotification)); - } - - @Test - @UiThreadTest - public void testShowNotificationEvenIfUnprovisioned_TrueIfHasPermissionAndExtra() { - initStatusBarNotification(true); - when(mMockStatusBarNotification.getUid()).thenReturn(UID_ALLOW_DURING_SETUP); - - assertTrue( - NotificationFilter.showNotificationEvenIfUnprovisioned( - mMockPackageManager, - mMockStatusBarNotification)); - } - - @Test - public void testShouldFilterHiddenNotifications() { - initStatusBarNotification(false); - // setup - when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false); - - // test should filter out hidden notifications: - // hidden - NotificationEntry entry = new NotificationEntryBuilder() - .setSuspended(true) - .build(); - - assertTrue(mNotificationFilter.shouldFilterOut(entry)); - - // not hidden - entry = new NotificationEntryBuilder() - .setSuspended(false) - .build(); - assertFalse(mNotificationFilter.shouldFilterOut(entry)); - } - - @Test - public void shouldFilterOtherNotificationWhenDisabled() { - // GIVEN that the media feature is disabled - when(mMediaFeatureFlag.getEnabled()).thenReturn(false); - NotificationFilter filter = newNotificationFilter(); - // WHEN the media filter is asked about an entry - NotificationEntry otherEntry = new NotificationEntryBuilder().build(); - final boolean shouldFilter = filter.shouldFilterOut(otherEntry); - // THEN it shouldn't be filtered - assertFalse(shouldFilter); - } - - @Test - public void shouldFilterOtherNotificationWhenEnabled() { - // GIVEN that the media feature is enabled - when(mMediaFeatureFlag.getEnabled()).thenReturn(true); - NotificationFilter filter = newNotificationFilter(); - // WHEN the media filter is asked about an entry - NotificationEntry otherEntry = new NotificationEntryBuilder().build(); - final boolean shouldFilter = filter.shouldFilterOut(otherEntry); - // THEN it shouldn't be filtered - assertFalse(shouldFilter); - } - - @Test - public void shouldFilterMediaNotificationWhenDisabled() { - // GIVEN that the media feature is disabled - when(mMediaFeatureFlag.getEnabled()).thenReturn(false); - NotificationFilter filter = newNotificationFilter(); - // WHEN the media filter is asked about a media entry - final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry); - // THEN it shouldn't be filtered - assertFalse(shouldFilter); - } - - @Test - public void shouldFilterMediaNotificationWhenEnabled() { - // GIVEN that the media feature is enabled - when(mMediaFeatureFlag.getEnabled()).thenReturn(true); - NotificationFilter filter = newNotificationFilter(); - // WHEN the media filter is asked about a media entry - final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry); - // THEN it should be filtered - assertTrue(shouldFilter); - } - - private void initStatusBarNotification(boolean allowDuringSetup) { - Bundle bundle = new Bundle(); - bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup); - Notification notification = new Notification.Builder(mContext, "test") - .addExtras(bundle) - .build(); - when(mMockStatusBarNotification.getNotification()).thenReturn(notification); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java deleted file mode 100644 index 58abbf2ddef7..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.notification; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -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.os.Handler; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.dump.DumpManager; -import com.android.systemui.keyguard.WakefulnessLifecycle; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -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.provider.VisualStabilityProvider; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper() -public class VisualStabilityManagerTest extends SysuiTestCase { - - private TestableLooper mTestableLooper; - - private VisualStabilityManager mVisualStabilityManager; - private VisualStabilityProvider mVisualStabilityProvider = mock(VisualStabilityProvider.class); - private VisualStabilityManager.Callback mCallback = mock(VisualStabilityManager.Callback.class); - private VisibilityLocationProvider mLocationProvider = mock(VisibilityLocationProvider.class); - private ExpandableNotificationRow mRow = mock(ExpandableNotificationRow.class); - private NotificationEntry mEntry; - - private StatusBarStateController.StateListener mStatusBarStateListener; - private WakefulnessLifecycle.Observer mWakefulnessObserver; - - @Before - public void setUp() { - StatusBarStateController statusBarStateController = mock(StatusBarStateController.class); - WakefulnessLifecycle wakefulnessLifecycle = mock(WakefulnessLifecycle.class); - - mTestableLooper = TestableLooper.get(this); - mVisualStabilityManager = new VisualStabilityManager( - mock(NotificationEntryManager.class), - mVisualStabilityProvider, - new Handler(mTestableLooper.getLooper()), - statusBarStateController, - wakefulnessLifecycle, - mock(DumpManager.class)); - - mVisualStabilityManager.setVisibilityLocationProvider(mLocationProvider); - mEntry = new NotificationEntryBuilder().build(); - mEntry.setRow(mRow); - - when(mRow.getEntry()).thenReturn(mEntry); - - ArgumentCaptor<StatusBarStateController.StateListener> stateListenerCaptor = - ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); - verify(statusBarStateController).addCallback(stateListenerCaptor.capture()); - mStatusBarStateListener = stateListenerCaptor.getValue(); - - ArgumentCaptor<WakefulnessLifecycle.Observer> wakefulnessObserverCaptor = - ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class); - verify(wakefulnessLifecycle).addObserver(wakefulnessObserverCaptor.capture()); - mWakefulnessObserver = wakefulnessObserverCaptor.getValue(); - } - - @Test - public void testPanelExpansion() { - setPanelExpanded(true); - setScreenOn(true); - assertFalse(mVisualStabilityManager.canReorderNotification(mRow)); - setPanelExpanded(false); - assertTrue(mVisualStabilityManager.canReorderNotification(mRow)); - } - - @Test - public void testScreenOn() { - setPanelExpanded(true); - setScreenOn(true); - assertFalse(mVisualStabilityManager.canReorderNotification(mRow)); - setScreenOn(false); - assertTrue(mVisualStabilityManager.canReorderNotification(mRow)); - } - - @Test - public void testReorderingAllowedChangesScreenOn() { - setPanelExpanded(true); - setScreenOn(true); - assertFalse(mVisualStabilityManager.isReorderingAllowed()); - setScreenOn(false); - assertTrue(mVisualStabilityManager.isReorderingAllowed()); - } - - @Test - public void testReorderingAllowedChangesPanel() { - setPanelExpanded(true); - setScreenOn(true); - assertFalse(mVisualStabilityManager.isReorderingAllowed()); - setPanelExpanded(false); - assertTrue(mVisualStabilityManager.isReorderingAllowed()); - } - - @Test - public void testCallBackCalledScreenOn() { - setPanelExpanded(true); - setScreenOn(true); - mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */); - setScreenOn(false); - verify(mCallback).onChangeAllowed(); - } - - @Test - public void testCallBackCalledPanelExpanded() { - setPanelExpanded(true); - setScreenOn(true); - mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */); - setPanelExpanded(false); - verify(mCallback).onChangeAllowed(); - } - - @Test - public void testCallBackExactlyOnce() { - setPanelExpanded(true); - setScreenOn(true); - mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */); - setScreenOn(false); - setScreenOn(true); - setScreenOn(false); - verify(mCallback).onChangeAllowed(); - } - - @Test - public void testCallBackCalledContinuouslyWhenRequested() { - setPanelExpanded(true); - setScreenOn(true); - mVisualStabilityManager.addReorderingAllowedCallback(mCallback, true /* persistent */); - setScreenOn(false); - setScreenOn(true); - setScreenOn(false); - verify(mCallback, times(2)).onChangeAllowed(); - } - - @Test - public void testAddedCanReorder() { - setPanelExpanded(true); - setScreenOn(true); - mVisualStabilityManager.notifyViewAddition(mRow); - assertTrue(mVisualStabilityManager.canReorderNotification(mRow)); - } - - @Test - public void testReorderingVisibleHeadsUpNotAllowed() { - setPanelExpanded(true); - setScreenOn(true); - when(mLocationProvider.isInVisibleLocation(any(NotificationEntry.class))).thenReturn(true); - mVisualStabilityManager.onHeadsUpStateChanged(mEntry, true); - assertFalse(mVisualStabilityManager.canReorderNotification(mRow)); - } - - @Test - public void testReorderingVisibleHeadsUpAllowed() { - setPanelExpanded(true); - setScreenOn(true); - when(mLocationProvider.isInVisibleLocation(any(NotificationEntry.class))).thenReturn(false); - mVisualStabilityManager.onHeadsUpStateChanged(mEntry, true); - assertTrue(mVisualStabilityManager.canReorderNotification(mRow)); - } - - @Test - public void testReorderingVisibleHeadsUpAllowedOnce() { - setPanelExpanded(true); - setScreenOn(true); - when(mLocationProvider.isInVisibleLocation(any(NotificationEntry.class))).thenReturn(false); - mVisualStabilityManager.onHeadsUpStateChanged(mEntry, true); - mVisualStabilityManager.onReorderingFinished(); - assertFalse(mVisualStabilityManager.canReorderNotification(mRow)); - } - - @Test - public void testPulsing() { - setPulsing(true); - assertFalse(mVisualStabilityManager.canReorderNotification(mRow)); - setPulsing(false); - assertTrue(mVisualStabilityManager.canReorderNotification(mRow)); - } - - @Test - public void testReorderingAllowedChanges_Pulsing() { - setPulsing(true); - assertFalse(mVisualStabilityManager.isReorderingAllowed()); - setPulsing(false); - assertTrue(mVisualStabilityManager.isReorderingAllowed()); - } - - @Test - public void testCallBackCalled_Pulsing() { - setPulsing(true); - mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */); - setPulsing(false); - verify(mCallback).onChangeAllowed(); - } - - @Test - public void testTemporarilyAllowReorderingNotifiesCallbacks() { - // GIVEN having the panel open (which would block reordering) - setScreenOn(true); - setPanelExpanded(true); - mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */); - - // WHEN we temprarily allow reordering - mVisualStabilityManager.temporarilyAllowReordering(); - - // THEN callbacks are notified that reordering is allowed - verify(mCallback).onChangeAllowed(); - assertTrue(mVisualStabilityManager.isReorderingAllowed()); - } - - @Test - public void testTemporarilyAllowReorderingDoesntOverridePulsing() { - // GIVEN we are in a pulsing state - setPulsing(true); - mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */); - - // WHEN we temprarily allow reordering - mVisualStabilityManager.temporarilyAllowReordering(); - - // THEN reordering is still not allowed - verify(mCallback, never()).onChangeAllowed(); - assertFalse(mVisualStabilityManager.isReorderingAllowed()); - } - - @Test - public void testTemporarilyAllowReorderingExpires() { - // GIVEN having the panel open (which would block reordering) - setScreenOn(true); - setPanelExpanded(true); - mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false /* persistent */); - - // WHEN we temprarily allow reordering and then wait until the window expires - mVisualStabilityManager.temporarilyAllowReordering(); - assertTrue(mVisualStabilityManager.isReorderingAllowed()); - mTestableLooper.processMessages(1); - - // THEN reordering is no longer allowed - assertFalse(mVisualStabilityManager.isReorderingAllowed()); - } - - private void setPanelExpanded(boolean expanded) { - mStatusBarStateListener.onExpandedChanged(expanded); - } - - private void setPulsing(boolean pulsing) { - mStatusBarStateListener.onPulsingChanged(pulsing); - } - - private void setScreenOn(boolean screenOn) { - if (screenOn) { - mWakefulnessObserver.onStartedWakingUp(); - } else { - mWakefulnessObserver.onFinishedGoingToSleep(); - } - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt deleted file mode 100644 index c51c628c5457..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification.collection - -import android.app.Notification -import android.app.NotificationChannel -import android.app.NotificationManager.IMPORTANCE_DEFAULT -import android.app.NotificationManager.IMPORTANCE_HIGH -import android.app.NotificationManager.IMPORTANCE_LOW -import android.app.PendingIntent -import android.app.Person -import android.os.SystemClock -import android.service.notification.NotificationListenerService.RankingMap -import android.testing.AndroidTestingRunner -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking -import com.android.systemui.statusbar.NotificationMediaManager -import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment -import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger -import com.android.systemui.statusbar.notification.NotificationFilter -import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager -import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy -import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow -import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING -import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE -import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT -import com.android.systemui.statusbar.policy.HeadsUpManager -import com.google.common.truth.Truth.assertThat -import dagger.Lazy -import junit.framework.Assert.assertEquals -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mockito.mock -import org.mockito.Mockito.`when` as whenever - -@SmallTest -@RunWith(AndroidTestingRunner::class) -class NotificationRankingManagerTest : SysuiTestCase() { - - private val lazyMedia: Lazy<NotificationMediaManager> = Lazy { - mock(NotificationMediaManager::class.java) - } - private lateinit var personNotificationIdentifier: PeopleNotificationIdentifier - private lateinit var rankingManager: TestableNotificationRankingManager - private lateinit var sectionsManager: NotificationSectionsFeatureManager - private lateinit var notificationFilter: NotificationFilter - - @Before - fun setup() { - personNotificationIdentifier = - mock(PeopleNotificationIdentifier::class.java) - sectionsManager = mock(NotificationSectionsFeatureManager::class.java) - notificationFilter = mock(NotificationFilter::class.java) - rankingManager = TestableNotificationRankingManager( - lazyMedia, - mock(NotificationGroupManagerLegacy::class.java), - mock(HeadsUpManager::class.java), - notificationFilter, - mock(NotificationEntryManagerLogger::class.java), - sectionsManager, - personNotificationIdentifier, - HighPriorityProvider( - personNotificationIdentifier, - mock(NotificationGroupManagerLegacy::class.java)), - mock(KeyguardEnvironment::class.java) - ) - } - - @Test - fun testSort_highPriorityTrumpsNMSRank() { - // NMS rank says A and then B. But A is not high priority and B is, so B should sort in - // front - val a = NotificationEntryBuilder() - .setImportance(IMPORTANCE_LOW) // low priority - .setRank(1) // NMS says rank first - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification( - Notification.Builder(mContext, "test") - .build()) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build() - - val b = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) // high priority - .setRank(2) // NMS says rank second - .setPkg("pkg2") - .setOpPkg("pkg2") - .setTag("tag") - .setNotification( - Notification.Builder(mContext, "test") - .build()) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build() - - assertEquals( - listOf(b, a), - rankingManager.updateRanking(null, listOf(a, b), "test")) - } - - @Test - fun testSort_samePriorityUsesNMSRank() { - // NMS rank says A and then B, and they are the same priority so use that rank - val aN = Notification.Builder(mContext, "test") - .setStyle(Notification.MessagingStyle("")) - .build() - val a = NotificationEntryBuilder() - .setRank(1) - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(aN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build() - - val bN = Notification.Builder(mContext, "test") - .setStyle(Notification.MessagingStyle("")) - .build() - val b = NotificationEntryBuilder() - .setRank(2) - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg2") - .setOpPkg("pkg2") - .setTag("tag") - .setNotification(bN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build() - - assertEquals( - listOf(a, b), - rankingManager.updateRanking(null, listOf(a, b), "test")) - } - - @Test - fun testSort_headsUp_trumpsPeople() { - whenever(sectionsManager.isFilteringEnabled()).thenReturn(true) - val aN = Notification.Builder(mContext, "test") - .setStyle(Notification.MessagingStyle("")) - .build() - val a = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(aN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build() - - whenever(personNotificationIdentifier.getPeopleNotificationType(a)) - .thenReturn(TYPE_IMPORTANT_PERSON) - - val bN = Notification.Builder(mContext, "test") - .setStyle(Notification.MessagingStyle("")) - .build() - val b = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg2") - .setOpPkg("pkg2") - .setTag("tag") - .setNotification(bN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build() - b.row = mock(ExpandableNotificationRow::class.java).also { - whenever(it.isHeadsUp).thenReturn(true) - } - - whenever(personNotificationIdentifier.getPeopleNotificationType(a)) - .thenReturn(TYPE_PERSON) - - assertEquals(listOf(b, a), rankingManager.updateRanking(null, listOf(a, b), "test")) - } - - @Test - fun testSort_importantPeople() { - whenever(sectionsManager.isFilteringEnabled()).thenReturn(true) - val aN = Notification.Builder(mContext, "test") - .setStyle(Notification.MessagingStyle("")) - .build() - val a = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(aN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.user) - .setOverrideGroupKey("") - .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(a)) - .thenReturn(TYPE_PERSON) - - val bN = Notification.Builder(mContext, "test") - .setStyle(Notification.MessagingStyle("")) - .build() - val b = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg2") - .setOpPkg("pkg2") - .setTag("tag") - .setNotification(bN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.user) - .setOverrideGroupKey("") - .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(b)) - .thenReturn(TYPE_IMPORTANT_PERSON) - - whenever(personNotificationIdentifier.compareTo(TYPE_PERSON, TYPE_IMPORTANT_PERSON)) - .thenReturn(TYPE_IMPORTANT_PERSON.compareTo(TYPE_PERSON)) - whenever(personNotificationIdentifier.compareTo(TYPE_IMPORTANT_PERSON, TYPE_PERSON)) - .thenReturn(TYPE_PERSON.compareTo(TYPE_IMPORTANT_PERSON)) - - assertEquals( - listOf(b, a), - rankingManager.updateRanking(null, listOf(a, b), "test")) - } - - @Test - fun testSort_fullPeople() { - whenever(sectionsManager.isFilteringEnabled()).thenReturn(true) - val aN = Notification.Builder(mContext, "test") - .setStyle(Notification.MessagingStyle("")) - .build() - val a = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(aN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.user) - .setOverrideGroupKey("") - .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(a)) - .thenReturn(TYPE_PERSON) - - val bN = Notification.Builder(mContext, "test") - .setStyle(Notification.MessagingStyle("")) - .build() - val b = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg2") - .setOpPkg("pkg2") - .setTag("tag") - .setNotification(bN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.user) - .setOverrideGroupKey("") - .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(b)) - .thenReturn(TYPE_FULL_PERSON) - - whenever(personNotificationIdentifier.compareTo(TYPE_PERSON, TYPE_FULL_PERSON)) - .thenReturn(TYPE_FULL_PERSON.compareTo(TYPE_PERSON)) - whenever(personNotificationIdentifier.compareTo(TYPE_FULL_PERSON, TYPE_PERSON)) - .thenReturn(TYPE_PERSON.compareTo(TYPE_FULL_PERSON)) - - assertEquals( - listOf(b, a), - rankingManager.updateRanking(null, listOf(a, b), "test")) - } - - @Test - fun testSort_properlySetsAlertingBucket() { - val notif = Notification.Builder(mContext, "test") .build() - - val e = NotificationEntryBuilder() - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(notif) - .setUser(mContext.user) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setOverrideGroupKey("") - .build() - - modifyRanking(e).setImportance(IMPORTANCE_DEFAULT).build() - - rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test") - assertEquals(e.bucket, BUCKET_ALERTING) - } - - @Test - fun testSort_properlySetsSilentBucket() { - val notif = Notification.Builder(mContext, "test") .build() - - val e = NotificationEntryBuilder() - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(notif) - .setUser(mContext.user) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setOverrideGroupKey("") - .build() - - modifyRanking(e).setImportance(IMPORTANCE_LOW).build() - - rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test") - assertEquals(e.bucket, BUCKET_SILENT) - } - - @Test - fun testFilter_resetsInitalizationTime() { - // GIVEN an entry that was initialized 1 second ago - val notif = Notification.Builder(mContext, "test") .build() - - val e = NotificationEntryBuilder() - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(notif) - .setUser(mContext.user) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setOverrideGroupKey("") - .build() - - e.setInitializationTime(SystemClock.elapsedRealtime() - 1000) - assertEquals(true, e.hasFinishedInitialization()) - - // WHEN we update ranking and filter out the notification entry - whenever(notificationFilter.shouldFilterOut(e)).thenReturn(true) - rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test") - - // THEN the initialization time for the entry is reset - assertEquals(false, e.hasFinishedInitialization()) - } - - @Test - fun testSort_colorizedForegroundService() { - whenever(sectionsManager.isFilteringEnabled()).thenReturn(true) - - val a = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification( - Notification.Builder(mContext, "test") - .build()) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build() - - val b = NotificationEntryBuilder() - .setImportance(IMPORTANCE_DEFAULT) // high priority - .setPkg("pkg2") - .setOpPkg("pkg2") - .setTag("tag") - .setNotification(mock(Notification::class.java).also { notif -> - whenever(notif.isForegroundService).thenReturn(true) - whenever(notif.isColorized).thenReturn(true) - }) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build() - - val cN = Notification.Builder(mContext, "test") - .setStyle(Notification.MessagingStyle("")) - .build() - val c = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(cN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.user) - .setOverrideGroupKey("") - .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(a)) - .thenReturn(TYPE_IMPORTANT_PERSON) - - assertThat(rankingManager.updateRanking(null, listOf(a, b, c), "test")) - .containsExactly(b, c, a) - assertThat(b.bucket).isEqualTo(BUCKET_FOREGROUND_SERVICE) - } - - @Test - fun testSort_importantCall() { - whenever(sectionsManager.isFilteringEnabled()).thenReturn(true) - - val a = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification( - Notification.Builder(mContext, "test") - .build()) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build() - - val b = NotificationEntryBuilder() - .setImportance(IMPORTANCE_DEFAULT) // high priority - .setPkg("pkg2") - .setOpPkg("pkg2") - .setTag("tag") - .setNotification(mock(Notification::class.java).also { notif -> - whenever(notif.isForegroundService).thenReturn(true) - whenever(notif.isColorized).thenReturn(true) - }) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.getUser()) - .setOverrideGroupKey("") - .build() - - val cN = Notification.Builder(mContext, "test") - .setStyle(Notification.MessagingStyle("")) - .build() - val c = NotificationEntryBuilder() - .setImportance(IMPORTANCE_HIGH) - .setPkg("pkg") - .setOpPkg("pkg") - .setTag("tag") - .setNotification(cN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.user) - .setOverrideGroupKey("") - .build() - - val dN = Notification.Builder(mContext, "test") - .setStyle(Notification.CallStyle.forOngoingCall( - Person.Builder().setName("caller").build(), - mock(PendingIntent::class.java))) - .build() - val d = NotificationEntryBuilder() - .setImportance(IMPORTANCE_DEFAULT) // high priority - .setPkg("pkg2") - .setOpPkg("pkg2") - .setTag("tag") - .setNotification(dN) - .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) - .setUser(mContext.user) - .setOverrideGroupKey("") - .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(a)) - .thenReturn(TYPE_IMPORTANT_PERSON) - - assertThat(rankingManager.updateRanking(null, listOf(a, b, c, d), "test")) - .containsExactly(b, d, c, a) - assertThat(d.bucket).isEqualTo(BUCKET_FOREGROUND_SERVICE) - } - - internal class TestableNotificationRankingManager( - mediaManager: Lazy<NotificationMediaManager>, - groupManager: NotificationGroupManagerLegacy, - headsUpManager: HeadsUpManager, - filter: NotificationFilter, - logger: NotificationEntryManagerLogger, - sectionsFeatureManager: NotificationSectionsFeatureManager, - peopleNotificationIdentifier: PeopleNotificationIdentifier, - highPriorityProvider: HighPriorityProvider, - keyguardEnvironment: KeyguardEnvironment - ) : NotificationRankingManager( - mediaManager, - groupManager, - headsUpManager, - filter, - logger, - sectionsFeatureManager, - peopleNotificationIdentifier, - highPriorityProvider, - keyguardEnvironment - ) { - fun applyTestRankingMap(r: RankingMap) { - rankingMap = r - } - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java index e00e20f0e46b..46f630b7db63 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java @@ -33,9 +33,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -57,7 +55,6 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotifPipelineFlags; -import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.policy.BatteryController; @@ -85,8 +82,6 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { @Mock AmbientDisplayConfiguration mAmbientDisplayConfiguration; @Mock - NotificationFilter mNotificationFilter; - @Mock StatusBarStateController mStatusBarStateController; @Mock KeyguardStateController mKeyguardStateController; @@ -131,20 +126,10 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { /** * Sets up the state such that any requests to - * {@link NotificationInterruptStateProviderImpl#canAlertCommon(NotificationEntry)} will - * pass as long its provided NotificationEntry fulfills group suppression check. - */ - private void ensureStateForAlertCommon() { - when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false); - } - - /** - * Sets up the state such that any requests to * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will * pass as long its provided NotificationEntry fulfills importance & DND checks. */ private void ensureStateForHeadsUpWhenAwake() throws RemoteException { - ensureStateForAlertCommon(); when(mHeadsUpManager.isSnoozed(any())).thenReturn(false); when(mStatusBarStateController.isDozing()).thenReturn(false); @@ -158,21 +143,10 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { * pass as long its provided NotificationEntry fulfills importance & DND checks. */ private void ensureStateForHeadsUpWhenDozing() { - ensureStateForAlertCommon(); - when(mStatusBarStateController.isDozing()).thenReturn(true); when(mAmbientDisplayConfiguration.pulseOnNotificationEnabled(anyInt())).thenReturn(true); } - /** - * Sets up the state such that any requests to - * {@link NotificationInterruptStateProviderImpl#shouldBubbleUp(NotificationEntry)} will - * pass as long its provided NotificationEntry fulfills importance & bubble checks. - */ - private void ensureStateForBubbleUp() { - ensureStateForAlertCommon(); - } - @Test public void testDefaultSuppressorDoesNotSuppress() { // GIVEN a suppressor without any overrides @@ -201,27 +175,6 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { } @Test - public void testShouldNotHeadsUpAwake_flteredOut() throws RemoteException { - // GIVEN state for "heads up when awake" is true - ensureStateForHeadsUpWhenAwake(); - - // WHEN this entry should be filtered out - NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); - when(mNotificationFilter.shouldFilterOut(entry)).thenReturn(true); - - // THEN we shouldn't heads up this entry - assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); - } - - @Test - public void testDoNotRunFilterOnNewPipeline() { - // WHEN this entry should be filtered out - NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); - mNotifInterruptionStateProvider.shouldHeadsUp(entry); - verify(mNotificationFilter, times(0)).shouldFilterOut(eq(entry)); - } - - @Test public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException { // GIVEN state for "heads up when awake" is true ensureStateForHeadsUpWhenAwake(); @@ -654,7 +607,6 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { */ @Test public void testShouldBubbleUp() { - ensureStateForBubbleUp(); assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isTrue(); } @@ -664,7 +616,6 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { */ @Test public void testShouldBubbleUp_notifInGroupWithOnlySummaryAlerts() { - ensureStateForBubbleUp(); NotificationEntry bubble = createBubble("testgroup", GROUP_ALERT_SUMMARY); assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(bubble)).isTrue(); } @@ -674,8 +625,6 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { */ @Test public void shouldNotBubbleUp_notAllowedToBubble() { - ensureStateForBubbleUp(); - NotificationEntry entry = createBubble(); modifyRanking(entry) .setCanBubble(false) @@ -689,8 +638,6 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { */ @Test public void shouldNotBubbleUp_notABubble() { - ensureStateForBubbleUp(); - NotificationEntry entry = createNotification(IMPORTANCE_HIGH); modifyRanking(entry) .setCanBubble(true) @@ -704,8 +651,6 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { */ @Test public void shouldNotBubbleUp_invalidMetadata() { - ensureStateForBubbleUp(); - NotificationEntry entry = createNotification(IMPORTANCE_HIGH); modifyRanking(entry) .setCanBubble(true) @@ -717,8 +662,6 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { @Test public void shouldNotBubbleUp_suppressedInterruptions() { - ensureStateForBubbleUp(); - // If the notification can't heads up in general, it shouldn't bubble. mNotifInterruptionStateProvider.addSuppressor(mSuppressInterruptions); @@ -727,8 +670,6 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { @Test public void shouldNotBubbleUp_filteredOut() { - ensureStateForBubbleUp(); - // Make canAlertCommon false by saying it's filtered out when(mKeyguardNotificationVisibilityProvider.shouldHideNotification(any())) .thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index f57c40958b24..b6a1bb3b27d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -26,7 +26,6 @@ import static android.service.notification.NotificationListenerService.Ranking.U import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking; import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; @@ -37,7 +36,6 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -77,7 +75,6 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.notification.AssistantFeedbackController; import com.android.systemui.statusbar.notification.NotificationActivityStarter; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; @@ -88,7 +85,6 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.wmshell.BubblesManager; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -128,7 +124,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private AccessibilityManager mAccessibilityManager; @Mock private HighPriorityProvider mHighPriorityProvider; @Mock private INotificationManager mINotificationManager; - @Mock private NotificationEntryManager mNotificationEntryManager; @Mock private LauncherApps mLauncherApps; @Mock private ShortcutManager mShortcutManager; @Mock private ChannelEditorDialogController mChannelEditorDialogController; @@ -160,7 +155,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mPeopleSpaceWidgetManager, mLauncherApps, mShortcutManager, mChannelEditorDialogController, mContextTracker, mAssistantFeedbackController, Optional.of(mBubblesManager), new UiEventLoggerFake(), mOnUserInteractionCallback, - mShadeController, mock(DumpManager.class)); + mShadeController); mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer, mOnSettingsClickListener); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); @@ -446,36 +441,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(mAssistantFeedbackController)); } - @Test - public void testShouldExtendLifetime() { - NotificationGuts guts = new NotificationGuts(mContext); - ExpandableNotificationRow row = spy(createTestNotificationRow()); - doReturn(guts).when(row).getGuts(); - NotificationEntry entry = row.getEntry(); - entry.setRow(row); - mGutsManager.setExposedGuts(guts); - - assertTrue(mGutsManager.shouldExtendLifetime(entry)); - } - - @Test - @Ignore - public void testSetShouldManageLifetime_setShouldManage() { - NotificationEntry entry = createTestNotificationRow().getEntry(); - mGutsManager.setShouldManageLifetime(entry, true /* shouldManage */); - - assertTrue(entry.getKey().equals(mGutsManager.mKeyToRemoveOnGutsClosed)); - } - - @Test - public void testSetShouldManageLifetime_setShouldNotManage() { - NotificationEntry entry = createTestNotificationRow().getEntry(); - mGutsManager.mKeyToRemoveOnGutsClosed = entry.getKey(); - mGutsManager.setShouldManageLifetime(entry, false /* shouldManage */); - - assertNull(mGutsManager.mKeyToRemoveOnGutsClosed); - } - //////////////////////////////////////////////////////////////////////////////////////////////// // Utility methods: diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index 38bd078589dc..66821dd5e4b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -51,7 +51,6 @@ import com.android.internal.logging.MetricsLogger; import com.android.systemui.TestableDependency; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.classifier.FalsingManagerFake; -import com.android.systemui.dump.DumpManager; import com.android.systemui.media.MediaFeatureFlag; import com.android.systemui.media.dialog.MediaOutputDialogFactory; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -62,10 +61,11 @@ import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.notification.ConversationNotificationProcessor; 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.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.icon.IconBuilder; import com.android.systemui.statusbar.notification.icon.IconManager; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; @@ -84,7 +84,6 @@ import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent; import com.android.systemui.tests.R; import com.android.systemui.wmshell.BubblesManager; import com.android.systemui.wmshell.BubblesTestActivity; -import com.android.wm.shell.bubbles.Bubbles; import org.mockito.ArgumentCaptor; @@ -112,8 +111,8 @@ public class NotificationTestHelper { private final Context mContext; private final TestableLooper mTestLooper; private int mId; - private final NotificationGroupManagerLegacy mGroupMembershipManager; - private final NotificationGroupManagerLegacy mGroupExpansionManager; + private final GroupMembershipManager mGroupMembershipManager; + private final GroupExpansionManager mGroupExpansionManager; private ExpandableNotificationRow mRow; private HeadsUpManagerPhone mHeadsUpManager; private final NotifBindPipeline mBindPipeline; @@ -136,24 +135,19 @@ public class NotificationTestHelper { dependency.injectMockDependency(NotificationShadeWindowController.class); dependency.injectMockDependency(MediaOutputDialogFactory.class); mStatusBarStateController = mock(StatusBarStateController.class); - mGroupMembershipManager = new NotificationGroupManagerLegacy( - mStatusBarStateController, - () -> mock(PeopleNotificationIdentifier.class), - Optional.of((mock(Bubbles.class))), - mock(DumpManager.class)); - mGroupExpansionManager = mGroupMembershipManager; + mGroupMembershipManager = mock(GroupMembershipManager.class); + mGroupExpansionManager = mock(GroupExpansionManager.class); mHeadsUpManager = new HeadsUpManagerPhone( mContext, mock(HeadsUpManagerLogger.class), mStatusBarStateController, mock(KeyguardBypassController.class), - mock(NotificationGroupManagerLegacy.class), + mock(GroupMembershipManager.class), mock(VisualStabilityProvider.class), mock(ConfigurationControllerImpl.class) ); mHeadsUpManager.mHandler.removeCallbacksAndMessages(null); mHeadsUpManager.mHandler = new Handler(mTestLooper.getLooper()); - mGroupMembershipManager.setHeadsUpManager(mHeadsUpManager); mIconManager = new IconManager( mock(CommonNotifCollection.class), mock(LauncherApps.class), @@ -529,10 +523,6 @@ public class NotificationTestHelper { mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags); inflateAndWait(entry); - // This would be done as part of onAsyncInflationFinished, but we skip large amounts of - // the callback chain, so we need to make up for not adding it to the group manager - // here. - mGroupMembershipManager.onEntryAdded(entry); return row; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java index ac9fcc064375..9d848e87b0a0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java @@ -18,24 +18,7 @@ package com.android.systemui.statusbar.notification.stack; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING; -import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE; -import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP; -import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE; -import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT; - -import static com.google.common.truth.Truth.assertThat; - import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; @@ -50,28 +33,19 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.media.KeyguardMediaController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.MediaContainerController; import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController; -import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import java.util.ArrayList; -import java.util.List; - @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -84,15 +58,11 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { @Mock private ConfigurationController mConfigurationController; @Mock private KeyguardMediaController mKeyguardMediaController; @Mock private NotificationSectionsFeatureManager mSectionsFeatureManager; - @Mock private NotificationRowComponent mNotificationRowComponent; - @Mock private ActivatableNotificationViewController mActivatableNotificationViewController; - @Mock private NotificationSectionsLogger mLogger; @Mock private MediaContainerController mMediaContainerController; @Mock private SectionHeaderController mIncomingHeaderController; @Mock private SectionHeaderController mPeopleHeaderController; @Mock private SectionHeaderController mAlertingHeaderController; @Mock private SectionHeaderController mSilentHeaderController; - @Mock private NotifPipelineFlags mNotifPipelineFlags; private NotificationSectionsManager mSectionsManager; @@ -113,22 +83,11 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { } return count; }); - when(mNotificationRowComponent.getActivatableNotificationViewController()) - .thenReturn(mActivatableNotificationViewController); - when(mMediaContainerController.getMediaContainerView()) - .thenReturn(mock(MediaContainerView.class)); - when(mIncomingHeaderController.getHeaderView()).thenReturn(mock(SectionHeaderView.class)); - when(mPeopleHeaderController.getHeaderView()).thenReturn(mock(SectionHeaderView.class)); - when(mAlertingHeaderController.getHeaderView()).thenReturn(mock(SectionHeaderView.class)); - when(mSilentHeaderController.getHeaderView()).thenReturn(mock(SectionHeaderView.class)); mSectionsManager = new NotificationSectionsManager( - mStatusBarStateController, mConfigurationController, mKeyguardMediaController, mSectionsFeatureManager, - mLogger, - mNotifPipelineFlags, mMediaContainerController, mIncomingHeaderController, mPeopleHeaderController, @@ -141,7 +100,6 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mSectionsManager.initialize(mNssl); when(mNssl.indexOfChild(any(View.class))).thenReturn(-1); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); - } @Test(expected = IllegalStateException.class) @@ -149,641 +107,4 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mSectionsManager.initialize(mNssl); } - @Test - public void testInsertHeader() { - // GIVEN a stack with HI and LO rows but no section headers - setStackState( - ALERTING, - ALERTING, - ALERTING, - GENTLE); - - // WHEN we update the section headers - mSectionsManager.updateSectionBoundaries(); - - // THEN a LO section header is added - verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 3); - } - - @Test - public void testRemoveHeader() { - // GIVEN a stack that originally had a header between the HI and LO sections - setStackState( - ALERTING, - ALERTING, - GENTLE); - mSectionsManager.updateSectionBoundaries(); - - // WHEN the last LO row is replaced with a HI row - setStackState( - ALERTING, - ALERTING, - GENTLE_HEADER, - ALERTING); - clearInvocations(mNssl); - mSectionsManager.updateSectionBoundaries(); - - // THEN the LO section header is removed - verify(mNssl).removeView(mSectionsManager.getSilentHeaderView()); - } - - @Test - public void testDoNothingIfHeaderAlreadyRemoved() { - // GIVEN a stack with only HI rows - setStackState( - ALERTING, - ALERTING, - ALERTING); - - // WHEN we update the sections headers - mSectionsManager.updateSectionBoundaries(); - - // THEN we don't add any section headers - verify(mNssl, never()).addView(eq(mSectionsManager.getSilentHeaderView()), anyInt()); - } - - @Test - public void testMoveHeaderForward() { - // GIVEN a stack that originally had a header between the HI and LO sections - setStackState( - ALERTING, - ALERTING, - ALERTING, - GENTLE); - mSectionsManager.updateSectionBoundaries(); - - // WHEN the LO section moves forward - setStackState( - ALERTING, - ALERTING, - GENTLE, - GENTLE_HEADER, - GENTLE); - mSectionsManager.updateSectionBoundaries(); - - // THEN the LO section header is also moved forward - verify(mNssl).changeViewPosition(mSectionsManager.getSilentHeaderView(), 2); - } - - @Test - public void testMoveHeaderBackward() { - // GIVEN a stack that originally had a header between the HI and LO sections - setStackState( - ALERTING, - GENTLE, - GENTLE, - GENTLE); - mSectionsManager.updateSectionBoundaries(); - - // WHEN the LO section moves backward - setStackState( - ALERTING, - GENTLE_HEADER, - ALERTING, - ALERTING, - GENTLE); - mSectionsManager.updateSectionBoundaries(); - - // THEN the LO section header is also moved backward (with appropriate index shifting) - verify(mNssl).changeViewPosition(mSectionsManager.getSilentHeaderView(), 3); - } - - @Test - public void testHeaderRemovedFromTransientParent() { - // GIVEN a stack where the header is animating away - setStackState( - ALERTING, - GENTLE_HEADER); - mSectionsManager.updateSectionBoundaries(); - clearInvocations(mNssl); - - SectionHeaderView silentHeaderView = mSectionsManager.getSilentHeaderView(); - ViewGroup transientParent = mock(ViewGroup.class); - when(silentHeaderView.getTransientContainer()).thenReturn(transientParent); - - // WHEN the LO section reappears - setStackState( - ALERTING, - GENTLE); - mSectionsManager.updateSectionBoundaries(); - - // THEN the header is first removed from the transient parent before being added to the - // NSSL. - final InOrder inOrder = inOrder(silentHeaderView, mNssl); - inOrder.verify(silentHeaderView).removeFromTransientContainer(); - inOrder.verify(mNssl).addView(eq(silentHeaderView), eq(1)); - } - - @Test - public void testHeaderNotShownOnLockscreen() { - // GIVEN a stack of HI and LO notifs on the lockscreen - when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); - setStackState( - ALERTING, - ALERTING, - ALERTING, - GENTLE); - - // WHEN we update the section headers - mSectionsManager.updateSectionBoundaries(); - - // Then the section header is not added - verify(mNssl, never()).addView(eq(mSectionsManager.getSilentHeaderView()), anyInt()); - } - - @Test - public void testHeaderShownWhenEnterLockscreen() { - // GIVEN a stack of HI and LO notifs on the lockscreen - when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); - setStackState( - ALERTING, - ALERTING, - ALERTING, - GENTLE); - mSectionsManager.updateSectionBoundaries(); - - // WHEN we unlock - when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); - mSectionsManager.updateSectionBoundaries(); - - // Then the section header is added - verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 3); - } - - @Test - public void testHeaderHiddenWhenEnterLockscreen() { - // GIVEN a stack of HI and LO notifs on the shade - setStackState( - ALERTING, - GENTLE_HEADER, - GENTLE); - - // WHEN we go back to the keyguard - when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); - mSectionsManager.updateSectionBoundaries(); - - // Then the section header is removed - verify(mNssl).removeView(mSectionsManager.getSilentHeaderView()); - } - - @Test - public void testPeopleFiltering_onlyAddSilentHeader() { - enablePeopleFiltering(); - - setStackState( - PERSON, - ALERTING, - GENTLE); - mSectionsManager.updateSectionBoundaries(); - - verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 2); - } - - @Test - public void testPeopleFiltering_AlertingHunWhilePeopleVisible() { - enablePeopleFiltering(); - - setupMockStack( - PEOPLE_HEADER, - ALERTING, - PERSON, - ALERTING_HEADER, - GENTLE_HEADER, - GENTLE - ); - mSectionsManager.updateSectionBoundaries(); - - verifyMockStack( - ChildType.HEADS_UP, - ChildType.PERSON, - ChildType.GENTLE_HEADER, - ChildType.GENTLE - ); - } - - @Test - public void testPeopleFiltering_PersonHunWhileAlertingHunVisible() { - enablePeopleFiltering(); - - setupMockStack( - PERSON, - INCOMING_HEADER, - ALERTING, - PEOPLE_HEADER, - PERSON - ); - mSectionsManager.updateSectionBoundaries(); - - verifyMockStack( - ChildType.HEADS_UP, - ChildType.HEADS_UP, - ChildType.PERSON - ); - } - - @Test - public void testPeopleFiltering_PersonHun() { - enablePeopleFiltering(); - - setupMockStack( - PERSON, - PEOPLE_HEADER, - PERSON - ); - mSectionsManager.updateSectionBoundaries(); - - verifyMockStack( - ChildType.PERSON, - ChildType.PERSON - ); - } - - @Test - public void testPeopleFiltering_AlertingHunWhilePersonHunning() { - enablePeopleFiltering(); - - setupMockStack( - ALERTING, - PERSON - ); - mSectionsManager.updateSectionBoundaries(); - verifyMockStack( - ChildType.HEADS_UP, - ChildType.PERSON - ); - } - - @Test - public void testPeopleFiltering_Fsn() { - enablePeopleFiltering(); - - setupMockStack( - INCOMING_HEADER, - ALERTING, - PEOPLE_HEADER, - FSN, - PERSON, - ALERTING, - GENTLE - ); - mSectionsManager.updateSectionBoundaries(); - - verifyMockStack( - ChildType.HEADS_UP, - ChildType.FSN, - ChildType.PERSON, - ChildType.ALERTING, - ChildType.GENTLE_HEADER, - ChildType.GENTLE - ); - } - - @Test - public void testMediaControls_AddWhenEnterKeyguard() { - enableMediaControls(); - - // GIVEN a stack that doesn't include media controls - setStackState(ALERTING, GENTLE_HEADER, GENTLE); - - // WHEN we go back to the keyguard - when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); - mSectionsManager.updateSectionBoundaries(); - - // Then the media controls are added - verify(mNssl).addView(mSectionsManager.getMediaControlsView(), 0); - } - - @Test - public void testMediaControls_AddWhenEnterKeyguardWithHeadsUp() { - enableMediaControls(); - - // GIVEN a stack that doesn't include media - setupMockStack( - ALERTING, - ALERTING, - GENTLE_HEADER, - GENTLE); - - // WHEN we go back to the keyguard - when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); - mSectionsManager.updateSectionBoundaries(); - - verifyMockStack( - ChildType.MEDIA_CONTROLS, - ChildType.ALERTING, - ChildType.ALERTING, - ChildType.GENTLE); - } - - @Test - public void testRemoveNonSilentHeader() { - enablePeopleFiltering(); - enableMediaControls(); - - setupMockStack( - MEDIA_CONTROLS, - INCOMING_HEADER, - PERSON, - ALERTING, - PEOPLE_HEADER, - ALERTING_HEADER, - ALERTING, - ALERTING, - GENTLE_HEADER, - GENTLE, - GENTLE - ); - - mSectionsManager.updateSectionBoundaries(); - - verifyMockStack( - ChildType.MEDIA_CONTROLS, - ChildType.PERSON, - ChildType.ALERTING, - ChildType.ALERTING, - ChildType.ALERTING, - ChildType.GENTLE_HEADER, - ChildType.GENTLE, - ChildType.GENTLE - ); - } - - @Test - public void testExpandIncomingSection() { - enablePeopleFiltering(); - - setupMockStack( - INCOMING_HEADER, - PERSON, - ALERTING, - PEOPLE_HEADER, - ALERTING, - PERSON, - ALERTING_HEADER, - ALERTING - ); - - mSectionsManager.updateSectionBoundaries(); - - verifyMockStack( - ChildType.HEADS_UP, - ChildType.HEADS_UP, - ChildType.HEADS_UP, - ChildType.PERSON, - ChildType.ALERTING - ); - } - - @Test - public void testIgnoreGoneView() { - enablePeopleFiltering(); - - setupMockStack( - PERSON.gone(), - ALERTING, - GENTLE - ); - - mSectionsManager.updateSectionBoundaries(); - - verifyMockStack( - ChildType.PERSON, - ChildType.ALERTING, - ChildType.GENTLE_HEADER, - ChildType.GENTLE - ); - } - - private void enablePeopleFiltering() { - when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true); - } - - private void enableMediaControls() { - when(mSectionsFeatureManager.isMediaControlsEnabled()).thenReturn(true); - } - - private enum ChildType { - INCOMING_HEADER, MEDIA_CONTROLS, PEOPLE_HEADER, ALERTING_HEADER, GENTLE_HEADER, HEADS_UP, - FSN, PERSON, ALERTING, GENTLE, OTHER - } - - private void setStackState(StackEntry... children) { - when(mNssl.getChildCount()).thenReturn(children.length); - for (int i = 0; i < children.length; i++) { - View child; - StackEntry entry = children[i]; - switch (entry.mChildType) { - case INCOMING_HEADER: - child = mSectionsManager.getIncomingHeaderView(); - break; - case MEDIA_CONTROLS: - child = mSectionsManager.getMediaControlsView(); - break; - case PEOPLE_HEADER: - child = mSectionsManager.getPeopleHeaderView(); - break; - case ALERTING_HEADER: - child = mSectionsManager.getAlertingHeaderView(); - break; - case GENTLE_HEADER: - child = mSectionsManager.getSilentHeaderView(); - break; - case FSN: - child = mockNotification(BUCKET_FOREGROUND_SERVICE, entry.mIsGone); - break; - case PERSON: - child = mockNotification(BUCKET_PEOPLE, entry.mIsGone); - break; - case ALERTING: - child = mockNotification(BUCKET_ALERTING, entry.mIsGone); - break; - case GENTLE: - child = mockNotification(BUCKET_SILENT, entry.mIsGone); - break; - case OTHER: - child = mock(View.class); - when(child.getVisibility()).thenReturn(View.VISIBLE); - when(child.getParent()).thenReturn(mNssl); - break; - default: - throw new RuntimeException("Unknown ChildType: " + children[i]); - } - when(mNssl.getChildAt(i)).thenReturn(child); - when(mNssl.indexOfChild(child)).thenReturn(i); - } - } - - private View mockNotification(@PriorityBucket int bucket, boolean isGone) { - ExpandableNotificationRow notifRow = - mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS); - when(notifRow.getVisibility()).thenReturn(View.VISIBLE); - when(notifRow.getParent()).thenReturn(mNssl); - - NotificationEntry mockEntry = mock(NotificationEntry.class); - when(notifRow.getEntry()).thenReturn(mockEntry); - - int[] bucketRef = new int[] { bucket }; - when(mockEntry.getBucket()).thenAnswer(invocation -> bucketRef[0]); - doAnswer(invocation -> { - bucketRef[0] = invocation.getArgument(0); - return null; - }).when(mockEntry).setBucket(anyInt()); - - when(notifRow.getVisibility()).thenReturn(isGone ? View.GONE : View.VISIBLE); - return notifRow; - } - - private void verifyMockStack(ChildType... expected) { - final List<ChildType> actual = new ArrayList<>(); - int childCount = mNssl.getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = mNssl.getChildAt(i); - if (child == mSectionsManager.getIncomingHeaderView()) { - actual.add(ChildType.INCOMING_HEADER); - continue; - } - if (child == mSectionsManager.getMediaControlsView()) { - actual.add(ChildType.MEDIA_CONTROLS); - continue; - } - if (child == mSectionsManager.getPeopleHeaderView()) { - actual.add(ChildType.PEOPLE_HEADER); - continue; - } - if (child == mSectionsManager.getAlertingHeaderView()) { - actual.add(ChildType.ALERTING_HEADER); - continue; - } - if (child == mSectionsManager.getSilentHeaderView()) { - actual.add(ChildType.GENTLE_HEADER); - continue; - } - if (child instanceof ExpandableNotificationRow) { - switch (((ExpandableNotificationRow) child).getEntry().getBucket()) { - case BUCKET_HEADS_UP: - actual.add(ChildType.HEADS_UP); - break; - case BUCKET_FOREGROUND_SERVICE: - actual.add(ChildType.FSN); - break; - case BUCKET_PEOPLE: - actual.add(ChildType.PERSON); - break; - case BUCKET_ALERTING: - actual.add(ChildType.ALERTING); - break; - case BUCKET_SILENT: - actual.add(ChildType.GENTLE); - break; - default: - actual.add(ChildType.OTHER); - break; - } - continue; - } - actual.add(ChildType.OTHER); - } - assertThat(actual).containsExactly((Object[]) expected).inOrder(); - } - - private void setupMockStack(StackEntry... entries) { - final List<View> children = new ArrayList<>(); - when(mNssl.getChildCount()).thenAnswer(invocation -> children.size()); - when(mNssl.getChildAt(anyInt())) - .thenAnswer(invocation -> { - Integer index = invocation.getArgument(0); - if (index == null || index < 0 || index >= children.size()) { - return null; - } - return children.get(index); - }); - when(mNssl.indexOfChild(any())) - .thenAnswer(invocation -> children.indexOf(invocation.getArgument(0))); - doAnswer(invocation -> { - View child = invocation.getArgument(0); - int index = invocation.getArgument(1); - children.add(index, child); - return null; - }).when(mNssl).addView(any(), anyInt()); - doAnswer(invocation -> { - View child = invocation.getArgument(0); - children.remove(child); - return null; - }).when(mNssl).removeView(any()); - doAnswer(invocation -> { - View child = invocation.getArgument(0); - int newIndex = invocation.getArgument(1); - children.remove(child); - children.add(newIndex, child); - return null; - }).when(mNssl).changeViewPosition(any(), anyInt()); - for (StackEntry entry : entries) { - View child; - switch (entry.mChildType) { - case INCOMING_HEADER: - child = mSectionsManager.getIncomingHeaderView(); - break; - case MEDIA_CONTROLS: - child = mSectionsManager.getMediaControlsView(); - break; - case PEOPLE_HEADER: - child = mSectionsManager.getPeopleHeaderView(); - break; - case ALERTING_HEADER: - child = mSectionsManager.getAlertingHeaderView(); - break; - case GENTLE_HEADER: - child = mSectionsManager.getSilentHeaderView(); - break; - case FSN: - child = mockNotification(BUCKET_FOREGROUND_SERVICE, entry.mIsGone); - break; - case PERSON: - child = mockNotification(BUCKET_PEOPLE, entry.mIsGone); - break; - case ALERTING: - child = mockNotification(BUCKET_ALERTING, entry.mIsGone); - break; - case GENTLE: - child = mockNotification(BUCKET_SILENT, entry.mIsGone); - break; - case OTHER: - child = mock(View.class); - when(child.getVisibility()).thenReturn(View.VISIBLE); - when(child.getParent()).thenReturn(mNssl); - break; - default: - throw new RuntimeException("Unknown ChildType: " + entry.mChildType); - } - children.add(child); - } - } - - private static final StackEntry INCOMING_HEADER = new StackEntry(ChildType.INCOMING_HEADER); - private static final StackEntry MEDIA_CONTROLS = new StackEntry(ChildType.MEDIA_CONTROLS); - private static final StackEntry PEOPLE_HEADER = new StackEntry(ChildType.PEOPLE_HEADER); - private static final StackEntry ALERTING_HEADER = new StackEntry(ChildType.ALERTING_HEADER); - private static final StackEntry GENTLE_HEADER = new StackEntry(ChildType.GENTLE_HEADER); - private static final StackEntry FSN = new StackEntry(ChildType.FSN); - private static final StackEntry PERSON = new StackEntry(ChildType.PERSON); - private static final StackEntry ALERTING = new StackEntry(ChildType.ALERTING); - private static final StackEntry GENTLE = new StackEntry(ChildType.GENTLE); - - private static class StackEntry { - final ChildType mChildType; - final boolean mIsGone; - - StackEntry(ChildType childType) { - this(childType, false); - } - - StackEntry(ChildType childType, boolean isGone) { - mChildType = childType; - mIsGone = isGone; - } - - public StackEntry gone() { - return new StackEntry(mChildType, true); - } - } } 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 9bcea101f83b..1460e048d234 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 @@ -67,6 +67,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.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.row.ExpandableNotificationRow; @@ -121,7 +122,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Mock private NotificationSwipeHelper mNotificationSwipeHelper; @Mock private CentralSurfaces mCentralSurfaces; @Mock private ScrimController mScrimController; - @Mock private NotificationGroupManagerLegacy mLegacyGroupManager; + @Mock private NotificationGroupManagerLegacy mGroupManagerLegacy; + @Mock private GroupExpansionManager mGroupExpansionManager; @Mock private SectionHeaderController mSilentHeaderController; @Mock private NotifPipelineFlags mNotifPipelineFlags; @Mock private NotifPipeline mNotifPipeline; @@ -174,8 +176,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mNotificationSwipeHelperBuilder, mCentralSurfaces, mScrimController, - mLegacyGroupManager, - mLegacyGroupManager, + mGroupManagerLegacy, + mGroupExpansionManager, mSilentHeaderController, mNotifPipeline, mNotifCollection, @@ -184,7 +186,6 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mShadeTransitionController, mUiEventLogger, mRemoteInputManager, - mVisualStabilityManager, mShadeController, mJankMonitor, mStackLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 37a48937419a..3c22edc0fcf2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -66,7 +66,6 @@ import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; 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.GroupExpansionManager; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -101,8 +100,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); @Mock private CentralSurfaces mCentralSurfaces; @Mock private SysuiStatusBarStateController mBarState; - @Mock private NotificationGroupManagerLegacy mGroupMembershipManger; - @Mock private NotificationGroupManagerLegacy mGroupExpansionManager; + @Mock private GroupMembershipManager mGroupMembershipManger; + @Mock private GroupExpansionManager mGroupExpansionManager; @Mock private DumpManager mDumpManager; @Mock private ExpandHelper mExpandHelper; @Mock private EmptyShadeView mEmptyShadeView; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 7b7f45a44615..a0f7087ddb9e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -418,7 +418,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { wakefulnessLifecycle, mStatusBarStateController, Optional.of(mBubbles), - mVisualStabilityManager, mDeviceProvisionedController, mNavigationBarController, mAccessibilityFloatingMenuController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index db5741c90ebc..2ab2172b7e29 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -25,7 +25,6 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.view.View; import androidx.test.filters.SmallTest; @@ -35,8 +34,8 @@ import com.android.systemui.statusbar.AlertingNotificationManagerTest; import com.android.systemui.statusbar.NotificationShadeWindowController; 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.provider.VisualStabilityProvider; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManagerLogger; @@ -60,19 +59,18 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { private HeadsUpManagerPhone mHeadsUpManager; @Mock private HeadsUpManagerLogger mHeadsUpManagerLogger; - @Mock private NotificationGroupManagerLegacy mGroupManager; - @Mock private View mNotificationShadeWindowView; + @Mock private GroupMembershipManager mGroupManager; @Mock private VisualStabilityProvider mVSProvider; @Mock private StatusBarStateController mStatusBarStateController; @Mock private KeyguardBypassController mBypassController; @Mock private ConfigurationControllerImpl mConfigurationController; private boolean mLivesPastNormalTime; - private final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone { + private static final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone { TestableHeadsUpManagerPhone( Context context, HeadsUpManagerLogger headsUpManagerLogger, - NotificationGroupManagerLegacy groupManager, + GroupMembershipManager groupManager, VisualStabilityProvider visualStabilityProvider, StatusBarStateController statusBarStateController, KeyguardBypassController keyguardBypassController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java deleted file mode 100644 index 7070bc19db62..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Copyright (C) 2018 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.phone; - -import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON; -import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.Notification; -import android.service.notification.StatusBarNotification; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.dump.DumpManager; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -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.legacy.NotificationGroupManagerLegacy; -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback; -import com.android.systemui.statusbar.notification.row.RowContentBindParams; -import com.android.systemui.statusbar.notification.row.RowContentBindStage; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.statusbar.policy.HeadsUpManagerLogger; -import com.android.wm.shell.bubbles.Bubbles; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -import java.util.HashMap; -import java.util.Optional; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { - @Rule public MockitoRule rule = MockitoJUnit.rule(); - - private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; - private NotificationGroupManagerLegacy mGroupManager; - private HeadsUpManager mHeadsUpManager; - @Mock private NotificationEntryManager mNotificationEntryManager; - @Mock private RowContentBindStage mBindStage; - @Mock PeopleNotificationIdentifier mPeopleNotificationIdentifier; - @Mock StatusBarStateController mStatusBarStateController; - @Captor private ArgumentCaptor<NotificationEntryListener> mListenerCaptor; - private NotificationEntryListener mNotificationEntryListener; - private final HashMap<String, NotificationEntry> mPendingEntries = new HashMap<>(); - private final NotificationGroupTestHelper mGroupTestHelper = - new NotificationGroupTestHelper(mContext); - - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - mHeadsUpManager = new HeadsUpManager(mContext, mock(HeadsUpManagerLogger.class)) {}; - - when(mNotificationEntryManager.getPendingNotificationsIterator()) - .thenReturn(mPendingEntries.values()); - - mGroupManager = new NotificationGroupManagerLegacy( - mStatusBarStateController, - () -> mPeopleNotificationIdentifier, - Optional.of(mock(Bubbles.class)), - mock(DumpManager.class)); - mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, mGroupManager); - mGroupManager.setHeadsUpManager(mHeadsUpManager); - - when(mBindStage.getStageParams(any())).thenReturn(new RowContentBindParams()); - - mGroupAlertTransferHelper = new NotificationGroupAlertTransferHelper( - mBindStage, mStatusBarStateController, mGroupManager); - mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager); - - mGroupAlertTransferHelper.bind(mNotificationEntryManager, mGroupManager); - verify(mNotificationEntryManager).addNotificationEntryListener(mListenerCaptor.capture()); - mNotificationEntryListener = mListenerCaptor.getValue(); - mHeadsUpManager.addListener(mGroupAlertTransferHelper); - } - - @After - public void tearDown() { - mHeadsUpManager.mHandler.removeCallbacksAndMessages(null); - } - - private void mockHasHeadsUpContentView(NotificationEntry entry, - boolean hasHeadsUpContentView) { - RowContentBindParams params = new RowContentBindParams(); - if (hasHeadsUpContentView) { - params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP); - } - when(mBindStage.getStageParams(eq(entry))).thenReturn(params); - } - - private void mockHasHeadsUpContentView(NotificationEntry entry) { - mockHasHeadsUpContentView(entry, true); - } - - private void mockIsPriority(NotificationEntry priorityEntry) { - when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry))) - .thenReturn(PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON); - } - - @Test - public void testSuppressedSummaryHeadsUpTransfersToChild() { - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); - mHeadsUpManager.showNotification(summaryEntry); - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); - - mockHasHeadsUpContentView(childEntry); - - // Summary will be suppressed because there is only one child. - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - // A suppressed summary should transfer its alert state to the child. - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertTrue(mHeadsUpManager.isAlerting(childEntry.getKey())); - } - - @Test - public void testSuppressedSummaryHeadsUpTransfersToChildButBackAgain() { - NotificationEntry summaryEntry = - mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationEntry childEntry = - mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationEntry childEntry2 = - mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - mHeadsUpManager.showNotification(summaryEntry); - // Trigger a transfer of alert state from summary to child. - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - // Add second child notification so that summary is no longer suppressed. - mPendingEntries.put(childEntry2.getKey(), childEntry2); - mNotificationEntryListener.onPendingEntryAdded(childEntry2); - mGroupManager.onEntryAdded(childEntry2); - - // The alert state should transfer back to the summary as there is now more than one - // child and the summary should no longer be suppressed. - assertTrue(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey())); - } - - @Test - public void testSuppressedSummaryHeadsUpDoesntTransferBackOnDozingChanged() { - NotificationEntry summaryEntry = - mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationEntry childEntry = - mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationEntry childEntry2 = - mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - mHeadsUpManager.showNotification(summaryEntry); - // Trigger a transfer of alert state from summary to child. - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - // Set dozing to true. - mGroupAlertTransferHelper.onDozingChanged(true); - - // Add second child notification so that summary is no longer suppressed. - mPendingEntries.put(childEntry2.getKey(), childEntry2); - mNotificationEntryListener.onPendingEntryAdded(childEntry2); - mGroupManager.onEntryAdded(childEntry2); - - // Dozing changed so no reason to re-alert summary. - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - } - - @Test - public void testSuppressedSummaryHeadsUpTransferDoesNotAlertChildIfUninflated() { - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); - mHeadsUpManager.showNotification(summaryEntry); - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); - mockHasHeadsUpContentView(childEntry, false); - - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - // Alert is immediately removed from summary, but we do not show child yet either as its - // content is not inflated. - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey())); - assertTrue(mGroupAlertTransferHelper.isAlertTransferPending(childEntry)); - } - - @Test - public void testSuppressedSummaryHeadsUpTransferAlertsChildOnInflation() { - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); - mHeadsUpManager.showNotification(summaryEntry); - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); - mockHasHeadsUpContentView(childEntry, false); - - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - // Child entry finishes its inflation. - ArgumentCaptor<BindCallback> callbackCaptor = ArgumentCaptor.forClass(BindCallback.class); - verify(mBindStage).requestRebind(eq(childEntry), callbackCaptor.capture()); - callbackCaptor.getValue().onBindFinished(childEntry); - - // Alert is immediately removed from summary, and we show child as its content is inflated. - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertTrue(mHeadsUpManager.isAlerting(childEntry.getKey())); - } - - @Test - public void testSuppressedSummaryHeadsUpTransferBackAbortsChildInflation() { - NotificationEntry summaryEntry = - mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationEntry childEntry = - mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - RowContentBindParams params = new RowContentBindParams(); - when(mBindStage.getStageParams(eq(childEntry))).thenReturn(params); - - NotificationEntry childEntry2 = - mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - mHeadsUpManager.showNotification(summaryEntry); - // Trigger a transfer of alert state from summary to child. - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - // Add second child notification so that summary is no longer suppressed. - mPendingEntries.put(childEntry2.getKey(), childEntry2); - mNotificationEntryListener.onPendingEntryAdded(childEntry2); - mGroupManager.onEntryAdded(childEntry2); - - // Child entry finishes its inflation. - ArgumentCaptor<BindCallback> callbackCaptor = ArgumentCaptor.forClass(BindCallback.class); - verify(mBindStage).requestRebind(eq(childEntry), callbackCaptor.capture()); - callbackCaptor.getValue().onBindFinished(childEntry); - - assertTrue((params.getContentViews() & FLAG_CONTENT_VIEW_HEADS_UP) == 0); - assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey())); - } - - @Test - public void testCleanUpPendingAlertInfo() { - NotificationEntry summaryEntry = - mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationEntry childEntry = - mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - mockHasHeadsUpContentView(childEntry, false); - - mHeadsUpManager.showNotification(summaryEntry); - // Trigger a transfer of alert state from summary to child. - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - mNotificationEntryListener.onEntryRemoved( - childEntry, null, false, UNDEFINED_DISMISS_REASON); - - assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry)); - } - - @Test - public void testUpdateGroupChangeDoesNotTransfer() { - NotificationEntry summaryEntry = - mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationEntry childEntry = - mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - mockHasHeadsUpContentView(childEntry, false); - - mHeadsUpManager.showNotification(summaryEntry); - // Trigger a transfer of alert state from summary to child. - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - // Notify that entry changed groups. - StatusBarNotification oldNotification = childEntry.getSbn(); - StatusBarNotification newSbn = spy(childEntry.getSbn().clone()); - doReturn("other_group").when(newSbn).getGroupKey(); - childEntry.setSbn(newSbn); - mGroupManager.onEntryUpdated(childEntry, oldNotification); - - assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry)); - } - - @Test - public void testUpdateChildToSummaryDoesNotTransfer() { - final String tag = "fooTag"; - NotificationEntry summaryEntry = - mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationEntry childEntry = - mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY, 47, tag); - mockHasHeadsUpContentView(childEntry, false); - - mHeadsUpManager.showNotification(summaryEntry); - // Trigger a transfer of alert state from summary to child. - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - // Update that child to a summary. - StatusBarNotification oldNotification = childEntry.getSbn(); - childEntry.setSbn( - mGroupTestHelper.createSummaryNotification( - Notification.GROUP_ALERT_SUMMARY, 47, tag).getSbn()); - mGroupManager.onEntryUpdated(childEntry, oldNotification); - - assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry)); - } - - @Test - public void testOverriddenSummaryHeadsUpTransfersToPriority() { - // Creation order is oldest to newest, meaning the priority will be deemed newest - int groupAlert = Notification.GROUP_ALERT_SUMMARY; - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert); - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert); - NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert); - mockIsPriority(priorityEntry); - - // summary gets heads up - mHeadsUpManager.showNotification(summaryEntry); - - mockHasHeadsUpContentView(summaryEntry); - mockHasHeadsUpContentView(priorityEntry); - mockHasHeadsUpContentView(childEntry); - - // Summary will have an alertOverride. - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(priorityEntry); - mGroupManager.onEntryAdded(childEntry); - - // An overridden summary should transfer its alert state to the priority. - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey())); - assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey())); - } - - @Test - public void testOverriddenSummaryHeadsUpTransferDoesNotAlertPriorityIfUninflated() { - // Creation order is oldest to newest, meaning the priority will be deemed newest - int groupAlert = Notification.GROUP_ALERT_SUMMARY; - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert); - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert); - NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert); - mockIsPriority(priorityEntry); - - // summary gets heads up - mHeadsUpManager.showNotification(summaryEntry); - - mockHasHeadsUpContentView(summaryEntry); - mockHasHeadsUpContentView(priorityEntry, false); - mockHasHeadsUpContentView(childEntry); - - // Summary will have an alertOverride. - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(priorityEntry); - mGroupManager.onEntryAdded(childEntry); - - // Alert is immediately removed from summary, but we do not show priority yet either as its - // content is not inflated. - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey())); - assertFalse(mHeadsUpManager.isAlerting(priorityEntry.getKey())); - assertTrue(mGroupAlertTransferHelper.isAlertTransferPending(priorityEntry)); - } - - @Test - public void testOverriddenSummaryHeadsUpTransfersToPriorityButBackAgain() { - // Creation order is oldest to newest, meaning the child2 will ultimately be deemed newest - int groupAlert = Notification.GROUP_ALERT_SUMMARY; - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert); - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert); - NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert); - NotificationEntry childEntry2 = mGroupTestHelper.createChildNotification(groupAlert); - mockIsPriority(priorityEntry); - - // summary gets heads up - mHeadsUpManager.showNotification(summaryEntry); - - mockHasHeadsUpContentView(summaryEntry); - mockHasHeadsUpContentView(priorityEntry); - mockHasHeadsUpContentView(childEntry); - mockHasHeadsUpContentView(childEntry2); - - // Summary will have an alertOverride. - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(priorityEntry); - mGroupManager.onEntryAdded(childEntry); - - // An overridden summary should transfer its alert state to the priority. - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey())); - assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey())); - - mGroupManager.onEntryAdded(childEntry2); - - // An overridden summary should transfer its alert state to the priority. - assertTrue(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey())); - assertFalse(mHeadsUpManager.isAlerting(childEntry2.getKey())); - assertFalse(mHeadsUpManager.isAlerting(priorityEntry.getKey())); - } - - @Test - public void testOverriddenSuppressedSummaryHeadsUpTransfersToChildThenToPriority() { - // Creation order is oldest to newest, meaning the priority will ultimately be deemed newest - int groupAlert = Notification.GROUP_ALERT_SUMMARY; - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert); - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert); - NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert); - mockIsPriority(priorityEntry); - - // summary gets heads up - mHeadsUpManager.showNotification(summaryEntry); - - mockHasHeadsUpContentView(summaryEntry); - mockHasHeadsUpContentView(priorityEntry); - mockHasHeadsUpContentView(childEntry); - - // Summary will be suppressed, and the child will receive the alert - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertTrue(mHeadsUpManager.isAlerting(childEntry.getKey())); - - // Alert should be transferred "back" from the child to the priority - mGroupManager.onEntryAdded(priorityEntry); - - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey())); - assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey())); - } - - @Test - public void testOverriddenSuppressedSummaryHeadsUpTransfersToPriorityThenToChild() { - // Creation order is oldest to newest, meaning the child will ultimately be deemed newest - int groupAlert = Notification.GROUP_ALERT_SUMMARY; - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert); - NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert); - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert); - mockIsPriority(priorityEntry); - - // summary gets heads up - mHeadsUpManager.showNotification(summaryEntry); - - mockHasHeadsUpContentView(summaryEntry); - mockHasHeadsUpContentView(priorityEntry); - mockHasHeadsUpContentView(childEntry); - - // Summary will have alert override of the priority - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(priorityEntry); - - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey())); - - // Alert should be transferred "back" from the priority to the child (which is newer) - mGroupManager.onEntryAdded(childEntry); - - assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey())); - assertTrue(mHeadsUpManager.isAlerting(childEntry.getKey())); - assertFalse(mHeadsUpManager.isAlerting(priorityEntry.getKey())); - } - -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java deleted file mode 100644 index d002cebe5cb1..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright (C) 2018 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.phone; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; - -import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import android.app.Notification; -import android.service.notification.StatusBarNotification; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.util.Log; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.dump.DumpManager; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; -import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup; -import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener; -import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.wm.shell.bubbles.Bubbles; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -import java.util.Optional; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class NotificationGroupManagerLegacyTest extends SysuiTestCase { - @Rule - public MockitoRule rule = MockitoJUnit.rule(); - - private NotificationGroupManagerLegacy mGroupManager; - private final NotificationGroupTestHelper mGroupTestHelper = - new NotificationGroupTestHelper(mContext); - - @Mock - PeopleNotificationIdentifier mPeopleNotificationIdentifier; - @Mock - HeadsUpManager mHeadsUpManager; - - @Before - public void setup() { - mDependency.injectMockDependency(Bubbles.class); - initializeGroupManager(); - } - - private void initializeGroupManager() { - mGroupManager = new NotificationGroupManagerLegacy( - mock(StatusBarStateController.class), - () -> mPeopleNotificationIdentifier, - Optional.of(mock(Bubbles.class)), - mock(DumpManager.class)); - mGroupManager.setHeadsUpManager(mHeadsUpManager); - } - - @Test - public void testIsOnlyChildInGroup() { - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); - - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - - assertTrue(mGroupManager.isOnlyChildInGroup(childEntry)); - } - - @Test - public void testIsChildInGroupWithSummary() { - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); - - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); - - assertTrue(mGroupManager.isChildInGroup(childEntry)); - } - - @Test - public void testIsSummaryOfGroupWithChildren() { - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); - - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); - - assertTrue(mGroupManager.isGroupSummary(summaryEntry)); - assertEquals(summaryEntry, mGroupManager.getGroupSummary(childEntry)); - } - - @Test - public void testRemoveChildFromGroupWithSummary() { - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); - - mGroupManager.onEntryRemoved(childEntry); - - assertFalse(mGroupManager.isChildInGroup(childEntry)); - } - - @Test - public void testRemoveSummaryFromGroupWithSummary() { - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); - - mGroupManager.onEntryRemoved(summaryEntry); - - assertNull(mGroupManager.getGroupSummary(childEntry)); - assertFalse(mGroupManager.isGroupSummary(summaryEntry)); - } - - @Test - public void testHeadsUpEntryIsIsolated() { - NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); - mGroupManager.onEntryAdded(summaryEntry); - mGroupManager.onEntryAdded(childEntry); - mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); - when(mHeadsUpManager.isAlerting(childEntry.getKey())).thenReturn(true); - - mGroupManager.onHeadsUpStateChanged(childEntry, true); - - // Child entries that are heads upped should be considered separate groups visually even if - // they are the same group logically - assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry)); - assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry)); - } - - @Test - public void testAlertOverrideWithSiblings_0() { - helpTestAlertOverrideWithSiblings(0); - } - - @Test - public void testAlertOverrideWithSiblings_1() { - helpTestAlertOverrideWithSiblings(1); - } - - @Test - public void testAlertOverrideWithSiblings_2() { - helpTestAlertOverrideWithSiblings(2); - } - - @Test - public void testAlertOverrideWithSiblings_3() { - helpTestAlertOverrideWithSiblings(3); - } - - @Test - public void testAlertOverrideWithSiblings_9() { - helpTestAlertOverrideWithSiblings(9); - } - - /** - * Helper for testing various sibling counts - */ - private void helpTestAlertOverrideWithSiblings(int numSiblings) { - helpTestAlertOverride( - /* numSiblings */ numSiblings, - /* summaryGroupAlert */ Notification.GROUP_ALERT_SUMMARY, - /* priorityGroupAlert */ Notification.GROUP_ALERT_SUMMARY, - /* siblingGroupAlert */ Notification.GROUP_ALERT_SUMMARY, - /* expectAlertOverride */ true); - } - - @Test - public void testAlertOverrideWithParentAlertAll() { - // tests that summary can have GROUP_ALERT_ALL and this still works - helpTestAlertOverride( - /* numSiblings */ 1, - /* summaryGroupAlert */ Notification.GROUP_ALERT_ALL, - /* priorityGroupAlert */ Notification.GROUP_ALERT_SUMMARY, - /* siblingGroupAlert */ Notification.GROUP_ALERT_SUMMARY, - /* expectAlertOverride */ true); - } - - @Test - public void testAlertOverrideWithParentAlertChild() { - // Tests that if the summary alerts CHILDREN, there's no alertOverride - helpTestAlertOverride( - /* numSiblings */ 1, - /* summaryGroupAlert */ Notification.GROUP_ALERT_CHILDREN, - /* priorityGroupAlert */ Notification.GROUP_ALERT_SUMMARY, - /* siblingGroupAlert */ Notification.GROUP_ALERT_SUMMARY, - /* expectAlertOverride */ false); - } - - @Test - public void testAlertOverrideWithChildrenAlertAll() { - // Tests that if the children alert ALL, there's no alertOverride - helpTestAlertOverride( - /* numSiblings */ 1, - /* summaryGroupAlert */ Notification.GROUP_ALERT_SUMMARY, - /* priorityGroupAlert */ Notification.GROUP_ALERT_ALL, - /* siblingGroupAlert */ Notification.GROUP_ALERT_ALL, - /* expectAlertOverride */ false); - } - - /** - * This tests, for a group with a priority entry and the given number of siblings, that: - * 1) the priority entry is identified as the alertOverride for the group - * 2) the onAlertOverrideChanged method is called at that time - * 3) when the priority entry is removed, these are reversed - */ - private void helpTestAlertOverride(int numSiblings, - @Notification.GroupAlertBehavior int summaryGroupAlert, - @Notification.GroupAlertBehavior int priorityGroupAlert, - @Notification.GroupAlertBehavior int siblingGroupAlert, - boolean expectAlertOverride) { - long when = 10000; - // Create entries in an order so that the priority entry can be deemed the newest child. - NotificationEntry[] siblings = new NotificationEntry[numSiblings]; - for (int i = 0; i < numSiblings; i++) { - siblings[i] = mGroupTestHelper - .createChildNotification(siblingGroupAlert, i, "sibling", ++when); - } - NotificationEntry priorityEntry = - mGroupTestHelper.createChildNotification(priorityGroupAlert, 0, "priority", ++when); - NotificationEntry summaryEntry = - mGroupTestHelper.createSummaryNotification(summaryGroupAlert, 0, "summary", ++when); - - // The priority entry is an important conversation. - when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry))) - .thenReturn(PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON); - - // Register a listener so we can verify that the event is sent. - OnGroupChangeListener groupChangeListener = mock(OnGroupChangeListener.class); - mGroupManager.registerGroupChangeListener(groupChangeListener); - - // Add all the entries. The order here shouldn't matter. - mGroupManager.onEntryAdded(summaryEntry); - for (int i = 0; i < numSiblings; i++) { - mGroupManager.onEntryAdded(siblings[i]); - } - mGroupManager.onEntryAdded(priorityEntry); - - if (!expectAlertOverride) { - // Test expectation is that there will NOT be an alert, so verify that! - NotificationGroup summaryGroup = - mGroupManager.getGroupForSummary(summaryEntry.getSbn()); - assertNull(summaryGroup.alertOverride); - return; - } - int max2Siblings = Math.min(2, numSiblings); - - // Verify that the summary group has the priority child as its alertOverride - NotificationGroup summaryGroup = mGroupManager.getGroupForSummary(summaryEntry.getSbn()); - assertEquals(priorityEntry, summaryGroup.alertOverride); - verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry); - verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, true); - if (numSiblings > 1) { - verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, false); - } - verify(groupChangeListener).onGroupCreated(any(), eq(priorityEntry.getKey())); - verify(groupChangeListener).onGroupCreated(any(), eq(summaryEntry.getSbn().getGroupKey())); - verify(groupChangeListener, times(max2Siblings + 1)).onGroupsChanged(); - verifyNoMoreInteractions(groupChangeListener); - - // Verify that only the priority notification is isolated from the group - assertEquals(priorityEntry, mGroupManager.getGroupSummary(priorityEntry)); - assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(priorityEntry)); - // Verify that the siblings are NOT isolated from the group - for (int i = 0; i < numSiblings; i++) { - assertEquals(summaryEntry, mGroupManager.getGroupSummary(siblings[i])); - assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(siblings[i])); - } - - // Remove the priority notification to validate that it is removed as the alertOverride - mGroupManager.onEntryRemoved(priorityEntry); - - // verify that the alertOverride is removed when the priority notification is - assertNull(summaryGroup.alertOverride); - verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, priorityEntry, null); - verify(groupChangeListener).onGroupRemoved(any(), eq(priorityEntry.getKey())); - verify(groupChangeListener, times(max2Siblings + 2)).onGroupsChanged(); - if (numSiblings == 0) { - verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, false); - } - verifyNoMoreInteractions(groupChangeListener); - } - - @Test - public void testAlertOverrideWhenUpdatingSummaryAtEnd() { - long when = 10000; - int numSiblings = 2; - int groupAlert = Notification.GROUP_ALERT_SUMMARY; - // Create entries in an order so that the priority entry can be deemed the newest child. - NotificationEntry[] siblings = new NotificationEntry[numSiblings]; - for (int i = 0; i < numSiblings; i++) { - siblings[i] = - mGroupTestHelper.createChildNotification(groupAlert, i, "sibling", ++when); - } - NotificationEntry priorityEntry = - mGroupTestHelper.createChildNotification(groupAlert, 0, "priority", ++when); - NotificationEntry summaryEntry = - mGroupTestHelper.createSummaryNotification(groupAlert, 0, "summary", ++when); - - // The priority entry is an important conversation. - when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry))) - .thenReturn(PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON); - - // Register a listener so we can verify that the event is sent. - OnGroupChangeListener groupChangeListener = mock(OnGroupChangeListener.class); - mGroupManager.registerGroupChangeListener(groupChangeListener); - - // Add all the entries. The order here shouldn't matter. - mGroupManager.onEntryAdded(summaryEntry); - for (int i = 0; i < numSiblings; i++) { - mGroupManager.onEntryAdded(siblings[i]); - } - mGroupManager.onEntryAdded(priorityEntry); - - int max2Siblings = Math.min(2, numSiblings); - - // Verify that the summary group has the priority child as its alertOverride - NotificationGroup summaryGroup = mGroupManager.getGroupForSummary(summaryEntry.getSbn()); - assertEquals(priorityEntry, summaryGroup.alertOverride); - verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry); - verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, true); - if (numSiblings > 1) { - verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, false); - } - verify(groupChangeListener).onGroupCreated(any(), eq(priorityEntry.getKey())); - verify(groupChangeListener).onGroupCreated(any(), eq(summaryEntry.getSbn().getGroupKey())); - verify(groupChangeListener, times(max2Siblings + 1)).onGroupsChanged(); - verifyNoMoreInteractions(groupChangeListener); - - // Verify that only the priority notification is isolated from the group - assertEquals(priorityEntry, mGroupManager.getGroupSummary(priorityEntry)); - assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(priorityEntry)); - // Verify that the siblings are NOT isolated from the group - for (int i = 0; i < numSiblings; i++) { - assertEquals(summaryEntry, mGroupManager.getGroupSummary(siblings[i])); - assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(siblings[i])); - } - - Log.d("NotificationGroupManagerLegacyTest", - "testAlertOverrideWhenUpdatingSummaryAtEnd: About to update summary"); - - StatusBarNotification oldSummarySbn = mGroupTestHelper.incrementPost(summaryEntry, 10000); - mGroupManager.onEntryUpdated(summaryEntry, oldSummarySbn); - - verify(groupChangeListener, times(max2Siblings + 2)).onGroupsChanged(); - verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, priorityEntry, null); - verifyNoMoreInteractions(groupChangeListener); - - Log.d("NotificationGroupManagerLegacyTest", - "testAlertOverrideWhenUpdatingSummaryAtEnd: About to update priority child"); - - StatusBarNotification oldPrioritySbn = mGroupTestHelper.incrementPost(priorityEntry, 10000); - mGroupManager.onEntryUpdated(priorityEntry, oldPrioritySbn); - - verify(groupChangeListener).onGroupRemoved(any(), eq(priorityEntry.getKey())); - verify(groupChangeListener, times(2)).onGroupCreated(any(), eq(priorityEntry.getKey())); - verify(groupChangeListener, times(2)) - .onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry); - verify(groupChangeListener, times(max2Siblings + 3)).onGroupsChanged(); - verifyNoMoreInteractions(groupChangeListener); - - Log.d("NotificationGroupManagerLegacyTest", - "testAlertOverrideWhenUpdatingSummaryAtEnd: Done"); - } -} 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 c896c0ad93e0..de43a1fabab6 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 @@ -178,10 +178,10 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { bubbleSbn.getNotification().contentIntent = mContentIntent; bubbleSbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; - ArrayList<NotificationEntry> activeNotifications = new ArrayList<>(); - activeNotifications.add(mNotificationRow.getEntry()); - activeNotifications.add(mBubbleNotificationRow.getEntry()); - when(mEntryManager.getVisibleNotifications()).thenReturn(activeNotifications); +// ArrayList<NotificationEntry> activeNotifications = new ArrayList<>(); +// activeNotifications.add(mNotificationRow.getEntry()); +// activeNotifications.add(mBubbleNotificationRow.getEntry()); +// when(mEntryManager.getVisibleNotifications()).thenReturn(activeNotifications); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); when(mOnUserInteractionCallback.registerFutureDismissal(eq(mNotificationRow.getEntry()), anyInt())).thenReturn(mFutureDismissalRunnable); @@ -347,9 +347,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { // The content intent should NOT be sent on click. verifyZeroInteractions(mContentIntent); - - // Notification should not be cancelled. - verify(mEntryManager, never()).performRemoveNotification(eq(sbn), any(), anyInt()); } @Test @@ -380,9 +377,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { verify(mContentIntent).getIntent(); verify(mContentIntent).isActivity(); verifyNoMoreInteractions(mContentIntent); - - // Notification should not be cancelled. - verify(mEntryManager, never()).performRemoveNotification(eq(sbn), any(), anyInt()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java index 23b14044b3e9..1ec4de9b573e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java @@ -38,7 +38,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -79,7 +79,7 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { mNotificationLockscreenUserManager); mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext, - mock(NotificationGroupManagerLegacy.class), mNotificationLockscreenUserManager, + mock(GroupExpansionManager.class), mNotificationLockscreenUserManager, mKeyguardStateController, mStatusBarStateController, mStatusBarKeyguardViewManager, mActivityStarter, mShadeController, new CommandQueue(mContext), mock(ActionClickLogger.class), mFakeExecutor)); |