Register KeyguardNotifVisProvider CoreStartable

KeyguardNotificationVisibilityProvider's `start` method was never being
invoked, because it was never being registered as a CoreStartable. This
was in turn causing all invalidaton events to be missed, resulting in
stale notification shade states being visible.

This CL properly registers the CoreStartable, and adds additional tests
to verify that listeners are called as expected once registered.

Fixes: 224763592
Test: atest KeyguardNotificationVisibilityProviderTest
Test: 0. Have silent notifications
      1. lock device
      2. expand shade, keeping device locked
      3. collapse shade
      4. verify silent header no longer visible
Change-Id: I70661583f0d98c6dac7924667dad89a3664334e2
Merged-In: I70661583f0d98c6dac7924667dad89a3664334e2
This commit is contained in:
Steve Elliott
2022-03-18 15:44:48 -04:00
parent b9bad684dc
commit 2d0f66a6ac
7 changed files with 354 additions and 67 deletions

View File

@@ -70,7 +70,7 @@ public class KeyguardCoordinator implements Coordinator {
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
return mKeyguardNotificationVisibilityProvider.hideNotification(entry);
return mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry);
}
};

View File

@@ -73,6 +73,7 @@ import com.android.systemui.statusbar.notification.collection.render.Notificatio
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProviderModule;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -107,9 +108,10 @@ import dagger.Provides;
*/
@Module(includes = {
CoordinatorsModule.class,
KeyguardNotificationVisibilityProviderModule.class,
NotifActivityLaunchEventsModule.class,
NotifPipelineChoreographerModule.class,
NotifPanelEventsModule.class,
NotifPipelineChoreographerModule.class,
NotificationSectionHeadersModule.class,
})
public interface NotificationsModule {

View File

@@ -14,6 +14,7 @@ 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.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -22,13 +23,49 @@ 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 com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.settings.SecureSettings
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
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(
/** Determines if notifications should be visible based on the state of the keyguard. */
interface KeyguardNotificationVisibilityProvider {
/**
* Determines if the given notification should be hidden based on the current keyguard state.
* If a [Consumer] registered via [addOnStateChangedListener] is invoked, the results of this
* method may no longer be valid and should be re-queried.
*/
fun shouldHideNotification(entry: NotificationEntry): Boolean
/** Registers a listener to be notified when the internal keyguard state has been updated. */
fun addOnStateChangedListener(listener: Consumer<String>)
/** Unregisters a listener previously registered with [addOnStateChangedListener]. */
fun removeOnStateChangedListener(listener: Consumer<String>)
}
/** Provides a [KeyguardNotificationVisibilityProvider] in [SysUISingleton] scope. */
@Module(includes = [KeyguardNotificationVisibilityProviderImplModule::class])
object KeyguardNotificationVisibilityProviderModule
@Module
private interface KeyguardNotificationVisibilityProviderImplModule {
@Binds
fun bindImpl(impl: KeyguardNotificationVisibilityProviderImpl):
KeyguardNotificationVisibilityProvider
@Binds
@IntoMap
@ClassKey(KeyguardNotificationVisibilityProvider::class)
fun bindStartable(impl: KeyguardNotificationVisibilityProviderImpl): CoreStartable
}
@SysUISingleton
private class KeyguardNotificationVisibilityProviderImpl @Inject constructor(
context: Context,
@Main private val handler: Handler,
private val keyguardStateController: KeyguardStateController,
@@ -36,8 +73,10 @@ class KeyguardNotificationVisibilityProvider @Inject constructor(
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val highPriorityProvider: HighPriorityProvider,
private val statusBarStateController: StatusBarStateController,
private val broadcastDispatcher: BroadcastDispatcher
) : CoreStartable(context) {
private val broadcastDispatcher: BroadcastDispatcher,
private val secureSettings: SecureSettings,
private val globalSettings: GlobalSettings
) : CoreStartable(context), KeyguardNotificationVisibilityProvider {
private val onStateChangedListeners = ListenerSet<Consumer<String>>()
private var hideSilentNotificationsOnLockscreen: Boolean = false
@@ -60,33 +99,28 @@ class KeyguardNotificationVisibilityProvider @Inject constructor(
// register lockscreen settings changed callbacks:
val settingsObserver: ContentObserver = object : ContentObserver(handler) {
override fun onChange(selfChange: Boolean, uri: Uri) {
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,
secureSettings.registerContentObserverForUser(
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
settingsObserver,
UserHandle.USER_ALL)
mContext.contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
secureSettings.registerContentObserverForUser(
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
true,
settingsObserver,
UserHandle.USER_ALL)
mContext.contentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
false,
settingsObserver)
globalSettings.registerContentObserver(Settings.Global.ZEN_MODE, settingsObserver)
mContext.contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
false,
secureSettings.registerContentObserverForUser(
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
settingsObserver,
UserHandle.USER_ALL)
@@ -98,41 +132,36 @@ class KeyguardNotificationVisibilityProvider @Inject constructor(
})
broadcastDispatcher.registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (keyguardStateController.isShowing()) {
if (keyguardStateController.isShowing) {
// maybe public mode changed
notifyStateChanged(intent.action)
notifyStateChanged(intent.action!!)
}
}
}, IntentFilter(Intent.ACTION_USER_SWITCHED))
}
fun addOnStateChangedListener(listener: Consumer<String>) {
override fun addOnStateChangedListener(listener: Consumer<String>) {
onStateChangedListeners.addIfAbsent(listener)
}
fun removeOnStateChangedListener(listener: Consumer<String>) {
override fun removeOnStateChangedListener(listener: Consumer<String>) {
onStateChangedListeners.remove(listener)
}
private fun notifyStateChanged(reason: String) {
onStateChangedListeners.forEach({ it.accept(reason) })
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 {
override fun shouldHideNotification(entry: NotificationEntry): Boolean {
val sbn = entry.sbn
// FILTER OUT the notification when the keyguard is showing and...
if (keyguardStateController.isShowing()) {
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 currUserId: Int = lockscreenUserManager.currentUserId
val notifUserId =
if (sbn.user.identifier == UserHandle.USER_ALL) currUserId
else sbn.user.identifier
@@ -178,9 +207,7 @@ class KeyguardNotificationVisibilityProvider @Inject constructor(
}
private fun readShowSilentNotificationSetting() {
hideSilentNotificationsOnLockscreen = Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
1) == 0
hideSilentNotificationsOnLockscreen =
secureSettings.getBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true)
}
}

View File

@@ -312,7 +312,7 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
if (mKeyguardNotificationVisibilityProvider.hideNotification(entry)) {
if (mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry)) {
mLogger.keyguardHideNotification(entry.getKey());
return false;
}

View File

@@ -303,11 +303,82 @@ public interface SettingsProxy {
default boolean putInt(String name, int value) {
return putIntForUser(name, value, getUserId());
}
/** See {@link #putInt(String, int)}. */
default boolean putIntForUser(String name, int value, int userHandle) {
return putStringForUser(name, Integer.toString(value), userHandle);
}
/**
* Convenience function for retrieving a single secure settings value
* as a boolean. Note that internally setting values are always
* stored as strings; this function converts the string to a boolean
* for you. The default value will be returned if the setting is
* not defined or not a boolean.
*
* @param name The name of the setting to retrieve.
* @param def Value to return if the setting is not defined.
*
* @return The setting's current value, or 'def' if it is not defined
* or not a valid boolean.
*/
default boolean getBool(String name, boolean def) {
return getBoolForUser(name, def, getUserId());
}
/** See {@link #getBool(String, boolean)}. */
default boolean getBoolForUser(String name, boolean def, int userHandle) {
return getIntForUser(name, def ? 1 : 0, userHandle) != 0;
}
/**
* Convenience function for retrieving a single secure settings value
* as a boolean. Note that internally setting values are always
* stored as strings; this function converts the string to a boolean
* for you.
* <p>
* This version does not take a default value. If the setting has not
* been set, or the string value is not a number,
* it throws {@link Settings.SettingNotFoundException}.
*
* @param name The name of the setting to retrieve.
*
* @throws Settings.SettingNotFoundException Thrown if a setting by the given
* name can't be found or the setting value is not a boolean.
*
* @return The setting's current value.
*/
default boolean getBool(String name) throws Settings.SettingNotFoundException {
return getBoolForUser(name, getUserId());
}
/** See {@link #getBool(String)}. */
default boolean getBoolForUser(String name, int userHandle)
throws Settings.SettingNotFoundException {
return getIntForUser(name, userHandle) != 0;
}
/**
* Convenience function for updating a single settings value as a
* boolean. This will either create a new entry in the table if the
* given name does not exist, or modify the value of the existing row
* with that name. Note that internally setting values are always
* stored as strings, so this function converts the given value to a
* string before storing it.
*
* @param name The name of the setting to modify.
* @param value The new value for the setting.
* @return true if the value was set, false on database errors
*/
default boolean putBool(String name, boolean value) {
return putBoolForUser(name, value, getUserId());
}
/** See {@link #putBool(String, boolean)}. */
default boolean putBoolForUser(String name, boolean value, int userHandle) {
return putIntForUser(name, value ? 1 : 0, userHandle);
}
/**
* Convenience function for retrieving a single secure settings value
* as a {@code long}. Note that internally setting values are always

View File

@@ -22,84 +22,238 @@ 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 com.android.systemui.util.mockito.KotlinMockitoHelpersKt.argThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.CoreStartable;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.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 com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.utils.os.FakeHandler;
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 java.util.Map;
import java.util.function.Consumer;
import dagger.BindsInstance;
import dagger.Component;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
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 final FakeSettings mFakeSettings = new FakeSettings();
private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
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
));
TestComponent component =
DaggerKeyguardNotificationVisibilityProviderTest_TestComponent
.factory()
.create(
mContext,
new FakeHandler(TestableLooper.get(this).getLooper()),
mKeyguardStateController,
mLockscreenUserManager,
mKeyguardUpdateMonitor,
mHighPriorityProvider,
mStatusBarStateController,
mBroadcastDispatcher,
mFakeSettings,
mFakeSettings);
mKeyguardNotificationVisibilityProvider = component.getProvider();
for (CoreStartable startable : component.getCoreStartables().values()) {
startable.start();
}
mEntry = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID))
.build();
}
@Test
public void notifyListeners_onUnlockedChanged() {
ArgumentCaptor<KeyguardStateController.Callback> callbackCaptor =
ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
verify(mKeyguardStateController).addCallback(callbackCaptor.capture());
KeyguardStateController.Callback callback = callbackCaptor.getValue();
Consumer<String> listener = mock(Consumer.class);
mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
callback.onUnlockedChanged();
verify(listener).accept(anyString());
}
@Test
public void notifyListeners_onKeyguardShowingChanged() {
ArgumentCaptor<KeyguardStateController.Callback> callbackCaptor =
ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
verify(mKeyguardStateController).addCallback(callbackCaptor.capture());
KeyguardStateController.Callback callback = callbackCaptor.getValue();
Consumer<String> listener = mock(Consumer.class);
mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
callback.onKeyguardShowingChanged();
verify(listener).accept(anyString());
}
@Test
public void notifyListeners_onStrongAuthStateChanged() {
ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCaptor =
ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
verify(mKeyguardUpdateMonitor).registerCallback(callbackCaptor.capture());
KeyguardUpdateMonitorCallback callback = callbackCaptor.getValue();
Consumer<String> listener = mock(Consumer.class);
mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
callback.onStrongAuthStateChanged(0);
verify(listener).accept(anyString());
}
@Test
public void notifyListeners_onStatusBarStateChanged() {
ArgumentCaptor<StatusBarStateController.StateListener> callbackCaptor =
ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
verify(mStatusBarStateController).addCallback(callbackCaptor.capture());
StatusBarStateController.StateListener callback = callbackCaptor.getValue();
Consumer<String> listener = mock(Consumer.class);
mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
callback.onStateChanged(0);
verify(listener).accept(anyString());
}
@Test
public void notifyListeners_onReceiveUserSwitchBroadcast() {
ArgumentCaptor<BroadcastReceiver> callbackCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
verify(mBroadcastDispatcher).registerReceiver(
callbackCaptor.capture(),
argThat(intentFilter -> intentFilter.hasAction(Intent.ACTION_USER_SWITCHED)),
isNull(),
isNull(),
eq(Context.RECEIVER_EXPORTED));
BroadcastReceiver callback = callbackCaptor.getValue();
Consumer<String> listener = mock(Consumer.class);
mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
when(mKeyguardStateController.isShowing()).thenReturn(true);
callback.onReceive(mContext, new Intent(Intent.ACTION_USER_SWITCHED));
verify(listener).accept(anyString());
}
@Test
public void notifyListeners_onSettingChange_lockScreenShowNotifs() {
when(mKeyguardStateController.isShowing()).thenReturn(true);
Consumer<String> listener = mock(Consumer.class);
mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
mFakeSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
verify(listener).accept(anyString());
}
@Test
public void notifyListeners_onSettingChange_lockScreenAllowPrivateNotifs() {
when(mKeyguardStateController.isShowing()).thenReturn(true);
Consumer<String> listener = mock(Consumer.class);
mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
mFakeSettings.putInt(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1);
verify(listener).accept(anyString());
}
@Test
public void notifyListeners_onSettingChange_zenMode() {
when(mKeyguardStateController.isShowing()).thenReturn(true);
Consumer<String> listener = mock(Consumer.class);
mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
mFakeSettings.putInt(Settings.Global.ZEN_MODE, 1);
verify(listener).accept(anyString());
}
@Test
public void notifyListeners_onSettingChange_lockScreenShowSilentNotifs() {
when(mKeyguardStateController.isShowing()).thenReturn(true);
Consumer<String> listener = mock(Consumer.class);
mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
mFakeSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1);
verify(listener).accept(anyString());
}
@Test
public void unfilteredState() {
// GIVEN an 'unfiltered-keyguard-showing' state
setupUnfilteredState(mEntry);
// THEN don't filter out the entry
assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@Test
@@ -109,7 +263,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
when(mKeyguardStateController.isShowing()).thenReturn(false);
// THEN don't filter out the entry
assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@Test
@@ -121,7 +275,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@Test
@@ -133,7 +287,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@Test
@@ -148,7 +302,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
.thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@Test
@@ -164,7 +318,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
.setVisibilityOverride(VISIBILITY_SECRET).build());
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@Test
@@ -180,7 +334,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@Test
@@ -209,7 +363,8 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
// THEN don't filter out the entry
assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(entryWithParent));
assertFalse(
mKeyguardNotificationVisibilityProvider.shouldHideNotification(entryWithParent));
// WHEN its parent doesn't exceed threshold to show on lockscreen
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
@@ -218,7 +373,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
.done());
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(entryWithParent));
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(entryWithParent));
}
/**
@@ -259,4 +414,27 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
// notification is high priority, so it shouldn't be filtered
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
}
}
@SysUISingleton
@Component(modules = { KeyguardNotificationVisibilityProviderModule.class })
interface TestComponent {
KeyguardNotificationVisibilityProvider getProvider();
Map<Class<?>, CoreStartable> getCoreStartables();
@Component.Factory
interface Factory {
TestComponent create(
@BindsInstance Context context,
@BindsInstance @Main Handler handler,
@BindsInstance KeyguardStateController keyguardStateController,
@BindsInstance NotificationLockscreenUserManager lockscreenUserManager,
@BindsInstance KeyguardUpdateMonitor keyguardUpdateMonitor,
@BindsInstance HighPriorityProvider highPriorityProvider,
@BindsInstance StatusBarStateController statusBarStateController,
@BindsInstance BroadcastDispatcher broadcastDispatcher,
@BindsInstance SecureSettings secureSettings,
@BindsInstance GlobalSettings globalSettings
);
}
}
}

View File

@@ -24,6 +24,7 @@ package com.android.systemui.util.mockito
*/
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatcher
import org.mockito.Mockito
/**
@@ -43,6 +44,14 @@ fun <T> eq(obj: T): T = Mockito.eq<T>(obj)
fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
inline fun <reified T> any(): T = any(T::class.java)
/**
* Returns Mockito.argThat() as nullable type to avoid java.lang.IllegalStateException when
* null is returned.
*
* Generic T is nullable because implicitly bounded by Any?.
*/
fun <T> argThat(matcher: ArgumentMatcher<T>): T = Mockito.argThat(matcher)
/**
* Kotlin type-inferred version of Mockito.nullable()
*/