Remove filtering old pipeline filtering inNotificationInterruptStateProviderImpl

Fixes: 218099854
Test: NotificationInterruptStateProviderImplTest
Change-Id: Ib9849cec349b2de5a89cc05fab638f1daeec6b71
This commit is contained in:
Jay Aliomer
2022-02-10 17:12:07 -05:00
parent 53c123b402
commit 5d1b99435c
11 changed files with 529 additions and 387 deletions

View File

@@ -16,36 +16,16 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
import static android.app.Notification.VISIBILITY_SECRET;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import androidx.annotation.MainThread;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import javax.inject.Inject;
@@ -56,171 +36,48 @@ import javax.inject.Inject;
@CoordinatorScope
public class KeyguardCoordinator implements Coordinator {
private static final String TAG = "KeyguardCoordinator";
private final Context mContext;
private final Handler mMainHandler;
private final KeyguardStateController mKeyguardStateController;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final BroadcastDispatcher mBroadcastDispatcher;
private final StatusBarStateController mStatusBarStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final HighPriorityProvider mHighPriorityProvider;
private final SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
private boolean mHideSilentNotificationsOnLockscreen;
private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
@Inject
public KeyguardCoordinator(
Context context,
@MainThread Handler mainThreadHandler,
KeyguardStateController keyguardStateController,
NotificationLockscreenUserManager lockscreenUserManager,
BroadcastDispatcher broadcastDispatcher,
StatusBarStateController statusBarStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
HighPriorityProvider highPriorityProvider,
SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider) {
mContext = context;
mMainHandler = mainThreadHandler;
mKeyguardStateController = keyguardStateController;
mLockscreenUserManager = lockscreenUserManager;
mBroadcastDispatcher = broadcastDispatcher;
SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider,
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
mStatusBarStateController = statusBarStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mHighPriorityProvider = highPriorityProvider;
mSectionHeaderVisibilityProvider = sectionHeaderVisibilityProvider;
mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider;
}
@Override
public void attach(NotifPipeline pipeline) {
readShowSilentNotificationSetting();
setupInvalidateNotifListCallbacks();
// Filter at the "finalize" stage so that views remain bound by PreparationCoordinator
pipeline.addFinalizeFilter(mNotifFilter);
mKeyguardNotificationVisibilityProvider
.addOnStateChangedListener(this::invalidateListFromFilter);
updateSectionHeadersVisibility();
}
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
final StatusBarNotification sbn = entry.getSbn();
// FILTER OUT the notification when the keyguard is showing and...
if (mKeyguardStateController.isShowing()) {
// ... user settings or the device policy manager doesn't allow lockscreen
// notifications;
if (!mLockscreenUserManager.shouldShowLockscreenNotifications()) {
return true;
}
final int currUserId = mLockscreenUserManager.getCurrentUserId();
final int notifUserId = (sbn.getUser().getIdentifier() == UserHandle.USER_ALL)
? currUserId : sbn.getUser().getIdentifier();
// ... user is in lockdown
if (mKeyguardUpdateMonitor.isUserInLockdown(currUserId)
|| mKeyguardUpdateMonitor.isUserInLockdown(notifUserId)) {
return true;
}
// ... device is in public mode and the user's settings doesn't allow
// notifications to show in public mode
if (mLockscreenUserManager.isLockscreenPublicMode(currUserId)
|| mLockscreenUserManager.isLockscreenPublicMode(notifUserId)) {
if (entry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET) {
return true;
}
if (!mLockscreenUserManager.userAllowsNotificationsInPublic(currUserId)
|| !mLockscreenUserManager.userAllowsNotificationsInPublic(
notifUserId)) {
return true;
}
}
// ... neither this notification nor its group have high enough priority
// to be shown on the lockscreen
if (entry.getParent() != null) {
final GroupEntry parent = entry.getParent();
if (priorityExceedsLockscreenShowingThreshold(parent)) {
return false;
}
}
return !priorityExceedsLockscreenShowingThreshold(entry);
}
return false;
return mKeyguardNotificationVisibilityProvider.hideNotification(entry);
}
};
private boolean priorityExceedsLockscreenShowingThreshold(ListEntry entry) {
if (entry == null) {
return false;
}
if (mHideSilentNotificationsOnLockscreen) {
return mHighPriorityProvider.isHighPriority(entry);
} else {
return entry.getRepresentativeEntry() != null
&& !entry.getRepresentativeEntry().getRanking().isAmbient();
}
}
// TODO(b/206118999): merge this class with SensitiveContentCoordinator which also depends on
// these same updates
private void setupInvalidateNotifListCallbacks() {
// register onKeyguardShowing callback
mKeyguardStateController.addCallback(mKeyguardCallback);
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
// register lockscreen settings changed callbacks:
final ContentObserver settingsObserver = new ContentObserver(mMainHandler) {
@Override
public void onChange(boolean selfChange, Uri uri) {
if (uri.equals(Settings.Secure.getUriFor(
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS))) {
readShowSilentNotificationSetting();
}
if (mKeyguardStateController.isShowing()) {
invalidateListFromFilter("Settings " + uri + " changed");
}
}
};
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS),
false,
settingsObserver,
UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
true,
settingsObserver,
UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
false,
settingsObserver);
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
false,
settingsObserver,
UserHandle.USER_ALL);
// register (maybe) public mode changed callbacks:
mStatusBarStateController.addCallback(mStatusBarStateListener);
mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mKeyguardStateController.isShowing()) {
// maybe public mode changed
invalidateListFromFilter(intent.getAction());
}
}}, new IntentFilter(Intent.ACTION_USER_SWITCHED));
}
private void invalidateListFromFilter(String reason) {
@@ -228,49 +85,10 @@ public class KeyguardCoordinator implements Coordinator {
mNotifFilter.invalidateList();
}
private void readShowSilentNotificationSetting() {
mHideSilentNotificationsOnLockscreen =
Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
1) == 0;
}
private void updateSectionHeadersVisibility() {
boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
boolean neverShowSections = mSectionHeaderVisibilityProvider.getNeverShowSectionHeaders();
boolean showSections = !onKeyguard && !neverShowSections;
mSectionHeaderVisibilityProvider.setSectionHeadersVisible(showSections);
}
private final KeyguardStateController.Callback mKeyguardCallback =
new KeyguardStateController.Callback() {
@Override
public void onUnlockedChanged() {
invalidateListFromFilter("onUnlockedChanged");
}
@Override
public void onKeyguardShowingChanged() {
invalidateListFromFilter("onKeyguardShowingChanged");
}
};
private final StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
public void onStateChanged(int newState) {
// maybe public mode changed
invalidateListFromFilter("onStatusBarStateChanged");
}
};
private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@Override
public void onStrongAuthStateChanged(int userId) {
// maybe lockdown mode changed
invalidateListFromFilter("onStrongAuthStateChanged");
}
};
}

