Merge "Add Coordinators to the NewNotifPipeline"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 4cc5b21..ff4ce94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -65,8 +65,18 @@
boolean needsRedaction(NotificationEntry entry);
+ /**
+ * Has the given user chosen to allow their private (full) notifications to be shown even
+ * when the lockscreen is in "public" (secure & locked) mode?
+ */
boolean userAllowsPrivateNotificationsInPublic(int currentUserId);
+ /**
+ * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
+ * "public" (secure & locked) mode?
+ */
+ boolean userAllowsNotificationsInPublic(int userId);
+
/** Notified when the current user changes. */
interface UserChangedListener {
void onUserChanged(int userId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index f5710a8..0f3f6b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -435,7 +435,7 @@
* Has the given user chosen to allow notifications to be shown even when the lockscreen is in
* "public" (secure & locked) mode?
*/
- private boolean userAllowsNotificationsInPublic(int userHandle) {
+ public boolean userAllowsNotificationsInPublic(int userHandle) {
if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index e5f44bd..b61c1ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -36,7 +36,10 @@
import javax.inject.Inject;
import javax.inject.Singleton;
-/** Component which manages the various reasons a notification might be filtered out. */
+/** Component which manages the various reasons a notification might be filtered out.*/
+// TODO: delete NotificationFilter.java after migrating to new NotifPipeline b/145659174.
+// Notification filtering is taken care of across the different Coordinators (mostly
+// KeyguardCoordinator.java)
@Singleton
public class NotificationFilter {
@@ -109,7 +112,7 @@
return true;
}
- if (entry.isSuspended()) {
+ if (entry.getRanking().isSuspended()) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
index f9f3266..9ae3882 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
@@ -18,6 +18,8 @@
import android.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -34,7 +36,8 @@
private final List<NotificationEntry> mUnmodifiableChildren =
Collections.unmodifiableList(mChildren);
- GroupEntry(String key) {
+ @VisibleForTesting
+ public GroupEntry(String key) {
super(key);
}
@@ -52,7 +55,8 @@
return mUnmodifiableChildren;
}
- void setSummary(@Nullable NotificationEntry summary) {
+ @VisibleForTesting
+ public void setSummary(@Nullable NotificationEntry summary) {
mSummary = summary;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index dc68c4b..6ce7fd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -18,6 +18,8 @@
import android.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Abstract superclass for top-level entries, i.e. things that can appear in the final notification
* list shown to users. In practice, this means either GroupEntries or NotificationEntries.
@@ -49,7 +51,8 @@
return mParent;
}
- void setParent(@Nullable GroupEntry parent) {
+ @VisibleForTesting
+ public void setParent(@Nullable GroupEntry parent) {
mParent = parent;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java
new file mode 100644
index 0000000..898918e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
+
+/**
+ * Interface for registering callbacks to the {@link NewNotifPipeline}.
+ *
+ * This includes registering:
+ * {@link Pluggable}s to the {@link NotifListBuilder}
+ * {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s to {@link NotifCollection}
+ */
+public interface Coordinator {
+
+ /**
+ * Called after the NewNotifPipeline is initialized.
+ * Coordinators should register their {@link Pluggable}s to the notifListBuilder
+ * and their {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s
+ * to the notifCollection in this method.
+ */
+ void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
new file mode 100644
index 0000000..f5ed089
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.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.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Filters low priority and privacy-sensitive notifications from the lockscreen.
+ */
+@Singleton
+public class KeyguardCoordinator implements Coordinator {
+ private static final String TAG = "KeyguardNotificationCoordinator";
+
+ 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;
+
+ @Inject
+ public KeyguardCoordinator(
+ Context context,
+ @MainThread Handler mainThreadHandler,
+ KeyguardStateController keyguardStateController,
+ NotificationLockscreenUserManager lockscreenUserManager,
+ BroadcastDispatcher broadcastDispatcher,
+ StatusBarStateController statusBarStateController,
+ KeyguardUpdateMonitor keyguardUpdateMonitor) {
+ mContext = context;
+ mMainHandler = mainThreadHandler;
+ mKeyguardStateController = keyguardStateController;
+ mLockscreenUserManager = lockscreenUserManager;
+
+ mBroadcastDispatcher = broadcastDispatcher;
+ mStatusBarStateController = statusBarStateController;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ }
+
+ @Override
+ public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+ setupInvalidateNotifListCallbacks();
+ notifListBuilder.addFilter(mNotifFilter);
+ }
+
+ protected 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 notification isn't for the current profile
+ if (!mLockscreenUserManager.isCurrentProfile(sbn.getUserId())) {
+ return true;
+ }
+
+ // 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().getVisibilityOverride() == VISIBILITY_SECRET) {
+ return true;
+ }
+
+ if (!mLockscreenUserManager.userAllowsNotificationsInPublic(currUserId)
+ || !mLockscreenUserManager.userAllowsNotificationsInPublic(
+ notifUserId)) {
+ return true;
+ }
+ }
+
+ // ... neither this notification nor its summary have high enough priority
+ // to be shown on the lockscreen
+ // TODO: grouping hasn't happened yet (b/145134683)
+ if (entry.getParent() != null) {
+ final NotificationEntry summary = entry.getParent().getRepresentativeEntry();
+ if (priorityExceedsLockscreenShowingThreshold(summary)) {
+ return false;
+ }
+ }
+ return !priorityExceedsLockscreenShowingThreshold(entry);
+ }
+ return false;
+ }
+ };
+
+ private boolean priorityExceedsLockscreenShowingThreshold(NotificationEntry entry) {
+ if (entry == null) {
+ return false;
+ }
+ if (NotificationUtils.useNewInterruptionModel(mContext)
+ && hideSilentNotificationsOnLockscreen()) {
+ // TODO: make sure in the NewNotifPipeline that entry.isHighPriority() has been
+ // correctly updated before reaching this point (b/145134683)
+ return entry.isHighPriority();
+ } else {
+ return !entry.getRanking().isAmbient();
+ }
+ }
+
+ private boolean hideSilentNotificationsOnLockscreen() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1) == 0;
+ }
+
+ private void setupInvalidateNotifListCallbacks() {
+ // register onKeyguardShowing callback
+ mKeyguardStateController.addCallback(mKeyguardCallback);
+
+ // register lockscreen settings changed callbacks:
+ final ContentObserver settingsObserver = new ContentObserver(mMainHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ 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);
+
+ // 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) {
+ mNotifFilter.invalidateList();
+ }
+
+ 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");
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
new file mode 100644
index 0000000..0d53a76
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Handles the attachment of the {@link NotifListBuilder} and {@link NotifCollection} to the
+ * {@link Coordinator}s, so that the Coordinators can register their respective callbacks.
+ */
+@Singleton
+public class NotifCoordinators implements Dumpable {
+ private static final String TAG = "NotifCoordinators";
+ private final List<Coordinator> mCoordinators = new ArrayList<>();
+
+ /**
+ * Creates all the coordinators.
+ */
+ @Inject
+ public NotifCoordinators(KeyguardCoordinator keyguardNotificationCoordinator) {
+ mCoordinators.add(keyguardNotificationCoordinator);
+ // TODO: add new Coordinators here! (b/145134683, b/112656837)
+ }
+
+ /**
+ * Sends the initialized notifListBuilder and notifCollection to each
+ * coordinator to indicate the notifListBuilder is ready to accept {@link Pluggable}s
+ * and the notifCollection is ready to accept {@link NotifCollectionListener}s and
+ * {@link NotifLifetimeExtender}s.
+ */
+ public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+ for (Coordinator c : mCoordinators) {
+ c.attach(notifCollection, notifListBuilder);
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(TAG + ":");
+ for (Coordinator c : mCoordinators) {
+ pw.println("\t" + c.getClass());
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
index 3b3e7e2..5fc55da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
@@ -23,6 +23,7 @@
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -37,6 +38,7 @@
public class NewNotifPipeline implements Dumpable {
private final NotifCollection mNotifCollection;
private final NotifListBuilderImpl mNotifPipeline;
+ private final NotifCoordinators mNotifPluggableCoordinators;
private final DumpController mDumpController;
private final FakePipelineConsumer mFakePipelineConsumer = new FakePipelineConsumer();
@@ -45,9 +47,11 @@
public NewNotifPipeline(
NotifCollection notifCollection,
NotifListBuilderImpl notifPipeline,
+ NotifCoordinators notifCoordinators,
DumpController dumpController) {
mNotifCollection = notifCollection;
mNotifPipeline = notifPipeline;
+ mNotifPluggableCoordinators = notifCoordinators;
mDumpController = dumpController;
}
@@ -57,6 +61,7 @@
mFakePipelineConsumer.attach(mNotifPipeline);
mNotifPipeline.attach(mNotifCollection);
mNotifCollection.attach(notificationService);
+ mNotifPluggableCoordinators.attach(mNotifCollection, mNotifPipeline);
Log.d(TAG, "Notif pipeline initialized");
@@ -66,6 +71,7 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mFakePipelineConsumer.dump(fd, pw, args);
+ mNotifPluggableCoordinators.dump(fd, pw, args);
}
private static final String TAG = "NewNotifPipeline";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
new file mode 100644
index 0000000..87b3783d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.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 junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+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.NotificationEntryBuilder;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+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 KeyguardCoordinatorTest 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 BroadcastDispatcher mBroadcastDispatcher;
+ @Mock private StatusBarStateController mStatusBarStateController;
+ @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+
+ private NotificationEntry mEntry;
+ private KeyguardCoordinator mKeyguardNotificationCoordinator;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mKeyguardNotificationCoordinator = new KeyguardCoordinator(
+ mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
+ mBroadcastDispatcher, mStatusBarStateController,
+ mKeyguardUpdateMonitor);
+
+ mEntry = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .build();
+ }
+
+ @Test
+ public void unfilteredState() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState();
+
+ // THEN don't filter out the entry
+ assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void notificationNotForCurrentProfile() {
+ // GIVEN the notification isn't for the given user
+ setupUnfilteredState();
+ when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(false);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void keyguardNotShowing() {
+ // GIVEN the lockscreen isn't showing
+ setupUnfilteredState();
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+
+ // THEN don't filter out the entry
+ assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void doNotShowLockscreenNotifications() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState();
+
+ // WHEN we shouldn't show any lockscreen notifications
+ when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void lockdown() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState();
+
+ // WHEN the notification's user is in lockdown:
+ when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void publicMode_settingsDisallow() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState();
+
+ // 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(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void publicMode_notifDisallowed() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState();
+
+ // 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(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void doesNotExceedThresholdToShow() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState();
+
+ // WHEN the notification doesn't exceed the threshold to show on the lockscreen
+ mEntry.setRanking(new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setImportance(IMPORTANCE_MIN)
+ .build());
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void summaryExceedsThresholdToShow() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState();
+
+ // WHEN the notification doesn't exceed the threshold to show on the lockscreen
+ // but its summary does
+ mEntry.setRanking(new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setImportance(IMPORTANCE_MIN)
+ .build());
+
+ final NotificationEntry summary = new NotificationEntryBuilder().build();
+ summary.setRanking(new RankingBuilder()
+ .setKey(summary.getKey())
+ .setImportance(IMPORTANCE_HIGH)
+ .build());
+ final GroupEntry group = new GroupEntry(mEntry.getSbn().getGroupKey());
+ group.setSummary(summary);
+ mEntry.setParent(group);
+
+ // THEN don't filter out the entry
+ assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ /**
+ * setup a state where the notification will not be filtered by the
+ * KeyguardNotificationCoordinator when the keyguard is showing.
+ */
+ private void setupUnfilteredState() {
+ // notification is for current profile
+ when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(true);
+
+ // 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
+ mEntry.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
+ }
+}