SysUi can mock static methods + coordinator tests

- Add ability to mock static methods in SystemUI (In SystemUI, use
  mockito-target-extended-minus-junit4 and add libdexmakerjvmtiagent
  and libstaticjvmtiagent jni libraries to SystemUI tests bp/mk files
  so that we have static-mocking abilities)
- Add tests for new Coordinators

Test: atest SystemUiTests
Bug: 145134683
Change-Id: I0450a07c6d465c6d1f7d74acddb054538540785a
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 2a5bdc7..404e791 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -127,7 +127,7 @@
         "SystemUI-proto",
         "metrics-helper-lib",
         "androidx.test.rules", "hamcrest-library",
-        "mockito-target-inline-minus-junit4",
+        "mockito-target-extended-minus-junit4",
         "testables",
         "truth-prebuilt",
         "dagger2-2.19",
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 606605a..6ea3f4e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -20,6 +20,7 @@
 
 import android.app.INotificationManager;
 import android.content.Context;
+import android.content.pm.IPackageManager;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
@@ -150,6 +151,13 @@
     /** */
     @Singleton
     @Provides
+    public IPackageManager provideIPackageManager() {
+        return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+    }
+
+    /** */
+    @Singleton
+    @Provides
     public LayoutInflater providerLayoutInflater(Context context) {
         return LayoutInflater.from(context);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
index defa372..b68cb0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.notification.collection.coordinator;
 
 import android.Manifest;
-import android.app.AppGlobals;
 import android.app.Notification;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
@@ -43,10 +42,13 @@
     private static final String TAG = "DeviceProvisionedCoordinator";
 
     private final DeviceProvisionedController mDeviceProvisionedController;
+    private final IPackageManager mIPackageManager;
 
     @Inject
-    public DeviceProvisionedCoordinator(DeviceProvisionedController deviceProvisionedController) {
+    public DeviceProvisionedCoordinator(DeviceProvisionedController deviceProvisionedController,
+            IPackageManager packageManager) {
         mDeviceProvisionedController = deviceProvisionedController;
+        mIPackageManager = packageManager;
     }
 
     @Override
@@ -70,17 +72,16 @@
      * marking them as relevant for setup are allowed to show when device is unprovisioned
      */
     private boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) {
-        final boolean hasPermission = checkUidPermission(AppGlobals.getPackageManager(),
+        final boolean hasPermission = checkUidPermission(
                 Manifest.permission.NOTIFICATION_DURING_SETUP,
                 sbn.getUid()) == PackageManager.PERMISSION_GRANTED;
         return hasPermission
                 && sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP);
     }
 
-    private static int checkUidPermission(IPackageManager packageManager, String permission,
-            int uid) {
+    private int checkUidPermission(String permission, int uid) {
         try {
-            return packageManager.checkUidPermission(permission, uid);
+            return mIPackageManager.checkUidPermission(permission, uid);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 81e2c22..e5f56d4 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -32,7 +32,8 @@
 
 LOCAL_JNI_SHARED_LIBRARIES := \
     libdexmakerjvmtiagent \
-    libmultiplejvmtiagentsinterferenceagent
+    libmultiplejvmtiagentsinterferenceagent \
+    libstaticjvmtiagent
 
 LOCAL_JAVA_LIBRARIES := \
     android.test.runner \
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
new file mode 100644
index 0000000..a9413c7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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 junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.app.ActivityManagerInternal;
+import android.app.Notification;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DeviceProvisionedCoordinatorTest extends SysuiTestCase {
+    private static final int NOTIF_UID = 0;
+
+    private static final String SHOW_WHEN_UNPROVISIONED_FLAG =
+            Notification.EXTRA_ALLOW_DURING_SETUP;
+    private static final String SETUP_NOTIF_PERMISSION =
+            Manifest.permission.NOTIFICATION_DURING_SETUP;
+
+    private MockitoSession mMockitoSession;
+
+    @Mock private ActivityManagerInternal mActivityMangerInternal;
+    @Mock private IPackageManager mIPackageManager;
+    @Mock private DeviceProvisionedController mDeviceProvisionedController;
+    @Mock private NotifListBuilderImpl mNotifListBuilder;
+    private Notification mNotification;
+    private NotificationEntry mEntry;
+    private DeviceProvisionedCoordinator mDeviceProvisionedCoordinator;
+    private NotifFilter mDeviceProvisionedFilter;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mDeviceProvisionedCoordinator = new DeviceProvisionedCoordinator(
+                mDeviceProvisionedController, mIPackageManager);
+
+        mNotification = new Notification();
+        mEntry = new NotificationEntryBuilder()
+                .setNotification(mNotification)
+                .setUid(NOTIF_UID)
+                .build();
+
+        ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
+        mDeviceProvisionedCoordinator.attach(null, mNotifListBuilder);
+        verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+        mDeviceProvisionedFilter = filterCaptor.getValue();
+    }
+
+    @Test
+    public void deviceProvisioned() {
+        // GIVEN device is provisioned
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
+
+        // THEN don't filter out the notification
+        assertFalse(mDeviceProvisionedFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void deviceUnprovisioned() {
+        // GIVEN device is unprovisioned
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(false);
+
+        // THEN filter out the notification
+        assertTrue(mDeviceProvisionedFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void deviceUnprovisionedCanBypass() throws RemoteException {
+        // GIVEN device is unprovisioned
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(false);
+
+        // GIVEN notification has a flag to allow the notification during setup
+        Bundle extras = new Bundle();
+        extras.putBoolean(SHOW_WHEN_UNPROVISIONED_FLAG, true);
+        mNotification.extras = extras;
+
+        // GIVEN notification has the permission to display during setup
+        when(mIPackageManager.checkUidPermission(SETUP_NOTIF_PERMISSION, NOTIF_UID))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        // THEN don't filter out the notification
+        assertFalse(mDeviceProvisionedFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void deviceUnprovisionedTryBypassWithoutPermission() throws RemoteException {
+        // GIVEN device is unprovisioned
+        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(false);
+
+        // GIVEN notification has a flag to allow the notification during setup
+        Bundle extras = new Bundle();
+        extras.putBoolean(SHOW_WHEN_UNPROVISIONED_FLAG, true);
+        mNotification.extras = extras;
+
+        // GIVEN notification does NOT have permission to display during setup
+        when(mIPackageManager.checkUidPermission(SETUP_NOTIF_PERMISSION, NOTIF_UID))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+
+        // THEN filter out the notification
+        assertTrue(mDeviceProvisionedFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    private RankingBuilder getRankingForUnfilteredNotif() {
+        return new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setSuppressedVisualEffects(0)
+                .setSuspended(false);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
new file mode 100644
index 0000000..ffaa335
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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 junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ForegroundCoordinatorTest extends SysuiTestCase {
+    private static final String TEST_PKG = "test_pkg";
+    private static final int NOTIF_USER_ID = 0;
+
+    @Mock private Handler mMainHandler;
+    @Mock private ForegroundServiceController mForegroundServiceController;
+    @Mock private AppOpsController mAppOpsController;
+    @Mock private NotifListBuilderImpl mNotifListBuilder;
+    @Mock private NotifCollection mNotifCollection;
+
+    private NotificationEntry mEntry;
+    private Notification mNotification;
+    private ForegroundCoordinator mForegroundCoordinator;
+    private NotifFilter mForegroundFilter;
+    private NotifLifetimeExtender mForegroundNotifLifetimeExtender;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mForegroundCoordinator = new ForegroundCoordinator(
+                mForegroundServiceController, mAppOpsController, mMainHandler);
+
+        mNotification = new Notification();
+        mEntry = new NotificationEntryBuilder()
+                .setUser(new UserHandle(NOTIF_USER_ID))
+                .setNotification(mNotification)
+                .build();
+
+        ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
+        ArgumentCaptor<NotifLifetimeExtender> lifetimeExtenderCaptor =
+                ArgumentCaptor.forClass(NotifLifetimeExtender.class);
+
+        mForegroundCoordinator.attach(mNotifCollection, mNotifListBuilder);
+        verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+        verify(mNotifCollection, times(1)).addNotificationLifetimeExtender(
+                lifetimeExtenderCaptor.capture());
+
+        mForegroundFilter = filterCaptor.getValue();
+        mForegroundNotifLifetimeExtender = lifetimeExtenderCaptor.getValue();
+    }
+
+    @Test
+    public void filterTest_disclosureUnnecessary() {
+        StatusBarNotification sbn = mEntry.getSbn();
+
+        // GIVEN the notification is a disclosure notification
+        when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(true);
+
+        // GIVEN the disclosure isn't needed for this user
+        when(mForegroundServiceController.isDisclosureNeededForUser(sbn.getUserId()))
+                .thenReturn(false);
+
+        // THEN filter out the notification
+        assertTrue(mForegroundFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void filterTest_systemAlertNotificationUnnecessary() {
+        StatusBarNotification sbn = mEntry.getSbn();
+
+        // GIVEN the notification is a system alert notification + not a disclosure notification
+        when(mForegroundServiceController.isSystemAlertNotification(sbn)).thenReturn(true);
+        when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(false);
+
+        // GIVEN the alert notification isn't needed for this user
+        final Bundle extras = new Bundle();
+        extras.putStringArray(Notification.EXTRA_FOREGROUND_APPS,
+                new String[]{TEST_PKG});
+        mNotification.extras = extras;
+        when(mForegroundServiceController.isSystemAlertWarningNeeded(sbn.getUserId(), TEST_PKG))
+                .thenReturn(false);
+
+        // THEN filter out the notification
+        assertTrue(mForegroundFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void filterTest_doNotFilter() {
+        StatusBarNotification sbn = mEntry.getSbn();
+
+        // GIVEN the notification isn't a system alert notification nor a disclosure notification
+        when(mForegroundServiceController.isSystemAlertNotification(sbn)).thenReturn(false);
+        when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(false);
+
+        // THEN don't filter out the notification
+        assertFalse(mForegroundFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void extendLifetimeText_notForeground() {
+        // GIVEN the notification doesn't represent a foreground service
+        mNotification.flags = 0;
+
+        // THEN don't extend the lifetime
+        assertFalse(mForegroundNotifLifetimeExtender
+                .shouldExtendLifetime(mEntry, NotificationListenerService.REASON_CLICK));
+    }
+
+    @Test
+    public void extendLifetimeText_foregroundNotifRecentlyPosted() {
+        // GIVEN the notification represents a foreground service that was just posted
+        mNotification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        mEntry = new NotificationEntryBuilder()
+                .setUser(new UserHandle(NOTIF_USER_ID))
+                .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "",
+                        NOTIF_USER_ID, NOTIF_USER_ID, mNotification,
+                        new UserHandle(NOTIF_USER_ID), "", System.currentTimeMillis()))
+                .setNotification(mNotification)
+                .build();
+
+        // THEN extend the lifetime
+        assertTrue(mForegroundNotifLifetimeExtender
+                .shouldExtendLifetime(mEntry, NotificationListenerService.REASON_CLICK));
+    }
+
+    @Test
+    public void extendLifetimeText_foregroundNotifOld() {
+        // GIVEN the notification represents a foreground service that was posted 10 seconds ago
+        mNotification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        mEntry = new NotificationEntryBuilder()
+                .setUser(new UserHandle(NOTIF_USER_ID))
+                .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "",
+                        NOTIF_USER_ID, NOTIF_USER_ID, mNotification,
+                        new UserHandle(NOTIF_USER_ID), "",
+                        System.currentTimeMillis() - 10000))
+                .setNotification(mNotification)
+                .build();
+
+        // THEN don't extend the lifetime because the extended time exceeds
+        // ForegroundCoordinator.MIN_FGS_TIME_MS
+        assertFalse(mForegroundNotifLifetimeExtender
+                .shouldExtendLifetime(mEntry, NotificationListenerService.REASON_CLICK));
+    }
+}
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
index 87b3783d..527370e 100644
--- 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
@@ -24,6 +24,8 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.os.Handler;
@@ -40,12 +42,15 @@
 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.NotifListBuilderImpl;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 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;
 import org.mockito.MockitoAnnotations;
 
@@ -61,14 +66,16 @@
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
     @Mock private StatusBarStateController mStatusBarStateController;
     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock private NotifListBuilderImpl mNotifListBuilder;
 
     private NotificationEntry mEntry;
-    private KeyguardCoordinator mKeyguardNotificationCoordinator;
+    private KeyguardCoordinator mKeyguardCoordinator;
+    private NotifFilter mKeyguardFilter;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mKeyguardNotificationCoordinator = new KeyguardCoordinator(
+        mKeyguardCoordinator = new KeyguardCoordinator(
                 mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
                 mBroadcastDispatcher, mStatusBarStateController,
                 mKeyguardUpdateMonitor);
@@ -76,6 +83,11 @@
         mEntry = new NotificationEntryBuilder()
                 .setUser(new UserHandle(NOTIF_USER_ID))
                 .build();
+
+        ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
+        mKeyguardCoordinator.attach(null, mNotifListBuilder);
+        verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+        mKeyguardFilter = filterCaptor.getValue();
     }
 
     @Test
@@ -84,7 +96,7 @@
         setupUnfilteredState();
 
         // THEN don't filter out the entry
-        assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+        assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -94,7 +106,7 @@
         when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(false);
 
         // THEN filter out the entry
-        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -104,7 +116,7 @@
         when(mKeyguardStateController.isShowing()).thenReturn(false);
 
         // THEN don't filter out the entry
-        assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+        assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -116,7 +128,7 @@
         when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
 
         // THEN filter out the entry
-        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -128,7 +140,7 @@
         when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
 
         // THEN filter out the entry
-        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -143,7 +155,7 @@
                 .thenReturn(false);
 
         // THEN filter out the entry
-        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -159,7 +171,7 @@
                 .setVisibilityOverride(VISIBILITY_SECRET).build());
 
         // THEN filter out the entry
-        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -174,7 +186,7 @@
                 .build());
 
         // THEN filter out the entry
-        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -199,7 +211,7 @@
         mEntry.setParent(group);
 
         // THEN don't filter out the entry
-        assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+        assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
new file mode 100644
index 0000000..182e866
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class RankingCoordinatorTest extends SysuiTestCase {
+
+    @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private NotifListBuilderImpl mNotifListBuilder;
+    private NotificationEntry mEntry;
+    private RankingCoordinator mRankingCoordinator;
+    private NotifFilter mRankingFilter;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mRankingCoordinator = new RankingCoordinator(mStatusBarStateController);
+        mEntry = new NotificationEntryBuilder().build();
+
+        ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
+        mRankingCoordinator.attach(null, mNotifListBuilder);
+        verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+        mRankingFilter = filterCaptor.getValue();
+    }
+
+    @Test
+    public void testUnfilteredState() {
+        // GIVEN no suppressed visual effects + app not suspended
+        mEntry.setRanking(getRankingForUnfilteredNotif().build());
+
+        // THEN don't filter out the notification
+        assertFalse(mRankingFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void filterSuspended() {
+        // GIVEN the notification's app is suspended
+        mEntry.setRanking(getRankingForUnfilteredNotif()
+                .setSuspended(true)
+                .build());
+
+        // THEN filter out the notification
+        assertTrue(mRankingFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void filterDozingSuppressAmbient() {
+        // GIVEN should suppress ambient
+        mEntry.setRanking(getRankingForUnfilteredNotif()
+                .setSuppressedVisualEffects(SUPPRESSED_EFFECT_AMBIENT)
+                .build());
+
+        // WHEN it's dozing (on ambient display)
+        when(mStatusBarStateController.isDozing()).thenReturn(true);
+
+        // THEN filter out the notification
+        assertTrue(mRankingFilter.shouldFilterOut(mEntry, 0));
+
+        // WHEN it's not dozing (showing the notification list)
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+
+        // THEN don't filter out the notification
+        assertFalse(mRankingFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void filterDozingSuppressNotificationList() {
+        // GIVEN should suppress from the notification list
+        mEntry.setRanking(getRankingForUnfilteredNotif()
+                .setSuppressedVisualEffects(SUPPRESSED_EFFECT_NOTIFICATION_LIST)
+                .build());
+
+        // WHEN it's dozing (on ambient display)
+        when(mStatusBarStateController.isDozing()).thenReturn(true);
+
+        // THEN don't filter out the notification
+        assertFalse(mRankingFilter.shouldFilterOut(mEntry, 0));
+
+        // WHEN it's not dozing (showing the notification list)
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+
+        // THEN filter out the notification
+        assertTrue(mRankingFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    private RankingBuilder getRankingForUnfilteredNotif() {
+        return new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setSuppressedVisualEffects(0)
+                .setSuspended(false);
+    }
+}