View File

@@ -0,0 +1,186 @@
package com.android.systemui.statusbar.notification.interruption
import android.app.Notification
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
import android.os.UserHandle
import android.provider.Settings
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.CoreStartable
import com.android.systemui.broadcast.BroadcastDispatcher
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.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.ListenerSet
import java.util.function.Consumer
import javax.inject.Inject
/**
* Determines if notifications should be visible based on the state of the keyguard
*/
class KeyguardNotificationVisibilityProvider @Inject constructor(
context: Context,
@Main private val handler: Handler,
private val keyguardStateController: KeyguardStateController,
private val lockscreenUserManager: NotificationLockscreenUserManager,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val highPriorityProvider: HighPriorityProvider,
private val statusBarStateController: StatusBarStateController,
private val broadcastDispatcher: BroadcastDispatcher
) : CoreStartable(context) {
private val onStateChangedListeners = ListenerSet<Consumer<String>>()
private var hideSilentNotificationsOnLockscreen: Boolean = false
override fun start() {
readShowSilentNotificationSetting()
keyguardStateController.addCallback(object : KeyguardStateController.Callback {
override fun onUnlockedChanged() {
notifyStateChanged("onUnlockedChanged")
}
override fun onKeyguardShowingChanged() {
notifyStateChanged("onKeyguardShowingChanged")
}
})
keyguardUpdateMonitor.registerCallback(object : KeyguardUpdateMonitorCallback() {
override fun onStrongAuthStateChanged(userId: Int) {
notifyStateChanged("onStrongAuthStateChanged")
}
})
// register lockscreen settings changed callbacks:
val settingsObserver: ContentObserver = object : ContentObserver(handler) {
override fun onChange(selfChange: Boolean, uri: Uri) {
if (keyguardStateController.isShowing) {
notifyStateChanged("Settings $uri changed")
}
}
}
mContext.contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS),
false,
settingsObserver,
UserHandle.USER_ALL)
mContext.contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
true,
settingsObserver,
UserHandle.USER_ALL)
mContext.contentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
false,
settingsObserver)
mContext.contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
false,
settingsObserver,
UserHandle.USER_ALL)
// register (maybe) public mode changed callbacks:
statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
override fun onStateChanged(state: Int) {
notifyStateChanged("onStatusBarStateChanged")
}
})
broadcastDispatcher.registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (keyguardStateController.isShowing()) {
// maybe public mode changed
notifyStateChanged(intent.action)
}
}
}, IntentFilter(Intent.ACTION_USER_SWITCHED))
}
fun addOnStateChangedListener(listener: Consumer<String>) {
onStateChangedListeners.addIfAbsent(listener)
}
fun removeOnStateChangedListener(listener: Consumer<String>) {
onStateChangedListeners.remove(listener)
}
private fun notifyStateChanged(reason: String) {
onStateChangedListeners.forEach({ it.accept(reason) })
}
/**
* Determines if the given notification should be hidden based on the current keyguard state.
* If Listener#onKeyguardStateChanged is invoked, the results of this method may no longer
* be valid, and so should be re-queried
*/
fun hideNotification(entry: NotificationEntry): Boolean {
val sbn = entry.sbn
// FILTER OUT the notification when the keyguard is showing and...
if (keyguardStateController.isShowing()) {
// ... user settings or the device policy manager doesn't allow lockscreen
// notifications;
if (!lockscreenUserManager.shouldShowLockscreenNotifications()) {
return true
}
val currUserId: Int = lockscreenUserManager.getCurrentUserId()
val notifUserId =
if (sbn.user.identifier == UserHandle.USER_ALL) currUserId
else sbn.user.identifier
// ... user is in lockdown
if (keyguardUpdateMonitor.isUserInLockdown(currUserId) ||
keyguardUpdateMonitor.isUserInLockdown(notifUserId)) {
return true
}
// ... device is in public mode and the user's settings doesn't allow
// notifications to show in public mode
if (lockscreenUserManager.isLockscreenPublicMode(currUserId) ||
lockscreenUserManager.isLockscreenPublicMode(notifUserId)) {
if (entry.ranking.lockscreenVisibilityOverride == Notification.VISIBILITY_SECRET) {
return true
}
if (!lockscreenUserManager.userAllowsNotificationsInPublic(currUserId) ||
!lockscreenUserManager.userAllowsNotificationsInPublic(
notifUserId)) {
return true
}
}
// ... neither this notification nor its group have high enough priority
// to be shown on the lockscreen
if (entry.parent != null) {
val parent = entry.parent
if (priorityExceedsLockscreenShowingThreshold(parent)) {
return false
}
}
return !priorityExceedsLockscreenShowingThreshold(entry)
}
return false
}
private fun priorityExceedsLockscreenShowingThreshold(entry: ListEntry?): Boolean =
when {
entry == null -> false
hideSilentNotificationsOnLockscreen -> highPriorityProvider.isHighPriority(entry)
else -> entry.representativeEntry?.ranking?.isAmbient == false
}
private fun readShowSilentNotificationSetting() {
hideSilentNotificationsOnLockscreen = Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
1) == 0
}
}

