Merge changes from topic "dedupe-lockscreen" into sc-dev
* changes: Dedupe smartspace and notification content on lockscreen Break circular dependencies in notif code
This commit is contained in:
@@ -49,4 +49,6 @@
|
|||||||
<bool name="flag_ongoing_call_status_bar_chip">true</bool>
|
<bool name="flag_ongoing_call_status_bar_chip">true</bool>
|
||||||
|
|
||||||
<bool name="flag_smartspace">false</bool>
|
<bool name="flag_smartspace">false</bool>
|
||||||
|
|
||||||
|
<bool name="flag_smartspace_deduping">true</bool>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -92,4 +92,8 @@ public class FeatureFlags {
|
|||||||
public boolean isSmartspaceEnabled() {
|
public boolean isSmartspaceEnabled() {
|
||||||
return mFlagReader.isEnabled(R.bool.flag_smartspace);
|
return mFlagReader.isEnabled(R.bool.flag_smartspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSmartspaceDedupingEnabled() {
|
||||||
|
return isSmartspaceEnabled() && mFlagReader.isEnabled(R.bool.flag_smartspace_deduping);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,12 @@ public interface NotificationLockscreenUserManager {
|
|||||||
/** Adds a listener to be notified when the current user changes. */
|
/** Adds a listener to be notified when the current user changes. */
|
||||||
void addUserChangedListener(UserChangedListener listener);
|
void addUserChangedListener(UserChangedListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a [KeyguardNotificationSuppressor] that will be consulted during
|
||||||
|
* {@link #shouldShowOnKeyguard(NotificationEntry)}
|
||||||
|
*/
|
||||||
|
void addKeyguardNotificationSuppressor(KeyguardNotificationSuppressor suppressor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a listener previously registered with
|
* Removes a listener previously registered with
|
||||||
* {@link #addUserChangedListener(UserChangedListener)}
|
* {@link #addUserChangedListener(UserChangedListener)}
|
||||||
@@ -88,4 +94,9 @@ public interface NotificationLockscreenUserManager {
|
|||||||
default void onUserChanged(int userId) {}
|
default void onUserChanged(int userId) {}
|
||||||
default void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {}
|
default void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Used to hide notifications on the lockscreen */
|
||||||
|
interface KeyguardNotificationSuppressor {
|
||||||
|
boolean shouldSuppressOnKeyguard(NotificationEntry entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ public class NotificationLockscreenUserManagerImpl implements
|
|||||||
private LockPatternUtils mLockPatternUtils;
|
private LockPatternUtils mLockPatternUtils;
|
||||||
protected KeyguardManager mKeyguardManager;
|
protected KeyguardManager mKeyguardManager;
|
||||||
private int mState = StatusBarState.SHADE;
|
private int mState = StatusBarState.SHADE;
|
||||||
|
private List<KeyguardNotificationSuppressor> mKeyguardSuppressors = new ArrayList<>();
|
||||||
|
|
||||||
protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
|
protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
@@ -343,6 +344,11 @@ public class NotificationLockscreenUserManagerImpl implements
|
|||||||
Log.wtf(TAG, "mEntryManager was null!", new Throwable());
|
Log.wtf(TAG, "mEntryManager was null!", new Throwable());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < mKeyguardSuppressors.size(); i++) {
|
||||||
|
if (mKeyguardSuppressors.get(i).shouldSuppressOnKeyguard(entry)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
boolean exceedsPriorityThreshold;
|
boolean exceedsPriorityThreshold;
|
||||||
if (hideSilentNotificationsOnLockscreen()) {
|
if (hideSilentNotificationsOnLockscreen()) {
|
||||||
exceedsPriorityThreshold =
|
exceedsPriorityThreshold =
|
||||||
@@ -620,6 +626,11 @@ public class NotificationLockscreenUserManagerImpl implements
|
|||||||
mListeners.add(listener);
|
mListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addKeyguardNotificationSuppressor(KeyguardNotificationSuppressor suppressor) {
|
||||||
|
mKeyguardSuppressors.add(suppressor);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeUserChangedListener(UserChangedListener listener) {
|
public void removeUserChangedListener(UserChangedListener listener) {
|
||||||
mListeners.remove(listener);
|
mListeners.remove(listener);
|
||||||
|
|||||||
@@ -46,8 +46,9 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
|||||||
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
|
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
|
||||||
import com.android.systemui.statusbar.NotificationUiAdjustment;
|
import com.android.systemui.statusbar.NotificationUiAdjustment;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
|
|
||||||
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
|
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.NotificationGroupManagerLegacy;
|
||||||
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
|
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.CommonNotifCollection;
|
||||||
@@ -138,12 +139,11 @@ public class NotificationEntryManager implements
|
|||||||
private final LeakDetector mLeakDetector;
|
private final LeakDetector mLeakDetector;
|
||||||
private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>();
|
private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>();
|
||||||
|
|
||||||
private final KeyguardEnvironment mKeyguardEnvironment;
|
|
||||||
private final NotificationGroupManagerLegacy mGroupManager;
|
private final NotificationGroupManagerLegacy mGroupManager;
|
||||||
private final Lazy<NotificationRankingManager> mRankingManager;
|
|
||||||
private final FeatureFlags mFeatureFlags;
|
private final FeatureFlags mFeatureFlags;
|
||||||
private final ForegroundServiceDismissalFeatureController mFgsFeatureController;
|
private final ForegroundServiceDismissalFeatureController mFgsFeatureController;
|
||||||
|
|
||||||
|
private LegacyNotificationRanker mRanker = new LegacyNotificationRankerStub();
|
||||||
private NotificationPresenter mPresenter;
|
private NotificationPresenter mPresenter;
|
||||||
private RankingMap mLatestRankingMap;
|
private RankingMap mLatestRankingMap;
|
||||||
|
|
||||||
@@ -200,8 +200,6 @@ public class NotificationEntryManager implements
|
|||||||
public NotificationEntryManager(
|
public NotificationEntryManager(
|
||||||
NotificationEntryManagerLogger logger,
|
NotificationEntryManagerLogger logger,
|
||||||
NotificationGroupManagerLegacy groupManager,
|
NotificationGroupManagerLegacy groupManager,
|
||||||
Lazy<NotificationRankingManager> rankingManager,
|
|
||||||
KeyguardEnvironment keyguardEnvironment,
|
|
||||||
FeatureFlags featureFlags,
|
FeatureFlags featureFlags,
|
||||||
Lazy<NotificationRowBinder> notificationRowBinderLazy,
|
Lazy<NotificationRowBinder> notificationRowBinderLazy,
|
||||||
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
|
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
|
||||||
@@ -211,8 +209,6 @@ public class NotificationEntryManager implements
|
|||||||
) {
|
) {
|
||||||
mLogger = logger;
|
mLogger = logger;
|
||||||
mGroupManager = groupManager;
|
mGroupManager = groupManager;
|
||||||
mRankingManager = rankingManager;
|
|
||||||
mKeyguardEnvironment = keyguardEnvironment;
|
|
||||||
mFeatureFlags = featureFlags;
|
mFeatureFlags = featureFlags;
|
||||||
mNotificationRowBinderLazy = notificationRowBinderLazy;
|
mNotificationRowBinderLazy = notificationRowBinderLazy;
|
||||||
mRemoteInputManagerLazy = notificationRemoteInputManagerLazy;
|
mRemoteInputManagerLazy = notificationRemoteInputManagerLazy;
|
||||||
@@ -226,6 +222,10 @@ public class NotificationEntryManager implements
|
|||||||
notificationListener.addNotificationHandler(mNotifListener);
|
notificationListener.addNotificationHandler(mNotifListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRanker(LegacyNotificationRanker ranker) {
|
||||||
|
mRanker = ranker;
|
||||||
|
}
|
||||||
|
|
||||||
/** Adds a {@link NotificationEntryListener}. */
|
/** Adds a {@link NotificationEntryListener}. */
|
||||||
public void addNotificationEntryListener(NotificationEntryListener listener) {
|
public void addNotificationEntryListener(NotificationEntryListener listener) {
|
||||||
mNotificationEntryListeners.add(listener);
|
mNotificationEntryListeners.add(listener);
|
||||||
@@ -419,7 +419,7 @@ public class NotificationEntryManager implements
|
|||||||
|
|
||||||
mActiveNotifications.put(entry.getKey(), entry);
|
mActiveNotifications.put(entry.getKey(), entry);
|
||||||
mGroupManager.onEntryAdded(entry);
|
mGroupManager.onEntryAdded(entry);
|
||||||
updateRankingAndSort(mRankingManager.get().getRankingMap(), "addEntryInternalInternal");
|
updateRankingAndSort(mRanker.getRankingMap(), "addEntryInternalInternal");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -698,13 +698,6 @@ public class NotificationEntryManager implements
|
|||||||
|
|
||||||
updateNotifications("updateNotificationInternal");
|
updateNotifications("updateNotificationInternal");
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
// Is this for you?
|
|
||||||
boolean isForCurrentUser = mKeyguardEnvironment
|
|
||||||
.isNotificationForCurrentProfiles(notification);
|
|
||||||
Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (NotificationEntryListener listener : mNotificationEntryListeners) {
|
for (NotificationEntryListener listener : mNotificationEntryListeners) {
|
||||||
listener.onPostEntryUpdated(entry);
|
listener.onPostEntryUpdated(entry);
|
||||||
}
|
}
|
||||||
@@ -862,8 +855,7 @@ public class NotificationEntryManager implements
|
|||||||
final int len = mActiveNotifications.size();
|
final int len = mActiveNotifications.size();
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
NotificationEntry entry = mActiveNotifications.valueAt(i);
|
NotificationEntry entry = mActiveNotifications.valueAt(i);
|
||||||
final StatusBarNotification sbn = entry.getSbn();
|
if (!mRanker.isNotificationForCurrentProfiles(entry)) {
|
||||||
if (!mKeyguardEnvironment.isNotificationForCurrentProfiles(sbn)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
filtered.add(entry);
|
filtered.add(entry);
|
||||||
@@ -886,13 +878,13 @@ public class NotificationEntryManager implements
|
|||||||
|
|
||||||
/** Resorts / filters the current notification set with the current RankingMap */
|
/** Resorts / filters the current notification set with the current RankingMap */
|
||||||
public void reapplyFilterAndSort(String reason) {
|
public void reapplyFilterAndSort(String reason) {
|
||||||
updateRankingAndSort(mRankingManager.get().getRankingMap(), reason);
|
updateRankingAndSort(mRanker.getRankingMap(), reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Calls to NotificationRankingManager and updates mSortedAndFiltered */
|
/** Calls to NotificationRankingManager and updates mSortedAndFiltered */
|
||||||
private void updateRankingAndSort(@NonNull RankingMap rankingMap, String reason) {
|
private void updateRankingAndSort(@NonNull RankingMap rankingMap, String reason) {
|
||||||
mSortedAndFiltered.clear();
|
mSortedAndFiltered.clear();
|
||||||
mSortedAndFiltered.addAll(mRankingManager.get().updateRanking(
|
mSortedAndFiltered.addAll(mRanker.updateRanking(
|
||||||
rankingMap, mActiveNotifications.values(), reason));
|
rankingMap, mActiveNotifications.values(), reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,14 +27,13 @@ import android.os.RemoteException;
|
|||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.systemui.Dependency;
|
|
||||||
import com.android.systemui.ForegroundServiceController;
|
import com.android.systemui.ForegroundServiceController;
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
import com.android.systemui.media.MediaFeatureFlag;
|
import com.android.systemui.media.MediaFeatureFlag;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
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.NotificationEntry;
|
||||||
import com.android.systemui.statusbar.phone.ShadeController;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -46,68 +45,43 @@ import javax.inject.Inject;
|
|||||||
public class NotificationFilter {
|
public class NotificationFilter {
|
||||||
|
|
||||||
private final StatusBarStateController mStatusBarStateController;
|
private final StatusBarStateController mStatusBarStateController;
|
||||||
|
private final KeyguardEnvironment mKeyguardEnvironment;
|
||||||
|
private final ForegroundServiceController mForegroundServiceController;
|
||||||
|
private final NotificationLockscreenUserManager mUserManager;
|
||||||
private final Boolean mIsMediaFlagEnabled;
|
private final Boolean mIsMediaFlagEnabled;
|
||||||
|
|
||||||
private NotificationEntryManager.KeyguardEnvironment mEnvironment;
|
|
||||||
private ShadeController mShadeController;
|
|
||||||
private ForegroundServiceController mFsc;
|
|
||||||
private NotificationLockscreenUserManager mUserManager;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public NotificationFilter(
|
public NotificationFilter(
|
||||||
StatusBarStateController statusBarStateController,
|
StatusBarStateController statusBarStateController,
|
||||||
|
KeyguardEnvironment keyguardEnvironment,
|
||||||
|
ForegroundServiceController foregroundServiceController,
|
||||||
|
NotificationLockscreenUserManager userManager,
|
||||||
MediaFeatureFlag mediaFeatureFlag) {
|
MediaFeatureFlag mediaFeatureFlag) {
|
||||||
mStatusBarStateController = statusBarStateController;
|
mStatusBarStateController = statusBarStateController;
|
||||||
|
mKeyguardEnvironment = keyguardEnvironment;
|
||||||
|
mForegroundServiceController = foregroundServiceController;
|
||||||
|
mUserManager = userManager;
|
||||||
mIsMediaFlagEnabled = mediaFeatureFlag.getEnabled();
|
mIsMediaFlagEnabled = mediaFeatureFlag.getEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
private NotificationEntryManager.KeyguardEnvironment getEnvironment() {
|
|
||||||
if (mEnvironment == null) {
|
|
||||||
mEnvironment = Dependency.get(NotificationEntryManager.KeyguardEnvironment.class);
|
|
||||||
}
|
|
||||||
return mEnvironment;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShadeController getShadeController() {
|
|
||||||
if (mShadeController == null) {
|
|
||||||
mShadeController = Dependency.get(ShadeController.class);
|
|
||||||
}
|
|
||||||
return mShadeController;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ForegroundServiceController getFsc() {
|
|
||||||
if (mFsc == null) {
|
|
||||||
mFsc = Dependency.get(ForegroundServiceController.class);
|
|
||||||
}
|
|
||||||
return mFsc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private NotificationLockscreenUserManager getUserManager() {
|
|
||||||
if (mUserManager == null) {
|
|
||||||
mUserManager = Dependency.get(NotificationLockscreenUserManager.class);
|
|
||||||
}
|
|
||||||
return mUserManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the provided notification should NOT be shown right now.
|
* @return true if the provided notification should NOT be shown right now.
|
||||||
*/
|
*/
|
||||||
public boolean shouldFilterOut(NotificationEntry entry) {
|
public boolean shouldFilterOut(NotificationEntry entry) {
|
||||||
final StatusBarNotification sbn = entry.getSbn();
|
final StatusBarNotification sbn = entry.getSbn();
|
||||||
if (!(getEnvironment().isDeviceProvisioned()
|
if (!(mKeyguardEnvironment.isDeviceProvisioned()
|
||||||
|| showNotificationEvenIfUnprovisioned(sbn))) {
|
|| showNotificationEvenIfUnprovisioned(sbn))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
|
if (!mKeyguardEnvironment.isNotificationForCurrentProfiles(sbn)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getUserManager().isLockscreenPublicMode(sbn.getUserId())
|
if (mUserManager.isLockscreenPublicMode(sbn.getUserId())
|
||||||
&& (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
|
&& (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
|
||||||
|| getUserManager().shouldHideNotifications(sbn.getUserId())
|
|| mUserManager.shouldHideNotifications(sbn.getUserId())
|
||||||
|| getUserManager().shouldHideNotifications(sbn.getKey()))) {
|
|| mUserManager.shouldHideNotifications(sbn.getKey()))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,8 +97,8 @@ public class NotificationFilter {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getFsc().isDisclosureNotification(sbn)
|
if (mForegroundServiceController.isDisclosureNotification(sbn)
|
||||||
&& !getFsc().isDisclosureNeededForUser(sbn.getUserId())) {
|
&& !mForegroundServiceController.isDisclosureNeededForUser(sbn.getUserId())) {
|
||||||
// this is a foreground-service disclosure for a user that does not need to show one
|
// this is a foreground-service disclosure for a user that does not need to show one
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,6 +185,11 @@ public class NotifCollection implements Dumpable {
|
|||||||
mBuildListener = buildListener;
|
mBuildListener = buildListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @see NotifPipeline#getEntry(String) () */
|
||||||
|
NotificationEntry getEntry(String key) {
|
||||||
|
return mNotificationSet.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
/** @see NotifPipeline#getAllNotifs() */
|
/** @see NotifPipeline#getAllNotifs() */
|
||||||
Collection<NotificationEntry> getAllNotifs() {
|
Collection<NotificationEntry> getAllNotifs() {
|
||||||
Assert.isMainThread();
|
Assert.isMainThread();
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.notification.collection;
|
package com.android.systemui.statusbar.notification.collection;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
|
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
|
||||||
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
|
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
|
||||||
@@ -89,6 +91,7 @@ public class NotifPipeline implements CommonNotifCollection {
|
|||||||
*
|
*
|
||||||
* The returned collection is read-only, unsorted, unfiltered, and ungrouped.
|
* The returned collection is read-only, unsorted, unfiltered, and ungrouped.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Collection<NotificationEntry> getAllNotifs() {
|
public Collection<NotificationEntry> getAllNotifs() {
|
||||||
return mNotifCollection.getAllNotifs();
|
return mNotifCollection.getAllNotifs();
|
||||||
}
|
}
|
||||||
@@ -98,6 +101,14 @@ public class NotifPipeline implements CommonNotifCollection {
|
|||||||
mNotifCollection.addCollectionListener(listener);
|
mNotifCollection.addCollectionListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the NotificationEntry associated with [key].
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public NotificationEntry getEntry(String key) {
|
||||||
|
return mNotifCollection.getEntry(key);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a lifetime extender. Lifetime extenders can cause notifications that have been
|
* Registers a lifetime extender. Lifetime extenders can cause notifications that have been
|
||||||
* dismissed or retracted by system server to be temporarily retained in the collection.
|
* dismissed or retracted by system server to be temporarily retained in the collection.
|
||||||
|
|||||||
@@ -23,9 +23,11 @@ import android.service.notification.NotificationListenerService.Ranking
|
|||||||
import android.service.notification.NotificationListenerService.RankingMap
|
import android.service.notification.NotificationListenerService.RankingMap
|
||||||
import android.service.notification.StatusBarNotification
|
import android.service.notification.StatusBarNotification
|
||||||
import com.android.systemui.statusbar.NotificationMediaManager
|
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.NotificationEntryManagerLogger
|
||||||
import com.android.systemui.statusbar.notification.NotificationFilter
|
import com.android.systemui.statusbar.notification.NotificationFilter
|
||||||
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
|
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.legacy.NotificationGroupManagerLegacy
|
||||||
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
|
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
|
||||||
@@ -39,7 +41,6 @@ import com.android.systemui.statusbar.policy.HeadsUpManager
|
|||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.Comparator
|
|
||||||
|
|
||||||
private const val TAG = "NotifRankingManager"
|
private const val TAG = "NotifRankingManager"
|
||||||
|
|
||||||
@@ -60,10 +61,11 @@ open class NotificationRankingManager @Inject constructor(
|
|||||||
private val logger: NotificationEntryManagerLogger,
|
private val logger: NotificationEntryManagerLogger,
|
||||||
private val sectionsFeatureManager: NotificationSectionsFeatureManager,
|
private val sectionsFeatureManager: NotificationSectionsFeatureManager,
|
||||||
private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
|
private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
|
||||||
private val highPriorityProvider: HighPriorityProvider
|
private val highPriorityProvider: HighPriorityProvider,
|
||||||
) {
|
private val keyguardEnvironment: KeyguardEnvironment
|
||||||
|
) : LegacyNotificationRanker {
|
||||||
|
|
||||||
var rankingMap: RankingMap? = null
|
override var rankingMap: RankingMap? = null
|
||||||
protected set
|
protected set
|
||||||
private val mediaManager by lazy {
|
private val mediaManager by lazy {
|
||||||
mediaManagerLazy.get()
|
mediaManagerLazy.get()
|
||||||
@@ -115,7 +117,7 @@ open class NotificationRankingManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateRanking(
|
override fun updateRanking(
|
||||||
newRankingMap: RankingMap?,
|
newRankingMap: RankingMap?,
|
||||||
entries: Collection<NotificationEntry>,
|
entries: Collection<NotificationEntry>,
|
||||||
reason: String
|
reason: String
|
||||||
@@ -131,6 +133,12 @@ open class NotificationRankingManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isNotificationForCurrentProfiles(
|
||||||
|
entry: NotificationEntry
|
||||||
|
): Boolean {
|
||||||
|
return keyguardEnvironment.isNotificationForCurrentProfiles(entry.sbn)
|
||||||
|
}
|
||||||
|
|
||||||
/** Uses the [rankingComparator] to sort notifications which aren't filtered */
|
/** Uses the [rankingComparator] to sort notifications which aren't filtered */
|
||||||
private fun filterAndSortLocked(
|
private fun filterAndSortLocked(
|
||||||
entries: Collection<NotificationEntry>,
|
entries: Collection<NotificationEntry>,
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.notification.collection.coordinator;
|
package com.android.systemui.statusbar.notification.collection.coordinator;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||||
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
|
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
|
||||||
|
|
||||||
@@ -27,5 +29,5 @@ public interface Coordinator {
|
|||||||
* Called after the NewNotifPipeline is initialized.
|
* Called after the NewNotifPipeline is initialized.
|
||||||
* Coordinators should register their listeners and {@link Pluggable}s to the pipeline.
|
* Coordinators should register their listeners and {@link Pluggable}s to the pipeline.
|
||||||
*/
|
*/
|
||||||
void attach(NotifPipeline pipeline);
|
void attach(@NonNull NotifPipeline pipeline);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ public class NotifCoordinators implements Dumpable {
|
|||||||
ConversationCoordinator conversationCoordinator,
|
ConversationCoordinator conversationCoordinator,
|
||||||
PreparationCoordinator preparationCoordinator,
|
PreparationCoordinator preparationCoordinator,
|
||||||
MediaCoordinator mediaCoordinator,
|
MediaCoordinator mediaCoordinator,
|
||||||
|
SmartspaceDedupingCoordinator smartspaceDedupingCoordinator,
|
||||||
VisualStabilityCoordinator visualStabilityCoordinator) {
|
VisualStabilityCoordinator visualStabilityCoordinator) {
|
||||||
dumpManager.registerDumpable(TAG, this);
|
dumpManager.registerDumpable(TAG, this);
|
||||||
|
|
||||||
@@ -70,9 +71,14 @@ public class NotifCoordinators implements Dumpable {
|
|||||||
mCoordinators.add(appOpsCoordinator);
|
mCoordinators.add(appOpsCoordinator);
|
||||||
mCoordinators.add(deviceProvisionedCoordinator);
|
mCoordinators.add(deviceProvisionedCoordinator);
|
||||||
mCoordinators.add(bubbleCoordinator);
|
mCoordinators.add(bubbleCoordinator);
|
||||||
mCoordinators.add(mediaCoordinator);
|
|
||||||
mCoordinators.add(conversationCoordinator);
|
mCoordinators.add(conversationCoordinator);
|
||||||
|
mCoordinators.add(mediaCoordinator);
|
||||||
mCoordinators.add(visualStabilityCoordinator);
|
mCoordinators.add(visualStabilityCoordinator);
|
||||||
|
|
||||||
|
if (featureFlags.isSmartspaceDedupingEnabled()) {
|
||||||
|
mCoordinators.add(smartspaceDedupingCoordinator);
|
||||||
|
}
|
||||||
|
|
||||||
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
|
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||||
mCoordinators.add(headsUpCoordinator);
|
mCoordinators.add(headsUpCoordinator);
|
||||||
mCoordinators.add(preparationCoordinator);
|
mCoordinators.add(preparationCoordinator);
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* 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.coordinator
|
||||||
|
|
||||||
|
import android.app.smartspace.SmartspaceTarget
|
||||||
|
import android.os.Parcelable
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
|
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||||
|
import com.android.systemui.statusbar.StatusBarState
|
||||||
|
import com.android.systemui.statusbar.SysuiStatusBarStateController
|
||||||
|
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
|
||||||
|
import com.android.systemui.statusbar.notification.NotificationEntryManager
|
||||||
|
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
||||||
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||||
|
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
|
||||||
|
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
|
||||||
|
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||||
|
import com.android.systemui.util.time.SystemClock
|
||||||
|
import java.util.concurrent.TimeUnit.SECONDS
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides notifications on the lockscreen if the content of those notifications is also visible
|
||||||
|
* in smartspace. This ONLY hides the notifications on the lockscreen: if the user pulls the shade
|
||||||
|
* down or unlocks the device, then the notifications are unhidden.
|
||||||
|
*
|
||||||
|
* In addition, notifications that have recently alerted aren't filtered. Tracking this in a way
|
||||||
|
* that involves the fewest pipeline invalidations requires some unfortunately complex logic.
|
||||||
|
*/
|
||||||
|
// This class is a singleton so that the same instance can be accessed by both the old and new
|
||||||
|
// pipelines
|
||||||
|
@SysUISingleton
|
||||||
|
class SmartspaceDedupingCoordinator @Inject constructor(
|
||||||
|
private val statusBarStateController: SysuiStatusBarStateController,
|
||||||
|
private val smartspaceController: LockscreenSmartspaceController,
|
||||||
|
private val notificationEntryManager: NotificationEntryManager,
|
||||||
|
private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
|
||||||
|
private val notifPipeline: NotifPipeline,
|
||||||
|
@Main private val executor: DelayableExecutor,
|
||||||
|
private val clock: SystemClock
|
||||||
|
) : Coordinator {
|
||||||
|
private var isOnLockscreen = false
|
||||||
|
|
||||||
|
private var trackedSmartspaceTargets = mutableMapOf<String, TrackedSmartspaceTarget>()
|
||||||
|
|
||||||
|
override fun attach(pipeline: NotifPipeline) {
|
||||||
|
pipeline.addPreGroupFilter(filter)
|
||||||
|
pipeline.addCollectionListener(collectionListener)
|
||||||
|
statusBarStateController.addCallback(statusBarStateListener)
|
||||||
|
smartspaceController.addListener(this::onNewSmartspaceTargets)
|
||||||
|
|
||||||
|
// TODO (b/173126564): Remove this once the old pipeline is no longer necessary
|
||||||
|
notificationLockscreenUserManager.addKeyguardNotificationSuppressor { entry ->
|
||||||
|
isDupedWithSmartspaceContent(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
recordStatusBarState(statusBarStateController.state)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isDupedWithSmartspaceContent(entry: NotificationEntry): Boolean {
|
||||||
|
return trackedSmartspaceTargets[entry.key]?.shouldFilter ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
private val filter = object : NotifFilter("SmartspaceDedupingFilter") {
|
||||||
|
override fun shouldFilterOut(entry: NotificationEntry, now: Long): Boolean {
|
||||||
|
return isOnLockscreen && isDupedWithSmartspaceContent(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val collectionListener = object : NotifCollectionListener {
|
||||||
|
override fun onEntryAdded(entry: NotificationEntry) {
|
||||||
|
trackedSmartspaceTargets[entry.key]?.let {
|
||||||
|
updateFilterStatus(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEntryUpdated(entry: NotificationEntry) {
|
||||||
|
trackedSmartspaceTargets[entry.key]?.let {
|
||||||
|
updateFilterStatus(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
|
||||||
|
trackedSmartspaceTargets[entry.key]?.let { trackedTarget ->
|
||||||
|
cancelExceptionTimeout(trackedTarget)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val statusBarStateListener = object : StatusBarStateController.StateListener {
|
||||||
|
override fun onStateChanged(newState: Int) {
|
||||||
|
recordStatusBarState(newState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onNewSmartspaceTargets(targets: List<Parcelable>) {
|
||||||
|
var changed = false
|
||||||
|
val newMap = mutableMapOf<String, TrackedSmartspaceTarget>()
|
||||||
|
val oldMap = trackedSmartspaceTargets
|
||||||
|
|
||||||
|
for (target in targets) {
|
||||||
|
// For all targets that are SmartspaceTargets and have non-null sourceNotificationKeys
|
||||||
|
(target as? SmartspaceTarget)?.sourceNotificationKey?.let { key ->
|
||||||
|
val trackedTarget = oldMap.getOrElse(key) {
|
||||||
|
TrackedSmartspaceTarget(key)
|
||||||
|
}
|
||||||
|
newMap[key] = trackedTarget
|
||||||
|
changed = changed || updateFilterStatus(trackedTarget)
|
||||||
|
}
|
||||||
|
// Currently, only filter out the first target
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
for (prevKey in oldMap.keys) {
|
||||||
|
if (!newMap.containsKey(prevKey)) {
|
||||||
|
oldMap[prevKey]?.cancelTimeoutRunnable?.run()
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
filter.invalidateList()
|
||||||
|
notificationEntryManager.updateNotifications("Smartspace targets changed")
|
||||||
|
}
|
||||||
|
|
||||||
|
trackedSmartspaceTargets = newMap
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the target's alert exception status has changed
|
||||||
|
*/
|
||||||
|
private fun updateFilterStatus(target: TrackedSmartspaceTarget): Boolean {
|
||||||
|
val prevShouldFilter = target.shouldFilter
|
||||||
|
|
||||||
|
val entry = notifPipeline.getEntry(target.key)
|
||||||
|
if (entry != null) {
|
||||||
|
updateAlertException(target, entry)
|
||||||
|
|
||||||
|
target.shouldFilter = !hasRecentlyAlerted(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return target.shouldFilter != prevShouldFilter && isOnLockscreen
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateAlertException(target: TrackedSmartspaceTarget, entry: NotificationEntry) {
|
||||||
|
val now = clock.currentTimeMillis()
|
||||||
|
val alertExceptionExpires = entry.ranking.lastAudiblyAlertedMillis + ALERT_WINDOW
|
||||||
|
|
||||||
|
if (alertExceptionExpires != target.alertExceptionExpires &&
|
||||||
|
alertExceptionExpires > now) {
|
||||||
|
// If we got here, the target is subject to a new alert exception window, so we
|
||||||
|
// should update our timeout to fire at the end of the new window
|
||||||
|
|
||||||
|
target.cancelTimeoutRunnable?.run()
|
||||||
|
target.alertExceptionExpires = alertExceptionExpires
|
||||||
|
target.cancelTimeoutRunnable = executor.executeDelayed({
|
||||||
|
target.cancelTimeoutRunnable = null
|
||||||
|
target.shouldFilter = true
|
||||||
|
filter.invalidateList()
|
||||||
|
notificationEntryManager.updateNotifications("deduping timeout expired")
|
||||||
|
}, alertExceptionExpires - now)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cancelExceptionTimeout(target: TrackedSmartspaceTarget) {
|
||||||
|
target.cancelTimeoutRunnable?.run()
|
||||||
|
target.cancelTimeoutRunnable = null
|
||||||
|
target.alertExceptionExpires = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recordStatusBarState(newState: Int) {
|
||||||
|
val wasOnLockscreen = isOnLockscreen
|
||||||
|
isOnLockscreen = newState == StatusBarState.KEYGUARD
|
||||||
|
|
||||||
|
if (isOnLockscreen != wasOnLockscreen) {
|
||||||
|
filter.invalidateList()
|
||||||
|
// No need to call notificationEntryManager.updateNotifications; something else already
|
||||||
|
// does it for us when the keyguard state changes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hasRecentlyAlerted(entry: NotificationEntry): Boolean {
|
||||||
|
return clock.currentTimeMillis() - entry.ranking.lastAudiblyAlertedMillis <= ALERT_WINDOW
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TrackedSmartspaceTarget(
|
||||||
|
val key: String
|
||||||
|
) {
|
||||||
|
var cancelTimeoutRunnable: Runnable? = null
|
||||||
|
var alertExceptionExpires: Long = 0
|
||||||
|
var shouldFilter = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ALERT_WINDOW = SECONDS.toMillis(30)
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
|
package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
|
|
||||||
@@ -45,5 +47,5 @@ public abstract class NotifFilter extends Pluggable<NotifFilter> {
|
|||||||
* various entries against.
|
* various entries against.
|
||||||
* @return True if the notif should be removed from the list
|
* @return True if the notif should be removed from the list
|
||||||
*/
|
*/
|
||||||
public abstract boolean shouldFilterOut(NotificationEntry entry, long now);
|
public abstract boolean shouldFilterOut(@NonNull NotificationEntry entry, long now);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ import com.android.systemui.statusbar.notification.NotificationEntryManagerLogge
|
|||||||
import com.android.systemui.statusbar.notification.collection.NotifCollection;
|
import com.android.systemui.statusbar.notification.collection.NotifCollection;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
|
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
|
|
||||||
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
|
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
|
||||||
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
|
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.NotificationRowBinder;
|
||||||
@@ -100,8 +99,6 @@ public interface NotificationsModule {
|
|||||||
static NotificationEntryManager provideNotificationEntryManager(
|
static NotificationEntryManager provideNotificationEntryManager(
|
||||||
NotificationEntryManagerLogger logger,
|
NotificationEntryManagerLogger logger,
|
||||||
NotificationGroupManagerLegacy groupManager,
|
NotificationGroupManagerLegacy groupManager,
|
||||||
Lazy<NotificationRankingManager> rankingManager,
|
|
||||||
NotificationEntryManager.KeyguardEnvironment keyguardEnvironment,
|
|
||||||
FeatureFlags featureFlags,
|
FeatureFlags featureFlags,
|
||||||
Lazy<NotificationRowBinder> notificationRowBinderLazy,
|
Lazy<NotificationRowBinder> notificationRowBinderLazy,
|
||||||
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
|
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
|
||||||
@@ -111,8 +108,6 @@ public interface NotificationsModule {
|
|||||||
return new NotificationEntryManager(
|
return new NotificationEntryManager(
|
||||||
logger,
|
logger,
|
||||||
groupManager,
|
groupManager,
|
||||||
rankingManager,
|
|
||||||
keyguardEnvironment,
|
|
||||||
featureFlags,
|
featureFlags,
|
||||||
notificationRowBinderLazy,
|
notificationRowBinderLazy,
|
||||||
notificationRemoteInputManagerLazy,
|
notificationRemoteInputManagerLazy,
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.notification.init
|
package com.android.systemui.statusbar.notification.init
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.service.notification.StatusBarNotification
|
import android.service.notification.StatusBarNotification
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.people.widget.PeopleSpaceWidgetManager
|
import com.android.systemui.people.widget.PeopleSpaceWidgetManager
|
||||||
@@ -30,6 +29,7 @@ import com.android.systemui.statusbar.notification.NotificationClicker
|
|||||||
import com.android.systemui.statusbar.notification.NotificationEntryManager
|
import com.android.systemui.statusbar.notification.NotificationEntryManager
|
||||||
import com.android.systemui.statusbar.notification.NotificationListController
|
import com.android.systemui.statusbar.notification.NotificationListController
|
||||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
||||||
|
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
|
||||||
import com.android.systemui.statusbar.notification.collection.TargetSdkResolver
|
import com.android.systemui.statusbar.notification.collection.TargetSdkResolver
|
||||||
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
|
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
|
||||||
import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer
|
import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer
|
||||||
@@ -59,10 +59,10 @@ import javax.inject.Inject
|
|||||||
*/
|
*/
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
class NotificationsControllerImpl @Inject constructor(
|
class NotificationsControllerImpl @Inject constructor(
|
||||||
private val context: Context,
|
|
||||||
private val featureFlags: FeatureFlags,
|
private val featureFlags: FeatureFlags,
|
||||||
private val notificationListener: NotificationListener,
|
private val notificationListener: NotificationListener,
|
||||||
private val entryManager: NotificationEntryManager,
|
private val entryManager: NotificationEntryManager,
|
||||||
|
private val legacyRanker: NotificationRankingManager,
|
||||||
private val notifPipeline: Lazy<NotifPipeline>,
|
private val notifPipeline: Lazy<NotifPipeline>,
|
||||||
private val targetSdkResolver: TargetSdkResolver,
|
private val targetSdkResolver: TargetSdkResolver,
|
||||||
private val newNotifPipeline: Lazy<NotifPipelineInitializer>,
|
private val newNotifPipeline: Lazy<NotifPipelineInitializer>,
|
||||||
@@ -128,6 +128,7 @@ class NotificationsControllerImpl @Inject constructor(
|
|||||||
groupManagerLegacy.get().setHeadsUpManager(headsUpManager)
|
groupManagerLegacy.get().setHeadsUpManager(headsUpManager)
|
||||||
groupAlertTransferHelper.setHeadsUpManager(headsUpManager)
|
groupAlertTransferHelper.setHeadsUpManager(headsUpManager)
|
||||||
|
|
||||||
|
entryManager.setRanker(legacyRanker)
|
||||||
entryManager.attach(notificationListener)
|
entryManager.attach(notificationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar;
|
package com.android.systemui.statusbar;
|
||||||
|
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
import static android.content.Intent.ACTION_USER_SWITCHED;
|
import static android.content.Intent.ACTION_USER_SWITCHED;
|
||||||
|
|
||||||
|
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
|
||||||
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
|
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
|
||||||
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_PEOPLE;
|
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_PEOPLE;
|
||||||
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
|
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
|
||||||
@@ -55,6 +57,7 @@ import com.android.systemui.Dependency;
|
|||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
|
import com.android.systemui.statusbar.NotificationLockscreenUserManager.KeyguardNotificationSuppressor;
|
||||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
||||||
@@ -383,13 +386,44 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
|
|||||||
assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(entry));
|
assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeyguardNotificationSuppressors() {
|
||||||
|
// GIVEN a notification that should be shown on the lockscreen
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
|
||||||
|
final NotificationEntry entry = new NotificationEntryBuilder()
|
||||||
|
.setImportance(IMPORTANCE_HIGH)
|
||||||
|
.build();
|
||||||
|
entry.setBucket(BUCKET_ALERTING);
|
||||||
|
|
||||||
|
// WHEN a suppressor is added that filters out all entries
|
||||||
|
FakeKeyguardSuppressor suppressor = new FakeKeyguardSuppressor();
|
||||||
|
mLockscreenUserManager.addKeyguardNotificationSuppressor(suppressor);
|
||||||
|
|
||||||
|
// THEN it's filtered out
|
||||||
|
assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(entry));
|
||||||
|
|
||||||
|
// WHEN the suppressor no longer filters out entries
|
||||||
|
suppressor.setShouldSuppress(false);
|
||||||
|
|
||||||
|
// THEN it's no longer filtered out
|
||||||
|
assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(entry));
|
||||||
|
}
|
||||||
|
|
||||||
private class TestNotificationLockscreenUserManager
|
private class TestNotificationLockscreenUserManager
|
||||||
extends NotificationLockscreenUserManagerImpl {
|
extends NotificationLockscreenUserManagerImpl {
|
||||||
public TestNotificationLockscreenUserManager(Context context) {
|
public TestNotificationLockscreenUserManager(Context context) {
|
||||||
super(context, mBroadcastDispatcher, mDevicePolicyManager, mUserManager,
|
super(
|
||||||
mClickNotifier, NotificationLockscreenUserManagerTest.this.mKeyguardManager,
|
context,
|
||||||
mStatusBarStateController, Handler.createAsync(Looper.myLooper()),
|
mBroadcastDispatcher,
|
||||||
mDeviceProvisionedController, mKeyguardStateController);
|
mDevicePolicyManager,
|
||||||
|
mUserManager,
|
||||||
|
mClickNotifier,
|
||||||
|
NotificationLockscreenUserManagerTest.this.mKeyguardManager,
|
||||||
|
mStatusBarStateController,
|
||||||
|
Handler.createAsync(Looper.myLooper()),
|
||||||
|
mDeviceProvisionedController,
|
||||||
|
mKeyguardStateController);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BroadcastReceiver getBaseBroadcastReceiverForTest() {
|
public BroadcastReceiver getBaseBroadcastReceiverForTest() {
|
||||||
@@ -404,4 +438,17 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
|
|||||||
return mSettingsObserver;
|
return mSettingsObserver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class FakeKeyguardSuppressor implements KeyguardNotificationSuppressor {
|
||||||
|
private boolean mShouldSuppress = true;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldSuppressOnKeyguard(NotificationEntry entry) {
|
||||||
|
return mShouldSuppress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShouldSuppress(boolean shouldSuppress) {
|
||||||
|
mShouldSuppress = shouldSuppress;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,16 +190,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
|||||||
mEntryManager = new NotificationEntryManager(
|
mEntryManager = new NotificationEntryManager(
|
||||||
mLogger,
|
mLogger,
|
||||||
mGroupManager,
|
mGroupManager,
|
||||||
() -> new NotificationRankingManager(
|
|
||||||
() -> mNotificationMediaManager,
|
|
||||||
mGroupManager,
|
|
||||||
mHeadsUpManager,
|
|
||||||
mock(NotificationFilter.class),
|
|
||||||
mLogger,
|
|
||||||
mock(NotificationSectionsFeatureManager.class),
|
|
||||||
mock(PeopleNotificationIdentifier.class),
|
|
||||||
mock(HighPriorityProvider.class)),
|
|
||||||
mEnvironment,
|
|
||||||
mFeatureFlags,
|
mFeatureFlags,
|
||||||
() -> mNotificationRowBinder,
|
() -> mNotificationRowBinder,
|
||||||
() -> mRemoteInputManager,
|
() -> mRemoteInputManager,
|
||||||
@@ -207,6 +197,17 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
|||||||
mock(ForegroundServiceDismissalFeatureController.class),
|
mock(ForegroundServiceDismissalFeatureController.class),
|
||||||
mock(IStatusBarService.class)
|
mock(IStatusBarService.class)
|
||||||
);
|
);
|
||||||
|
mEntryManager.setRanker(
|
||||||
|
new NotificationRankingManager(
|
||||||
|
() -> mNotificationMediaManager,
|
||||||
|
mGroupManager,
|
||||||
|
mHeadsUpManager,
|
||||||
|
mock(NotificationFilter.class),
|
||||||
|
mLogger,
|
||||||
|
mock(NotificationSectionsFeatureManager.class),
|
||||||
|
mock(PeopleNotificationIdentifier.class),
|
||||||
|
mock(HighPriorityProvider.class),
|
||||||
|
mEnvironment));
|
||||||
mEntryManager.setUpWithPresenter(mPresenter);
|
mEntryManager.setUpWithPresenter(mPresenter);
|
||||||
mEntryManager.addNotificationEntryListener(mEntryListener);
|
mEntryManager.addNotificationEntryListener(mEntryListener);
|
||||||
mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor);
|
mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor);
|
||||||
|
|||||||
@@ -77,13 +77,16 @@ public class NotificationFilterTest extends SysuiTestCase {
|
|||||||
mock(StatusBarNotification.class);
|
mock(StatusBarNotification.class);
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
ForegroundServiceController mFsc;
|
StatusBarStateController mStatusBarStateController;
|
||||||
@Mock
|
@Mock
|
||||||
KeyguardEnvironment mEnvironment;
|
KeyguardEnvironment mEnvironment;
|
||||||
@Mock
|
@Mock
|
||||||
MediaFeatureFlag mMediaFeatureFlag;
|
ForegroundServiceController mFsc;
|
||||||
@Mock
|
@Mock
|
||||||
StatusBarStateController mStatusBarStateController;
|
NotificationLockscreenUserManager mUserManager;
|
||||||
|
@Mock
|
||||||
|
MediaFeatureFlag mMediaFeatureFlag;
|
||||||
|
|
||||||
private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
|
private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
|
||||||
|
|
||||||
private NotificationFilter mNotificationFilter;
|
private NotificationFilter mNotificationFilter;
|
||||||
@@ -127,7 +130,12 @@ public class NotificationFilterTest extends SysuiTestCase {
|
|||||||
mDependency,
|
mDependency,
|
||||||
TestableLooper.get(this));
|
TestableLooper.get(this));
|
||||||
mRow = testHelper.createRow();
|
mRow = testHelper.createRow();
|
||||||
mNotificationFilter = new NotificationFilter(mStatusBarStateController, mMediaFeatureFlag);
|
mNotificationFilter = new NotificationFilter(
|
||||||
|
mStatusBarStateController,
|
||||||
|
mEnvironment,
|
||||||
|
mFsc,
|
||||||
|
mUserManager,
|
||||||
|
mMediaFeatureFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -195,7 +203,11 @@ public class NotificationFilterTest extends SysuiTestCase {
|
|||||||
public void shouldFilterOtherNotificationWhenDisabled() {
|
public void shouldFilterOtherNotificationWhenDisabled() {
|
||||||
// GIVEN that the media feature is disabled
|
// GIVEN that the media feature is disabled
|
||||||
when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
|
when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
|
||||||
NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
|
NotificationFilter filter = new NotificationFilter(
|
||||||
|
mStatusBarStateController,
|
||||||
|
mEnvironment,
|
||||||
|
mFsc,
|
||||||
|
mUserManager,
|
||||||
mMediaFeatureFlag);
|
mMediaFeatureFlag);
|
||||||
// WHEN the media filter is asked about an entry
|
// WHEN the media filter is asked about an entry
|
||||||
NotificationEntry otherEntry = new NotificationEntryBuilder().build();
|
NotificationEntry otherEntry = new NotificationEntryBuilder().build();
|
||||||
@@ -208,7 +220,11 @@ public class NotificationFilterTest extends SysuiTestCase {
|
|||||||
public void shouldFilterOtherNotificationWhenEnabled() {
|
public void shouldFilterOtherNotificationWhenEnabled() {
|
||||||
// GIVEN that the media feature is enabled
|
// GIVEN that the media feature is enabled
|
||||||
when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
|
when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
|
||||||
NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
|
NotificationFilter filter = new NotificationFilter(
|
||||||
|
mStatusBarStateController,
|
||||||
|
mEnvironment,
|
||||||
|
mFsc,
|
||||||
|
mUserManager,
|
||||||
mMediaFeatureFlag);
|
mMediaFeatureFlag);
|
||||||
// WHEN the media filter is asked about an entry
|
// WHEN the media filter is asked about an entry
|
||||||
NotificationEntry otherEntry = new NotificationEntryBuilder().build();
|
NotificationEntry otherEntry = new NotificationEntryBuilder().build();
|
||||||
@@ -221,7 +237,11 @@ public class NotificationFilterTest extends SysuiTestCase {
|
|||||||
public void shouldFilterMediaNotificationWhenDisabled() {
|
public void shouldFilterMediaNotificationWhenDisabled() {
|
||||||
// GIVEN that the media feature is disabled
|
// GIVEN that the media feature is disabled
|
||||||
when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
|
when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
|
||||||
NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
|
NotificationFilter filter = new NotificationFilter(
|
||||||
|
mStatusBarStateController,
|
||||||
|
mEnvironment,
|
||||||
|
mFsc,
|
||||||
|
mUserManager,
|
||||||
mMediaFeatureFlag);
|
mMediaFeatureFlag);
|
||||||
// WHEN the media filter is asked about a media entry
|
// WHEN the media filter is asked about a media entry
|
||||||
final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry);
|
final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry);
|
||||||
@@ -233,7 +253,11 @@ public class NotificationFilterTest extends SysuiTestCase {
|
|||||||
public void shouldFilterMediaNotificationWhenEnabled() {
|
public void shouldFilterMediaNotificationWhenEnabled() {
|
||||||
// GIVEN that the media feature is enabled
|
// GIVEN that the media feature is enabled
|
||||||
when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
|
when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
|
||||||
NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
|
NotificationFilter filter = new NotificationFilter(
|
||||||
|
mStatusBarStateController,
|
||||||
|
mEnvironment,
|
||||||
|
mFsc,
|
||||||
|
mUserManager,
|
||||||
mMediaFeatureFlag);
|
mMediaFeatureFlag);
|
||||||
// WHEN the media filter is asked about a media entry
|
// WHEN the media filter is asked about a media entry
|
||||||
final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry);
|
final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry);
|
||||||
|
|||||||
@@ -30,9 +30,11 @@ import androidx.test.filters.SmallTest
|
|||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
|
import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
|
||||||
import com.android.systemui.statusbar.NotificationMediaManager
|
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.NotificationEntryManagerLogger
|
||||||
import com.android.systemui.statusbar.notification.NotificationFilter
|
import com.android.systemui.statusbar.notification.NotificationFilter
|
||||||
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
|
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.collection.provider.HighPriorityProvider
|
||||||
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
|
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_FULL_PERSON
|
||||||
@@ -42,7 +44,6 @@ 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_ALERTING
|
||||||
import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
|
import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
|
||||||
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
|
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
|
||||||
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
|
|
||||||
import com.android.systemui.statusbar.policy.HeadsUpManager
|
import com.android.systemui.statusbar.policy.HeadsUpManager
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
@@ -79,8 +80,10 @@ class NotificationRankingManagerTest : SysuiTestCase() {
|
|||||||
mock(NotificationEntryManagerLogger::class.java),
|
mock(NotificationEntryManagerLogger::class.java),
|
||||||
sectionsManager,
|
sectionsManager,
|
||||||
personNotificationIdentifier,
|
personNotificationIdentifier,
|
||||||
HighPriorityProvider(personNotificationIdentifier,
|
HighPriorityProvider(
|
||||||
mock(NotificationGroupManagerLegacy::class.java))
|
personNotificationIdentifier,
|
||||||
|
mock(NotificationGroupManagerLegacy::class.java)),
|
||||||
|
mock(KeyguardEnvironment::class.java)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +489,8 @@ class NotificationRankingManagerTest : SysuiTestCase() {
|
|||||||
logger: NotificationEntryManagerLogger,
|
logger: NotificationEntryManagerLogger,
|
||||||
sectionsFeatureManager: NotificationSectionsFeatureManager,
|
sectionsFeatureManager: NotificationSectionsFeatureManager,
|
||||||
peopleNotificationIdentifier: PeopleNotificationIdentifier,
|
peopleNotificationIdentifier: PeopleNotificationIdentifier,
|
||||||
highPriorityProvider: HighPriorityProvider
|
highPriorityProvider: HighPriorityProvider,
|
||||||
|
keyguardEnvironment: KeyguardEnvironment
|
||||||
) : NotificationRankingManager(
|
) : NotificationRankingManager(
|
||||||
mediaManager,
|
mediaManager,
|
||||||
groupManager,
|
groupManager,
|
||||||
@@ -495,7 +499,8 @@ class NotificationRankingManagerTest : SysuiTestCase() {
|
|||||||
logger,
|
logger,
|
||||||
sectionsFeatureManager,
|
sectionsFeatureManager,
|
||||||
peopleNotificationIdentifier,
|
peopleNotificationIdentifier,
|
||||||
highPriorityProvider
|
highPriorityProvider,
|
||||||
|
keyguardEnvironment
|
||||||
) {
|
) {
|
||||||
fun applyTestRankingMap(r: RankingMap) {
|
fun applyTestRankingMap(r: RankingMap) {
|
||||||
rankingMap = r
|
rankingMap = r
|
||||||
|
|||||||
@@ -0,0 +1,418 @@
|
|||||||
|
/*
|
||||||
|
* 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.coordinator
|
||||||
|
|
||||||
|
import android.app.smartspace.SmartspaceTarget
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.os.UserHandle
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
|
||||||
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
|
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||||
|
import com.android.systemui.statusbar.StatusBarState
|
||||||
|
import com.android.systemui.statusbar.SysuiStatusBarStateController
|
||||||
|
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
|
||||||
|
import com.android.systemui.statusbar.notification.NotificationEntryManager
|
||||||
|
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
||||||
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||||
|
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
|
||||||
|
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
|
||||||
|
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable
|
||||||
|
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
|
||||||
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.`when`
|
||||||
|
import org.mockito.Mockito.anyString
|
||||||
|
import org.mockito.Mockito.clearInvocations
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
class SmartspaceDedupingCoordinatorTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var statusBarStateController: SysuiStatusBarStateController
|
||||||
|
@Mock
|
||||||
|
private lateinit var smartspaceController: LockscreenSmartspaceController
|
||||||
|
@Mock
|
||||||
|
private lateinit var notificationEntryManager: NotificationEntryManager
|
||||||
|
@Mock
|
||||||
|
private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
|
||||||
|
@Mock
|
||||||
|
private lateinit var notifPipeline: NotifPipeline
|
||||||
|
@Mock
|
||||||
|
private lateinit var pluggableListener: Pluggable.PluggableListener<NotifFilter>
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
private lateinit var filterCaptor: ArgumentCaptor<NotifFilter>
|
||||||
|
@Captor
|
||||||
|
private lateinit var collectionListenerCaptor: ArgumentCaptor<NotifCollectionListener>
|
||||||
|
@Captor
|
||||||
|
private lateinit var stateListenerCaptor: ArgumentCaptor<StatusBarStateController.StateListener>
|
||||||
|
@Captor
|
||||||
|
private lateinit var smartspaceListenerCaptor: ArgumentCaptor<SmartspaceTargetListener>
|
||||||
|
|
||||||
|
private lateinit var filter: NotifFilter
|
||||||
|
private lateinit var collectionListener: NotifCollectionListener
|
||||||
|
private lateinit var statusBarListener: StatusBarStateController.StateListener
|
||||||
|
private lateinit var newTargetListener: SmartspaceTargetListener
|
||||||
|
|
||||||
|
private lateinit var entry1HasRecentlyAlerted: NotificationEntry
|
||||||
|
private lateinit var entry2HasNotRecentlyAlerted: NotificationEntry
|
||||||
|
private lateinit var entry3NotAssociatedWithTarget: NotificationEntry
|
||||||
|
private lateinit var entry4HasNotRecentlyAlerted: NotificationEntry
|
||||||
|
private lateinit var target1: SmartspaceTarget
|
||||||
|
private lateinit var target2: SmartspaceTarget
|
||||||
|
private lateinit var target4: SmartspaceTarget
|
||||||
|
|
||||||
|
private val clock = FakeSystemClock()
|
||||||
|
private val executor = FakeExecutor(clock)
|
||||||
|
private val now = clock.currentTimeMillis()
|
||||||
|
|
||||||
|
private lateinit var deduper: SmartspaceDedupingCoordinator
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
// Mock out some behavior
|
||||||
|
`when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||||
|
|
||||||
|
// Build the deduper
|
||||||
|
deduper = SmartspaceDedupingCoordinator(
|
||||||
|
statusBarStateController,
|
||||||
|
smartspaceController,
|
||||||
|
notificationEntryManager,
|
||||||
|
notificationLockscreenUserManager,
|
||||||
|
notifPipeline,
|
||||||
|
executor,
|
||||||
|
clock
|
||||||
|
)
|
||||||
|
|
||||||
|
// Attach the deduper and capture the listeners/filters that it registers
|
||||||
|
deduper.attach(notifPipeline)
|
||||||
|
|
||||||
|
verify(notifPipeline).addPreGroupFilter(filterCaptor.capture())
|
||||||
|
filter = filterCaptor.value
|
||||||
|
filter.setInvalidationListener(pluggableListener)
|
||||||
|
|
||||||
|
verify(notifPipeline).addCollectionListener(capture(collectionListenerCaptor))
|
||||||
|
collectionListener = collectionListenerCaptor.value
|
||||||
|
|
||||||
|
verify(statusBarStateController).addCallback(capture(stateListenerCaptor))
|
||||||
|
statusBarListener = stateListenerCaptor.value
|
||||||
|
|
||||||
|
verify(smartspaceController).addListener(capture(smartspaceListenerCaptor))
|
||||||
|
newTargetListener = smartspaceListenerCaptor.value
|
||||||
|
|
||||||
|
// Initialize some test data
|
||||||
|
entry1HasRecentlyAlerted = NotificationEntryBuilder()
|
||||||
|
.setPkg(PACKAGE_1)
|
||||||
|
.setId(11)
|
||||||
|
.setLastAudiblyAlertedMs(now - 10000)
|
||||||
|
.build()
|
||||||
|
entry2HasNotRecentlyAlerted = NotificationEntryBuilder()
|
||||||
|
.setPkg(PACKAGE_2)
|
||||||
|
.setId(22)
|
||||||
|
.build()
|
||||||
|
entry3NotAssociatedWithTarget = NotificationEntryBuilder()
|
||||||
|
.setPkg("com.test.package.3")
|
||||||
|
.setId(33)
|
||||||
|
.setLastAudiblyAlertedMs(now - 10000)
|
||||||
|
.build()
|
||||||
|
entry4HasNotRecentlyAlerted = NotificationEntryBuilder()
|
||||||
|
.setPkg(PACKAGE_2)
|
||||||
|
.setId(44)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
target1 = buildTargetFor(entry1HasRecentlyAlerted)
|
||||||
|
target2 = buildTargetFor(entry2HasNotRecentlyAlerted)
|
||||||
|
target4 = buildTargetFor(entry4HasNotRecentlyAlerted)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBasicFiltering() {
|
||||||
|
// GIVEN a few notifications
|
||||||
|
addEntries(
|
||||||
|
entry2HasNotRecentlyAlerted,
|
||||||
|
entry3NotAssociatedWithTarget,
|
||||||
|
entry4HasNotRecentlyAlerted)
|
||||||
|
|
||||||
|
// WHEN we receive smartspace targets associated with entry 2 and 3
|
||||||
|
sendTargets(target2, target4)
|
||||||
|
|
||||||
|
// THEN both pipelines are rerun
|
||||||
|
verifyPipelinesInvalidated()
|
||||||
|
|
||||||
|
// THEN the first target is filtered out, but the other ones aren't
|
||||||
|
assertTrue(filter.shouldFilterOut(entry2HasNotRecentlyAlerted, now))
|
||||||
|
assertFalse(filter.shouldFilterOut(entry3NotAssociatedWithTarget, now))
|
||||||
|
assertFalse(filter.shouldFilterOut(entry4HasNotRecentlyAlerted, now))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDoNotFilterRecentlyAlertedNotifs() {
|
||||||
|
// GIVEN one notif that recently alerted and a second that hasn't
|
||||||
|
addEntries(entry1HasRecentlyAlerted, entry2HasNotRecentlyAlerted)
|
||||||
|
|
||||||
|
// WHEN they become associated with smartspace targets
|
||||||
|
sendTargets(target1, target2)
|
||||||
|
|
||||||
|
// THEN neither is filtered (the first because it's recently alerted and the second
|
||||||
|
// because it's not in the first position
|
||||||
|
verifyPipelinesNotInvalidated()
|
||||||
|
assertFalse(filter.shouldFilterOut(entry1HasRecentlyAlerted, now))
|
||||||
|
assertFalse(filter.shouldFilterOut(entry2HasNotRecentlyAlerted, now))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFilterAlertedButNotRecentNotifs() {
|
||||||
|
// GIVEN a notification that alerted, but a very long time ago
|
||||||
|
val entryOldAlert = NotificationEntryBuilder(entry1HasRecentlyAlerted)
|
||||||
|
.setLastAudiblyAlertedMs(now - 40000)
|
||||||
|
.build()
|
||||||
|
addEntries(entryOldAlert)
|
||||||
|
|
||||||
|
// WHEN it becomes part of smartspace
|
||||||
|
val target = buildTargetFor(entryOldAlert)
|
||||||
|
sendTargets(target)
|
||||||
|
|
||||||
|
// THEN it's still filtered out (because it's not in the alert window)
|
||||||
|
verifyPipelinesInvalidated()
|
||||||
|
assertTrue(filter.shouldFilterOut(entryOldAlert, now))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testExceptionExpires() {
|
||||||
|
// GIVEN a recently-alerted notif that is the primary smartspace target
|
||||||
|
addEntries(entry1HasRecentlyAlerted)
|
||||||
|
sendTargets(target1)
|
||||||
|
clearPipelineInvocations()
|
||||||
|
|
||||||
|
// WHEN we go beyond the target's exception window
|
||||||
|
clock.advanceTime(20000)
|
||||||
|
|
||||||
|
// THEN the pipeline is invalidated
|
||||||
|
verifyPipelinesInvalidated()
|
||||||
|
assertExecutorIsClear()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testExceptionIsEventuallyFiltered() {
|
||||||
|
// GIVEN a notif that has recently alerted
|
||||||
|
addEntries(entry1HasRecentlyAlerted)
|
||||||
|
|
||||||
|
// WHEN it becomes the primary smartspace target
|
||||||
|
sendTargets(target1)
|
||||||
|
|
||||||
|
// THEN it isn't filtered out (because it recently alerted)
|
||||||
|
assertFalse(filter.shouldFilterOut(entry1HasRecentlyAlerted, now))
|
||||||
|
|
||||||
|
// WHEN we pass the alert window
|
||||||
|
clock.advanceTime(20000)
|
||||||
|
|
||||||
|
// THEN the notif is once again filtered
|
||||||
|
assertTrue(filter.shouldFilterOut(entry1HasRecentlyAlerted, clock.uptimeMillis()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testExceptionIsUpdated() {
|
||||||
|
// GIVEN a notif that has recently alerted and is the primary smartspace target
|
||||||
|
addEntries(entry1HasRecentlyAlerted)
|
||||||
|
sendTargets(target1)
|
||||||
|
clearPipelineInvocations()
|
||||||
|
assertFalse(filter.shouldFilterOut(entry1HasRecentlyAlerted, clock.uptimeMillis()))
|
||||||
|
|
||||||
|
// GIVEN the notif is updated with a much more recent alert time
|
||||||
|
NotificationEntryBuilder(entry1HasRecentlyAlerted)
|
||||||
|
.setLastAudiblyAlertedMs(clock.currentTimeMillis() - 500)
|
||||||
|
.apply(entry1HasRecentlyAlerted)
|
||||||
|
updateEntries(entry1HasRecentlyAlerted)
|
||||||
|
assertFalse(filter.shouldFilterOut(entry1HasRecentlyAlerted, clock.uptimeMillis()))
|
||||||
|
|
||||||
|
// WHEN we advance beyond the original exception window
|
||||||
|
clock.advanceTime(25000)
|
||||||
|
|
||||||
|
// THEN the original exception window doesn't fire
|
||||||
|
verifyPipelinesNotInvalidated()
|
||||||
|
assertFalse(filter.shouldFilterOut(entry1HasRecentlyAlerted, clock.uptimeMillis()))
|
||||||
|
|
||||||
|
// WHEN we advance beyond the new exception window
|
||||||
|
clock.advanceTime(4500)
|
||||||
|
|
||||||
|
// THEN the pipelines are invalidated and no more timeouts are scheduled
|
||||||
|
verifyPipelinesInvalidated()
|
||||||
|
assertExecutorIsClear()
|
||||||
|
assertTrue(filter.shouldFilterOut(entry1HasRecentlyAlerted, clock.uptimeMillis()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testReplacementIsCanceled() {
|
||||||
|
// GIVEN a single notif and smartspace target
|
||||||
|
addEntries(entry1HasRecentlyAlerted)
|
||||||
|
sendTargets(target1)
|
||||||
|
clearPipelineInvocations()
|
||||||
|
|
||||||
|
// WHEN a higher-ranked target arrives
|
||||||
|
val newerEntry = NotificationEntryBuilder()
|
||||||
|
.setPkg(PACKAGE_2)
|
||||||
|
.setId(55)
|
||||||
|
.setLastAudiblyAlertedMs(now - 1000)
|
||||||
|
.build()
|
||||||
|
val newerTarget = buildTargetFor(newerEntry)
|
||||||
|
sendTargets(newerTarget, target1)
|
||||||
|
|
||||||
|
// THEN the timeout of the other target is canceled and it is no longer filtered
|
||||||
|
assertExecutorIsClear()
|
||||||
|
assertFalse(filter.shouldFilterOut(entry1HasRecentlyAlerted, clock.uptimeMillis()))
|
||||||
|
verifyPipelinesInvalidated()
|
||||||
|
clearPipelineInvocations()
|
||||||
|
|
||||||
|
// WHEN the entry associated with the newer target later arrives
|
||||||
|
addEntries(newerEntry)
|
||||||
|
|
||||||
|
// THEN the entry is not filtered out (because it recently alerted)
|
||||||
|
assertFalse(filter.shouldFilterOut(newerEntry, clock.uptimeMillis()))
|
||||||
|
|
||||||
|
// WHEN its exception window passes
|
||||||
|
clock.advanceTime(ALERT_WINDOW)
|
||||||
|
|
||||||
|
// THEN we go back to filtering it
|
||||||
|
verifyPipelinesInvalidated()
|
||||||
|
assertExecutorIsClear()
|
||||||
|
assertTrue(filter.shouldFilterOut(newerEntry, clock.uptimeMillis()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRetractedIsCanceled() {
|
||||||
|
// GIVEN A recently alerted target
|
||||||
|
addEntries(entry1HasRecentlyAlerted)
|
||||||
|
sendTargets(target1)
|
||||||
|
|
||||||
|
// WHEN the entry is removed
|
||||||
|
removeEntries(entry1HasRecentlyAlerted)
|
||||||
|
|
||||||
|
// THEN its pending timeout is canceled
|
||||||
|
assertExecutorIsClear()
|
||||||
|
clock.advanceTime(ALERT_WINDOW)
|
||||||
|
verifyPipelinesNotInvalidated()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testTargetBeforeEntryFunctionsProperly() {
|
||||||
|
// WHEN targets are added before their entries exist
|
||||||
|
sendTargets(target2, target1)
|
||||||
|
|
||||||
|
// THEN neither is filtered out
|
||||||
|
assertFalse(filter.shouldFilterOut(entry2HasNotRecentlyAlerted, now))
|
||||||
|
assertFalse(filter.shouldFilterOut(entry1HasRecentlyAlerted, now))
|
||||||
|
|
||||||
|
// WHEN the entries are later added
|
||||||
|
addEntries(entry2HasNotRecentlyAlerted, entry1HasRecentlyAlerted)
|
||||||
|
|
||||||
|
// THEN the pipelines are not invalidated (because they're already going to be rerun)
|
||||||
|
// but the first entry is still filtered out properly.
|
||||||
|
verifyPipelinesNotInvalidated()
|
||||||
|
assertTrue(filter.shouldFilterOut(entry2HasNotRecentlyAlerted, now))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLockscreenTracking() {
|
||||||
|
// GIVEN a couple of smartspace targets that haven't alerted recently
|
||||||
|
addEntries(entry2HasNotRecentlyAlerted, entry4HasNotRecentlyAlerted)
|
||||||
|
sendTargets(target2, target4)
|
||||||
|
clearPipelineInvocations()
|
||||||
|
|
||||||
|
assertTrue(filter.shouldFilterOut(entry2HasNotRecentlyAlerted, now))
|
||||||
|
|
||||||
|
// WHEN we are no longer on the keyguard
|
||||||
|
statusBarListener.onStateChanged(StatusBarState.SHADE)
|
||||||
|
|
||||||
|
// THEN the new pipeline is invalidated (but the old one isn't because it's not
|
||||||
|
// necessary) because the notif should no longer be filtered out
|
||||||
|
verify(pluggableListener).onPluggableInvalidated(filter)
|
||||||
|
verify(notificationEntryManager, never()).updateNotifications(anyString())
|
||||||
|
assertFalse(filter.shouldFilterOut(entry2HasNotRecentlyAlerted, now))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildTargetFor(entry: NotificationEntry): SmartspaceTarget {
|
||||||
|
return SmartspaceTarget
|
||||||
|
.Builder("test", ComponentName("test", "class"), UserHandle.CURRENT)
|
||||||
|
.setSourceNotificationKey(entry.key)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addEntries(vararg entries: NotificationEntry) {
|
||||||
|
for (entry in entries) {
|
||||||
|
`when`(notifPipeline.getEntry(entry.key)).thenReturn(entry)
|
||||||
|
collectionListener.onEntryAdded(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateEntries(vararg entries: NotificationEntry) {
|
||||||
|
for (entry in entries) {
|
||||||
|
`when`(notifPipeline.getEntry(entry.key)).thenReturn(entry)
|
||||||
|
collectionListener.onEntryUpdated(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeEntries(vararg entries: NotificationEntry) {
|
||||||
|
for (entry in entries) {
|
||||||
|
`when`(notifPipeline.getEntry(entry.key)).thenReturn(null)
|
||||||
|
collectionListener.onEntryRemoved(entry, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendTargets(vararg targets: SmartspaceTarget) {
|
||||||
|
newTargetListener.onSmartspaceTargetsUpdated(targets.toMutableList())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifyPipelinesInvalidated() {
|
||||||
|
verify(pluggableListener).onPluggableInvalidated(filter)
|
||||||
|
verify(notificationEntryManager).updateNotifications(anyString())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertExecutorIsClear() {
|
||||||
|
assertEquals(0, executor.numPending())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifyPipelinesNotInvalidated() {
|
||||||
|
verify(pluggableListener, never()).onPluggableInvalidated(filter)
|
||||||
|
verify(notificationEntryManager, never()).updateNotifications(anyString())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearPipelineInvocations() {
|
||||||
|
clearInvocations(pluggableListener)
|
||||||
|
clearInvocations(notificationEntryManager)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ALERT_WINDOW = TimeUnit.SECONDS.toMillis(30)
|
||||||
|
private const val PACKAGE_1 = "com.test.package.1"
|
||||||
|
private const val PACKAGE_2 = "com.test.package.2"
|
||||||
@@ -181,16 +181,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
|
|||||||
mEntryManager = new NotificationEntryManager(
|
mEntryManager = new NotificationEntryManager(
|
||||||
mock(NotificationEntryManagerLogger.class),
|
mock(NotificationEntryManagerLogger.class),
|
||||||
mGroupMembershipManager,
|
mGroupMembershipManager,
|
||||||
() -> new NotificationRankingManager(
|
|
||||||
() -> mock(NotificationMediaManager.class),
|
|
||||||
mGroupMembershipManager,
|
|
||||||
mHeadsUpManager,
|
|
||||||
mock(NotificationFilter.class),
|
|
||||||
mock(NotificationEntryManagerLogger.class),
|
|
||||||
mock(NotificationSectionsFeatureManager.class),
|
|
||||||
mock(PeopleNotificationIdentifier.class),
|
|
||||||
mock(HighPriorityProvider.class)),
|
|
||||||
mEnvironment,
|
|
||||||
mFeatureFlags,
|
mFeatureFlags,
|
||||||
() -> mRowBinder,
|
() -> mRowBinder,
|
||||||
() -> mRemoteInputManager,
|
() -> mRemoteInputManager,
|
||||||
@@ -198,6 +188,17 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
|
|||||||
mock(ForegroundServiceDismissalFeatureController.class),
|
mock(ForegroundServiceDismissalFeatureController.class),
|
||||||
mock(IStatusBarService.class)
|
mock(IStatusBarService.class)
|
||||||
);
|
);
|
||||||
|
mEntryManager.setRanker(
|
||||||
|
new NotificationRankingManager(
|
||||||
|
() -> mock(NotificationMediaManager.class),
|
||||||
|
mGroupMembershipManager,
|
||||||
|
mHeadsUpManager,
|
||||||
|
mock(NotificationFilter.class),
|
||||||
|
mock(NotificationEntryManagerLogger.class),
|
||||||
|
mock(NotificationSectionsFeatureManager.class),
|
||||||
|
mock(PeopleNotificationIdentifier.class),
|
||||||
|
mock(HighPriorityProvider.class),
|
||||||
|
mEnvironment));
|
||||||
|
|
||||||
NotifRemoteViewCache cache = new NotifRemoteViewCacheImpl(mEntryManager);
|
NotifRemoteViewCache cache = new NotifRemoteViewCacheImpl(mEntryManager);
|
||||||
NotifBindPipeline pipeline = new NotifBindPipeline(
|
NotifBindPipeline pipeline = new NotifBindPipeline(
|
||||||
|
|||||||
Reference in New Issue
Block a user