Merge "Register KeyguardNotifVisProvider CoreStartable" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
f0a312d294
@@ -70,7 +70,7 @@ public class KeyguardCoordinator implements Coordinator {
|
|||||||
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
|
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldFilterOut(NotificationEntry entry, long now) {
|
public boolean shouldFilterOut(NotificationEntry entry, long now) {
|
||||||
return mKeyguardNotificationVisibilityProvider.hideNotification(entry);
|
return mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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.NotificationsController;
|
||||||
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
|
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
|
||||||
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
|
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.NotificationInterruptStateProvider;
|
||||||
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
|
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
|
||||||
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
|
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
|
||||||
@@ -107,9 +108,10 @@ import dagger.Provides;
|
|||||||
*/
|
*/
|
||||||
@Module(includes = {
|
@Module(includes = {
|
||||||
CoordinatorsModule.class,
|
CoordinatorsModule.class,
|
||||||
|
KeyguardNotificationVisibilityProviderModule.class,
|
||||||
NotifActivityLaunchEventsModule.class,
|
NotifActivityLaunchEventsModule.class,
|
||||||
NotifPipelineChoreographerModule.class,
|
|
||||||
NotifPanelEventsModule.class,
|
NotifPanelEventsModule.class,
|
||||||
|
NotifPipelineChoreographerModule.class,
|
||||||
NotificationSectionHeadersModule.class,
|
NotificationSectionHeadersModule.class,
|
||||||
})
|
})
|
||||||
public interface NotificationsModule {
|
public interface NotificationsModule {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import com.android.keyguard.KeyguardUpdateMonitor
|
|||||||
import com.android.keyguard.KeyguardUpdateMonitorCallback
|
import com.android.keyguard.KeyguardUpdateMonitorCallback
|
||||||
import com.android.systemui.CoreStartable
|
import com.android.systemui.CoreStartable
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.dagger.qualifiers.Main
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||||
@@ -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.notification.collection.provider.HighPriorityProvider
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||||
import com.android.systemui.util.ListenerSet
|
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 java.util.function.Consumer
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/** Determines if notifications should be visible based on the state of the keyguard. */
|
||||||
* Determines if notifications should be visible based on the state of the keyguard
|
interface KeyguardNotificationVisibilityProvider {
|
||||||
*/
|
/**
|
||||||
class KeyguardNotificationVisibilityProvider @Inject constructor(
|
* 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,
|
context: Context,
|
||||||
@Main private val handler: Handler,
|
@Main private val handler: Handler,
|
||||||
private val keyguardStateController: KeyguardStateController,
|
private val keyguardStateController: KeyguardStateController,
|
||||||
@@ -36,8 +73,10 @@ class KeyguardNotificationVisibilityProvider @Inject constructor(
|
|||||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||||
private val highPriorityProvider: HighPriorityProvider,
|
private val highPriorityProvider: HighPriorityProvider,
|
||||||
private val statusBarStateController: StatusBarStateController,
|
private val statusBarStateController: StatusBarStateController,
|
||||||
private val broadcastDispatcher: BroadcastDispatcher
|
private val broadcastDispatcher: BroadcastDispatcher,
|
||||||
) : CoreStartable(context) {
|
private val secureSettings: SecureSettings,
|
||||||
|
private val globalSettings: GlobalSettings
|
||||||
|
) : CoreStartable(context), KeyguardNotificationVisibilityProvider {
|
||||||
private val onStateChangedListeners = ListenerSet<Consumer<String>>()
|
private val onStateChangedListeners = ListenerSet<Consumer<String>>()
|
||||||
private var hideSilentNotificationsOnLockscreen: Boolean = false
|
private var hideSilentNotificationsOnLockscreen: Boolean = false
|
||||||
|
|
||||||
@@ -60,33 +99,28 @@ class KeyguardNotificationVisibilityProvider @Inject constructor(
|
|||||||
|
|
||||||
// register lockscreen settings changed callbacks:
|
// register lockscreen settings changed callbacks:
|
||||||
val settingsObserver: ContentObserver = object : ContentObserver(handler) {
|
val settingsObserver: ContentObserver = object : ContentObserver(handler) {
|
||||||
override fun onChange(selfChange: Boolean, uri: Uri) {
|
override fun onChange(selfChange: Boolean, uri: Uri?) {
|
||||||
if (keyguardStateController.isShowing) {
|
if (keyguardStateController.isShowing) {
|
||||||
notifyStateChanged("Settings $uri changed")
|
notifyStateChanged("Settings $uri changed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mContext.contentResolver.registerContentObserver(
|
secureSettings.registerContentObserverForUser(
|
||||||
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS),
|
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
|
||||||
false,
|
|
||||||
settingsObserver,
|
settingsObserver,
|
||||||
UserHandle.USER_ALL)
|
UserHandle.USER_ALL)
|
||||||
|
|
||||||
mContext.contentResolver.registerContentObserver(
|
secureSettings.registerContentObserverForUser(
|
||||||
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
|
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
|
||||||
true,
|
true,
|
||||||
settingsObserver,
|
settingsObserver,
|
||||||
UserHandle.USER_ALL)
|
UserHandle.USER_ALL)
|
||||||
|
|
||||||
mContext.contentResolver.registerContentObserver(
|
globalSettings.registerContentObserver(Settings.Global.ZEN_MODE, settingsObserver)
|
||||||
Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
|
|
||||||
false,
|
|
||||||
settingsObserver)
|
|
||||||
|
|
||||||
mContext.contentResolver.registerContentObserver(
|
secureSettings.registerContentObserverForUser(
|
||||||
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
|
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
|
||||||
false,
|
|
||||||
settingsObserver,
|
settingsObserver,
|
||||||
UserHandle.USER_ALL)
|
UserHandle.USER_ALL)
|
||||||
|
|
||||||
@@ -98,41 +132,36 @@ class KeyguardNotificationVisibilityProvider @Inject constructor(
|
|||||||
})
|
})
|
||||||
broadcastDispatcher.registerReceiver(object : BroadcastReceiver() {
|
broadcastDispatcher.registerReceiver(object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
if (keyguardStateController.isShowing()) {
|
if (keyguardStateController.isShowing) {
|
||||||
// maybe public mode changed
|
// maybe public mode changed
|
||||||
notifyStateChanged(intent.action)
|
notifyStateChanged(intent.action!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, IntentFilter(Intent.ACTION_USER_SWITCHED))
|
}, IntentFilter(Intent.ACTION_USER_SWITCHED))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addOnStateChangedListener(listener: Consumer<String>) {
|
override fun addOnStateChangedListener(listener: Consumer<String>) {
|
||||||
onStateChangedListeners.addIfAbsent(listener)
|
onStateChangedListeners.addIfAbsent(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeOnStateChangedListener(listener: Consumer<String>) {
|
override fun removeOnStateChangedListener(listener: Consumer<String>) {
|
||||||
onStateChangedListeners.remove(listener)
|
onStateChangedListeners.remove(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyStateChanged(reason: String) {
|
private fun notifyStateChanged(reason: String) {
|
||||||
onStateChangedListeners.forEach({ it.accept(reason) })
|
onStateChangedListeners.forEach { it.accept(reason) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun shouldHideNotification(entry: NotificationEntry): Boolean {
|
||||||
* 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
|
val sbn = entry.sbn
|
||||||
// FILTER OUT the notification when the keyguard is showing and...
|
// 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
|
// ... user settings or the device policy manager doesn't allow lockscreen
|
||||||
// notifications;
|
// notifications;
|
||||||
if (!lockscreenUserManager.shouldShowLockscreenNotifications()) {
|
if (!lockscreenUserManager.shouldShowLockscreenNotifications()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
val currUserId: Int = lockscreenUserManager.getCurrentUserId()
|
val currUserId: Int = lockscreenUserManager.currentUserId
|
||||||
val notifUserId =
|
val notifUserId =
|
||||||
if (sbn.user.identifier == UserHandle.USER_ALL) currUserId
|
if (sbn.user.identifier == UserHandle.USER_ALL) currUserId
|
||||||
else sbn.user.identifier
|
else sbn.user.identifier
|
||||||
@@ -178,9 +207,7 @@ class KeyguardNotificationVisibilityProvider @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun readShowSilentNotificationSetting() {
|
private fun readShowSilentNotificationSetting() {
|
||||||
hideSilentNotificationsOnLockscreen = Settings.Secure.getInt(
|
hideSilentNotificationsOnLockscreen =
|
||||||
mContext.getContentResolver(),
|
secureSettings.getBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true)
|
||||||
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
|
|
||||||
1) == 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -312,7 +312,7 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mKeyguardNotificationVisibilityProvider.hideNotification(entry)) {
|
if (mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry)) {
|
||||||
mLogger.keyguardHideNotification(entry.getKey());
|
mLogger.keyguardHideNotification(entry.getKey());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -303,11 +303,82 @@ public interface SettingsProxy {
|
|||||||
default boolean putInt(String name, int value) {
|
default boolean putInt(String name, int value) {
|
||||||
return putIntForUser(name, value, getUserId());
|
return putIntForUser(name, value, getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** See {@link #putInt(String, int)}. */
|
/** See {@link #putInt(String, int)}. */
|
||||||
default boolean putIntForUser(String name, int value, int userHandle) {
|
default boolean putIntForUser(String name, int value, int userHandle) {
|
||||||
return putStringForUser(name, Integer.toString(value), 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
|
* Convenience function for retrieving a single secure settings value
|
||||||
* as a {@code long}. Note that internally setting values are always
|
* as a {@code long}. Note that internally setting values are always
|
||||||
|
|||||||
@@ -22,84 +22,238 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
|||||||
import static android.app.NotificationManager.IMPORTANCE_MIN;
|
import static android.app.NotificationManager.IMPORTANCE_MIN;
|
||||||
|
|
||||||
import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
|
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.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
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 static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
|
import android.testing.TestableLooper;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||||
|
import com.android.keyguard.KeyguardUpdateMonitorCallback;
|
||||||
|
import com.android.systemui.CoreStartable;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||||
import com.android.systemui.statusbar.RankingBuilder;
|
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.GroupEntry;
|
||||||
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
|
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
|
||||||
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
|
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
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.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import dagger.BindsInstance;
|
||||||
|
import dagger.Component;
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
|
@TestableLooper.RunWithLooper
|
||||||
public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
|
public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
|
||||||
private static final int NOTIF_USER_ID = 0;
|
private static final int NOTIF_USER_ID = 0;
|
||||||
private static final int CURR_USER_ID = 1;
|
private static final int CURR_USER_ID = 1;
|
||||||
|
|
||||||
@Mock
|
|
||||||
private Handler mMainHandler;
|
|
||||||
@Mock private KeyguardStateController mKeyguardStateController;
|
@Mock private KeyguardStateController mKeyguardStateController;
|
||||||
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
|
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
|
||||||
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||||
@Mock private HighPriorityProvider mHighPriorityProvider;
|
@Mock private HighPriorityProvider mHighPriorityProvider;
|
||||||
@Mock private SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
|
|
||||||
@Mock private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
|
|
||||||
@Mock private StatusBarStateController mStatusBarStateController;
|
@Mock private StatusBarStateController mStatusBarStateController;
|
||||||
@Mock private BroadcastDispatcher mBroadcastDispatcher;
|
@Mock private BroadcastDispatcher mBroadcastDispatcher;
|
||||||
|
private final FakeSettings mFakeSettings = new FakeSettings();
|
||||||
|
|
||||||
|
private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
|
||||||
private NotificationEntry mEntry;
|
private NotificationEntry mEntry;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
// TODO refactor the test of KeyguardNotificationVisibilityProvider out
|
TestComponent component =
|
||||||
mKeyguardNotificationVisibilityProvider = spy(new KeyguardNotificationVisibilityProvider(
|
DaggerKeyguardNotificationVisibilityProviderTest_TestComponent
|
||||||
mContext,
|
.factory()
|
||||||
mMainHandler,
|
.create(
|
||||||
mKeyguardStateController,
|
mContext,
|
||||||
mLockscreenUserManager,
|
new FakeHandler(TestableLooper.get(this).getLooper()),
|
||||||
mKeyguardUpdateMonitor,
|
mKeyguardStateController,
|
||||||
mHighPriorityProvider,
|
mLockscreenUserManager,
|
||||||
mStatusBarStateController,
|
mKeyguardUpdateMonitor,
|
||||||
mBroadcastDispatcher
|
mHighPriorityProvider,
|
||||||
));
|
mStatusBarStateController,
|
||||||
|
mBroadcastDispatcher,
|
||||||
|
mFakeSettings,
|
||||||
|
mFakeSettings);
|
||||||
|
mKeyguardNotificationVisibilityProvider = component.getProvider();
|
||||||
|
for (CoreStartable startable : component.getCoreStartables().values()) {
|
||||||
|
startable.start();
|
||||||
|
}
|
||||||
mEntry = new NotificationEntryBuilder()
|
mEntry = new NotificationEntryBuilder()
|
||||||
.setUser(new UserHandle(NOTIF_USER_ID))
|
.setUser(new UserHandle(NOTIF_USER_ID))
|
||||||
.build();
|
.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
|
@Test
|
||||||
public void unfilteredState() {
|
public void unfilteredState() {
|
||||||
// GIVEN an 'unfiltered-keyguard-showing' state
|
// GIVEN an 'unfiltered-keyguard-showing' state
|
||||||
setupUnfilteredState(mEntry);
|
setupUnfilteredState(mEntry);
|
||||||
|
|
||||||
// THEN don't filter out the entry
|
// THEN don't filter out the entry
|
||||||
assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
|
assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -109,7 +263,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
|
|||||||
when(mKeyguardStateController.isShowing()).thenReturn(false);
|
when(mKeyguardStateController.isShowing()).thenReturn(false);
|
||||||
|
|
||||||
// THEN don't filter out the entry
|
// THEN don't filter out the entry
|
||||||
assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
|
assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -121,7 +275,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
|
|||||||
when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
|
when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
|
||||||
|
|
||||||
// THEN filter out the entry
|
// THEN filter out the entry
|
||||||
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
|
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -133,7 +287,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
|
|||||||
when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
|
when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
|
||||||
|
|
||||||
// THEN filter out the entry
|
// THEN filter out the entry
|
||||||
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
|
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -148,7 +302,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
|
|||||||
.thenReturn(false);
|
.thenReturn(false);
|
||||||
|
|
||||||
// THEN filter out the entry
|
// THEN filter out the entry
|
||||||
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
|
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -164,7 +318,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
|
|||||||
.setVisibilityOverride(VISIBILITY_SECRET).build());
|
.setVisibilityOverride(VISIBILITY_SECRET).build());
|
||||||
|
|
||||||
// THEN filter out the entry
|
// THEN filter out the entry
|
||||||
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
|
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -180,7 +334,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
|
|||||||
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
|
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
|
||||||
|
|
||||||
// THEN filter out the entry
|
// THEN filter out the entry
|
||||||
assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
|
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -209,7 +363,8 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
|
|||||||
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
|
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
|
||||||
|
|
||||||
// THEN don't filter out the entry
|
// 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 its parent doesn't exceed threshold to show on lockscreen
|
||||||
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
|
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
|
||||||
@@ -218,7 +373,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
|
|||||||
.done());
|
.done());
|
||||||
|
|
||||||
// THEN filter out the entry
|
// 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
|
// notification is high priority, so it shouldn't be filtered
|
||||||
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -24,6 +24,7 @@ package com.android.systemui.util.mockito
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import org.mockito.ArgumentCaptor
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.ArgumentMatcher
|
||||||
import org.mockito.Mockito
|
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)
|
fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
|
||||||
inline fun <reified T> any(): T = any(T::class.java)
|
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()
|
* Kotlin type-inferred version of Mockito.nullable()
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user