View File

@@ -211,6 +211,14 @@ class NotificationInterruptLogger @Inject constructor(
"Pulsing: $str1"
})
}
fun keyguardHideNotification(key: String) {
hunBuffer.log(TAG, DEBUG, {
str1 = key
}, {
"Keyguard Hide Notification: $str1"
})
}
}
private const val TAG = "InterruptionStateProvider"

View File

@@ -36,6 +36,7 @@ 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.StatusBarState;
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.policy.BatteryController;
@@ -66,6 +67,8 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
private final ContentObserver mHeadsUpObserver;
private final HeadsUpManager mHeadsUpManager;
private final NotificationInterruptLogger mLogger;
private final NotifPipelineFlags mFlags;
private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
@VisibleForTesting
protected boolean mUseHeadsUp = false;
@@ -81,7 +84,9 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
StatusBarStateController statusBarStateController,
HeadsUpManager headsUpManager,
NotificationInterruptLogger logger,
@Main Handler mainHandler) {
@Main Handler mainHandler,
NotifPipelineFlags flags,
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
mContentResolver = contentResolver;
mPowerManager = powerManager;
mDreamManager = dreamManager;
@@ -91,6 +96,8 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
mStatusBarStateController = statusBarStateController;
mHeadsUpManager = headsUpManager;
mLogger = logger;
mFlags = flags;
mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider;
mHeadsUpObserver = new ContentObserver(mainHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -282,7 +289,7 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
private boolean canAlertCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
if (mNotificationFilter.shouldFilterOut(entry)) {
if (!mFlags.isNewPipelineEnabled() && mNotificationFilter.shouldFilterOut(entry)) {
mLogger.logNoAlertingFilteredOut(sbn);
return false;
}
@@ -305,6 +312,11 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
if (mKeyguardNotificationVisibilityProvider.hideNotification(entry)) {
mLogger.keyguardHideNotification(entry.getKey());
return false;
}
return true;
}

View File

@@ -16,18 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
import static android.app.Notification.VISIBILITY_PUBLIC;
import static android.app.Notification.VISIBILITY_SECRET;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Handler;
import android.os.UserHandle;
@@ -39,20 +29,16 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
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.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -66,13 +52,13 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
@Mock private Handler mMainHandler;
@Mock private KeyguardStateController mKeyguardStateController;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private HighPriorityProvider mHighPriorityProvider;
@Mock private SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
@Mock private NotifPipeline mNotifPipeline;
@Mock private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
private NotificationEntry mEntry;
private NotifFilter mKeyguardFilter;
@@ -81,9 +67,9 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
KeyguardCoordinator keyguardCoordinator = new KeyguardCoordinator(
mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
mBroadcastDispatcher, mStatusBarStateController,
mKeyguardUpdateMonitor, mHighPriorityProvider, mSectionHeaderVisibilityProvider);
mStatusBarStateController,
mKeyguardUpdateMonitor, mHighPriorityProvider, mSectionHeaderVisibilityProvider,
mKeyguardNotificationVisibilityProvider);
mEntry = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID))
@@ -94,171 +80,4 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
verify(mNotifPipeline, times(1)).addFinalizeFilter(filterCaptor.capture());
mKeyguardFilter = filterCaptor.getValue();
}
@Test
public void unfilteredState() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// THEN don't filter out the entry
assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
public void keyguardNotShowing() {
// GIVEN the lockscreen isn't showing
setupUnfilteredState(mEntry);
when(mKeyguardStateController.isShowing()).thenReturn(false);
// THEN don't filter out the entry
assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
public void doNotShowLockscreenNotifications() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// WHEN we shouldn't show any lockscreen notifications
when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
public void lockdown() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// WHEN the notification's user is in lockdown:
when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
// THEN filter out the entry
assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
public void publicMode_settingsDisallow() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// WHEN the notification's user is in public mode and settings are configured to disallow
// notifications in public mode
when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(true);
when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
.thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
public void publicMode_notifDisallowed() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// WHEN the notification's user is in public mode and settings are configured to disallow
// notifications in public mode
when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(true);
mEntry.setRanking(new RankingBuilder()
.setKey(mEntry.getKey())
.setVisibilityOverride(VISIBILITY_SECRET).build());
// THEN filter out the entry
assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
public void doesNotExceedThresholdToShow() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// WHEN the notification doesn't exceed the threshold to show on the lockscreen
mEntry.setRanking(new RankingBuilder()
.setKey(mEntry.getKey())
.setImportance(IMPORTANCE_MIN)
.build());
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
}
@Test
public void summaryExceedsThresholdToShow() {
// GIVEN the notification doesn't exceed the threshold to show on the lockscreen
// but it's part of a group (has a parent)
final NotificationEntry entryWithParent = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID))
.build();
final GroupEntry parent = new GroupEntryBuilder()
.setKey("test_group_key")
.setSummary(new NotificationEntryBuilder()
.setImportance(IMPORTANCE_HIGH)
.build())
.addChild(entryWithParent)
.build();
setupUnfilteredState(entryWithParent);
entryWithParent.setRanking(new RankingBuilder()
.setKey(entryWithParent.getKey())
.setImportance(IMPORTANCE_MIN)
.build());
// WHEN its parent does exceed threshold tot show on the lockscreen
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
// THEN don't filter out the entry
assertFalse(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
// WHEN its parent doesn't exceed threshold to show on lockscreen
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
modifyEntry(parent.getSummary(), builder -> builder
.setImportance(IMPORTANCE_MIN)
.done());
// THEN filter out the entry
assertTrue(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
}
/**
* setup a state where the notification will not be filtered by the
* KeyguardNotificationCoordinator when the keyguard is showing.
*/
private void setupUnfilteredState(NotificationEntry entry) {
// keyguard is showing
when(mKeyguardStateController.isShowing()).thenReturn(true);
// show notifications on the lockscreen
when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true);
// neither the current user nor the notification's user is in lockdown
when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
// not in public mode
when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(false);
// entry's ranking - should show on all lockscreens
// + priority of the notification exceeds the threshold to be shown on the lockscreen
entry.setRanking(new RankingBuilder()
.setKey(mEntry.getKey())
.setVisibilityOverride(VISIBILITY_PUBLIC)
.setImportance(IMPORTANCE_HIGH)
.build());
// settings allows notifications in public mode
when(mLockscreenUserManager.userAllowsNotificationsInPublic(CURR_USER_ID)).thenReturn(true);
when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
.thenReturn(true);
// notification doesn't have a summary
// notification is high priority, so it shouldn't be filtered
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
}
}

View File

@@ -0,0 +1,262 @@
/*
* Copyright (C) 2022 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 android.app.Notification.VISIBILITY_PUBLIC;
import static android.app.Notification.VISIBILITY_SECRET;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.os.Handler;
import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
private static final int NOTIF_USER_ID = 0;
private static final int CURR_USER_ID = 1;
@Mock
private Handler mMainHandler;
@Mock private KeyguardStateController mKeyguardStateController;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private HighPriorityProvider mHighPriorityProvider;
@Mock private SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
@Mock private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
private NotificationEntry mEntry;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
// TODO refactor the test of KeyguardNotificationVisibilityProvider out
mKeyguardNotificationVisibilityProvider = spy(new KeyguardNotificationVisibilityProvider(
mContext,
mMainHandler,
mKeyguardStateController,
mLockscreenUserManager,
mKeyguardUpdateMonitor,
mHighPriorityProvider,
mStatusBarStateController,
mBroadcastDispatcher
));
mEntry = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID))
.build();
}
@Test
public void unfilteredState() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// THEN don't filter out the entry
assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
}
@Test
public void keyguardNotShowing() {
// GIVEN the lockscreen isn't showing
setupUnfilteredState(mEntry);
when(mKeyguardStateController.isShowing()).thenReturn(false);
// THEN don't filter out the entry
assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
}
@Test
public void doNotShowLockscreenNotifications() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// WHEN we shouldn't show any lockscreen notifications
when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
}
@Test
public void lockdown() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// WHEN the notification's user is in lockdown:
when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
}
@Test
public void publicMode_settingsDisallow() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// WHEN the notification's user is in public mode and settings are configured to disallow
// notifications in public mode
when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(true);
when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
.thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
}
@Test
public void publicMode_notifDisallowed() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// WHEN the notification's user is in public mode and settings are configured to disallow
// notifications in public mode
when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(true);
mEntry.setRanking(new RankingBuilder()
.setKey(mEntry.getKey())
.setVisibilityOverride(VISIBILITY_SECRET).build());
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
}
@Test
public void doesNotExceedThresholdToShow() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// WHEN the notification doesn't exceed the threshold to show on the lockscreen
mEntry.setRanking(new RankingBuilder()
.setKey(mEntry.getKey())
.setImportance(IMPORTANCE_MIN)
.build());
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
}
@Test
public void summaryExceedsThresholdToShow() {
// GIVEN the notification doesn't exceed the threshold to show on the lockscreen
// but it's part of a group (has a parent)
final NotificationEntry entryWithParent = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID))
.build();
final GroupEntry parent = new GroupEntryBuilder()
.setKey("test_group_key")
.setSummary(new NotificationEntryBuilder()
.setImportance(IMPORTANCE_HIGH)
.build())
.addChild(entryWithParent)
.build();
setupUnfilteredState(entryWithParent);
entryWithParent.setRanking(new RankingBuilder()
.setKey(entryWithParent.getKey())
.setImportance(IMPORTANCE_MIN)
.build());
// WHEN its parent does exceed threshold tot show on the lockscreen
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
// THEN don't filter out the entry
assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(entryWithParent));
// WHEN its parent doesn't exceed threshold to show on lockscreen
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
modifyEntry(parent.getSummary(), builder -> builder
.setImportance(IMPORTANCE_MIN)
.done());
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(entryWithParent));
}
/**
* setup a state where the notification will not be filtered by the
* KeyguardNotificationCoordinator when the keyguard is showing.
*/
private void setupUnfilteredState(NotificationEntry entry) {
// keyguard is showing
when(mKeyguardStateController.isShowing()).thenReturn(true);
// show notifications on the lockscreen
when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true);
// neither the current user nor the notification's user is in lockdown
when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
// not in public mode
when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(false);
// entry's ranking - should show on all lockscreens
// + priority of the notification exceeds the threshold to be shown on the lockscreen
entry.setRanking(new RankingBuilder()
.setKey(mEntry.getKey())
.setVisibilityOverride(VISIBILITY_PUBLIC)
.setImportance(IMPORTANCE_HIGH)
.build());
// settings allows notifications in public mode
when(mLockscreenUserManager.userAllowsNotificationsInPublic(CURR_USER_ID)).thenReturn(true);
when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
.thenReturn(true);
// notification doesn't have a summary
// notification is high priority, so it shouldn't be filtered
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
}
}

View File

@@ -30,6 +30,9 @@ 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.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
@@ -48,6 +51,7 @@ import androidx.test.filters.SmallTest;
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;
@@ -86,6 +90,10 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
BatteryController mBatteryController;
@Mock
Handler mMockHandler;
@Mock
NotifPipelineFlags mFlags;
@Mock
KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
@@ -104,8 +112,9 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
mStatusBarStateController,
mHeadsUpManager,
mLogger,
mMockHandler);
mMockHandler,
mFlags,
mKeyguardNotificationVisibilityProvider);
mNotifInterruptionStateProvider.mUseHeadsUp = true;
}
@@ -193,6 +202,16 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
@Test
public void testDoNotRunFilterOnNewPipeline() {
when(mFlags.isNewPipelineEnabled()).thenReturn(true);
// WHEN this entry should be filtered out
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
mNotifInterruptionStateProvider.shouldHeadsUp(entry);
verify(mFlags, times(1)).isNewPipelineEnabled();
verify(mNotificationFilter, times(0)).shouldFilterOut(eq(entry));
}
@Test
public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException {
// GIVEN state for "heads up when awake" is true

View File

@@ -131,6 +131,7 @@ import com.android.systemui.statusbar.notification.collection.legacy.VisualStabi
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -309,7 +310,9 @@ public class CentralSurfacesTest extends SysuiTestCase {
mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter,
mStatusBarStateController, mBatteryController, mHeadsUpManager,
mock(NotificationInterruptLogger.class),
new Handler(TestableLooper.get(this).getLooper()));
new Handler(TestableLooper.get(this).getLooper()),
mock(NotifPipelineFlags.class),
mock(KeyguardNotificationVisibilityProvider.class));
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -994,9 +997,12 @@ public class CentralSurfacesTest extends SysuiTestCase {
BatteryController batteryController,
HeadsUpManager headsUpManager,
NotificationInterruptLogger logger,
Handler mainHandler) {
Handler mainHandler,
NotifPipelineFlags flags,
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
super(contentResolver, powerManager, dreamManager, ambientDisplayConfiguration, filter,
batteryController, controller, headsUpManager, logger, mainHandler);
batteryController, controller, headsUpManager, logger, mainHandler,
flags, keyguardNotificationVisibilityProvider);
mUseHeadsUp = true;
}
}

View File

@@ -98,6 +98,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
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.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -343,7 +344,9 @@ public class BubblesTest extends SysuiTestCase {
mock(BatteryController.class),
mock(HeadsUpManager.class),
mock(NotificationInterruptLogger.class),
mock(Handler.class)
mock(Handler.class),
mock(NotifPipelineFlags.class),
mock(KeyguardNotificationVisibilityProvider.class)
);
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);

View File

@@ -85,6 +85,7 @@ import com.android.systemui.statusbar.notification.collection.legacy.Notificatio
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.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -309,7 +310,9 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mock(BatteryController.class),
mock(HeadsUpManager.class),
mock(NotificationInterruptLogger.class),
mock(Handler.class)
mock(Handler.class),
mock(NotifPipelineFlags.class),
mock(KeyguardNotificationVisibilityProvider.class)
);
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(true);
when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);

View File

@@ -23,7 +23,9 @@ import android.os.PowerManager;
import android.service.dreams.IDreamManager;
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.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -42,7 +44,9 @@ public class TestableNotificationInterruptStateProviderImpl
BatteryController batteryController,
HeadsUpManager headsUpManager,
NotificationInterruptLogger logger,
Handler mainHandler) {
Handler mainHandler,
NotifPipelineFlags flags,
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
super(contentResolver,
powerManager,
dreamManager,
@@ -52,7 +56,9 @@ public class TestableNotificationInterruptStateProviderImpl
statusBarStateController,
headsUpManager,
logger,
mainHandler);
mainHandler,
flags,
keyguardNotificationVisibilityProvider);
mUseHeadsUp = true;
}
}