1 package com.android.systemui.statusbar.notification.interruption 2 3 import android.app.Notification 4 import android.app.Notification.VISIBILITY_SECRET 5 import android.content.Context 6 import android.database.ContentObserver 7 import android.net.Uri 8 import android.os.Handler 9 import android.os.HandlerExecutor 10 import android.os.UserHandle 11 import android.provider.Settings 12 import com.android.keyguard.KeyguardUpdateMonitor 13 import com.android.keyguard.KeyguardUpdateMonitorCallback 14 import com.android.systemui.CoreStartable 15 import com.android.systemui.dagger.SysUISingleton 16 import com.android.systemui.dagger.qualifiers.Main 17 import com.android.systemui.plugins.statusbar.StatusBarStateController 18 import com.android.systemui.settings.UserTracker 19 import com.android.systemui.statusbar.NotificationLockscreenUserManager 20 import com.android.systemui.statusbar.StatusBarState 21 import com.android.systemui.statusbar.SysuiStatusBarStateController 22 import com.android.systemui.statusbar.notification.collection.ListEntry 23 import com.android.systemui.statusbar.notification.collection.NotificationEntry 24 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider 25 import com.android.systemui.statusbar.policy.KeyguardStateController 26 import com.android.systemui.util.ListenerSet 27 import com.android.systemui.util.asIndenting 28 import com.android.systemui.util.settings.GlobalSettings 29 import com.android.systemui.util.settings.SecureSettings 30 import com.android.systemui.util.withIncreasedIndent 31 import dagger.Binds 32 import dagger.Module 33 import dagger.multibindings.ClassKey 34 import dagger.multibindings.IntoMap 35 import java.io.PrintWriter 36 import java.util.function.Consumer 37 import javax.inject.Inject 38 39 /** Determines if notifications should be visible based on the state of the keyguard. */ 40 interface KeyguardNotificationVisibilityProvider { 41 /** 42 * Determines if the given notification should be hidden based on the current keyguard state. 43 * If a [Consumer] registered via [addOnStateChangedListener] is invoked, the results of this 44 * method may no longer be valid and should be re-queried. 45 */ 46 fun shouldHideNotification(entry: NotificationEntry): Boolean 47 48 /** Registers a listener to be notified when the internal keyguard state has been updated. */ 49 fun addOnStateChangedListener(listener: Consumer<String>) 50 51 /** Unregisters a listener previously registered with [addOnStateChangedListener]. */ 52 fun removeOnStateChangedListener(listener: Consumer<String>) 53 } 54 55 /** Provides a [KeyguardNotificationVisibilityProvider] in [SysUISingleton] scope. */ 56 @Module(includes = [KeyguardNotificationVisibilityProviderImplModule::class]) 57 object KeyguardNotificationVisibilityProviderModule 58 59 @Module 60 private interface KeyguardNotificationVisibilityProviderImplModule { 61 @Binds 62 fun bindImpl(impl: KeyguardNotificationVisibilityProviderImpl): 63 KeyguardNotificationVisibilityProvider 64 65 @Binds 66 @IntoMap 67 @ClassKey(KeyguardNotificationVisibilityProvider::class) 68 fun bindStartable(impl: KeyguardNotificationVisibilityProviderImpl): CoreStartable 69 } 70 71 @SysUISingleton 72 private class KeyguardNotificationVisibilityProviderImpl @Inject constructor( 73 @Main private val handler: Handler, 74 private val keyguardStateController: KeyguardStateController, 75 private val lockscreenUserManager: NotificationLockscreenUserManager, 76 private val keyguardUpdateMonitor: KeyguardUpdateMonitor, 77 private val highPriorityProvider: HighPriorityProvider, 78 private val statusBarStateController: SysuiStatusBarStateController, 79 private val userTracker: UserTracker, 80 private val secureSettings: SecureSettings, 81 private val globalSettings: GlobalSettings 82 ) : CoreStartable, KeyguardNotificationVisibilityProvider { 83 private val showSilentNotifsUri = 84 secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS) 85 private val onStateChangedListeners = ListenerSet<Consumer<String>>() 86 private var hideSilentNotificationsOnLockscreen: Boolean = false 87 88 private val userTrackerCallback = object : UserTracker.Callback { 89 override fun onUserChanged(newUser: Int, userContext: Context) { 90 if (isLockedOrLocking) { 91 // maybe public mode changed 92 notifyStateChanged("onUserSwitched") 93 } 94 } 95 } 96 97 override fun start() { 98 readShowSilentNotificationSetting() 99 keyguardStateController.addCallback(object : KeyguardStateController.Callback { 100 override fun onUnlockedChanged() { 101 notifyStateChanged("onUnlockedChanged") 102 } 103 104 override fun onKeyguardShowingChanged() { 105 notifyStateChanged("onKeyguardShowingChanged") 106 } 107 }) 108 keyguardUpdateMonitor.registerCallback(object : KeyguardUpdateMonitorCallback() { 109 override fun onStrongAuthStateChanged(userId: Int) { 110 notifyStateChanged("onStrongAuthStateChanged") 111 } 112 }) 113 114 // register lockscreen settings changed callbacks: 115 val settingsObserver: ContentObserver = object : ContentObserver(handler) { 116 override fun onChange(selfChange: Boolean, uri: Uri?) { 117 if (uri == showSilentNotifsUri) { 118 readShowSilentNotificationSetting() 119 } 120 if (isLockedOrLocking) { 121 notifyStateChanged("Settings $uri changed") 122 } 123 } 124 } 125 126 secureSettings.registerContentObserverForUser( 127 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 128 settingsObserver, 129 UserHandle.USER_ALL) 130 131 secureSettings.registerContentObserverForUser( 132 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 133 true, 134 settingsObserver, 135 UserHandle.USER_ALL) 136 137 globalSettings.registerContentObserver(Settings.Global.ZEN_MODE, settingsObserver) 138 139 secureSettings.registerContentObserverForUser( 140 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 141 settingsObserver, 142 UserHandle.USER_ALL) 143 144 // register (maybe) public mode changed callbacks: 145 statusBarStateController.addCallback(object : StatusBarStateController.StateListener { 146 override fun onStateChanged(newState: Int) { 147 notifyStateChanged("onStatusBarStateChanged") 148 } 149 override fun onUpcomingStateChanged(state: Int) { 150 notifyStateChanged("onStatusBarUpcomingStateChanged") 151 } 152 }) 153 userTracker.addCallback(userTrackerCallback, HandlerExecutor(handler)) 154 } 155 156 override fun addOnStateChangedListener(listener: Consumer<String>) { 157 onStateChangedListeners.addIfAbsent(listener) 158 } 159 160 override fun removeOnStateChangedListener(listener: Consumer<String>) { 161 onStateChangedListeners.remove(listener) 162 } 163 164 private fun notifyStateChanged(reason: String) { 165 onStateChangedListeners.forEach { it.accept(reason) } 166 } 167 168 override fun shouldHideNotification(entry: NotificationEntry): Boolean = when { 169 // Keyguard state doesn't matter if the keyguard is not showing. 170 !isLockedOrLocking -> false 171 // Notifications not allowed on the lockscreen, always hide. 172 !lockscreenUserManager.shouldShowLockscreenNotifications() -> true 173 // User settings do not allow this notification on the lockscreen, so hide it. 174 userSettingsDisallowNotification(entry) -> true 175 // Entry is explicitly marked SECRET, so hide it. 176 entry.sbn.notification.visibility == VISIBILITY_SECRET -> true 177 // if entry is silent, apply custom logic to see if should hide 178 shouldHideIfEntrySilent(entry) -> true 179 else -> false 180 } 181 182 private fun shouldHideIfEntrySilent(entry: ListEntry): Boolean = when { 183 // Show if explicitly high priority (not hidden) 184 highPriorityProvider.isExplicitlyHighPriority(entry) -> false 185 // Ambient notifications are hidden always from lock screen 186 entry.representativeEntry?.isAmbient == true -> true 187 // [Now notification is silent] 188 // Hide regardless of parent priority if user wants silent notifs hidden 189 hideSilentNotificationsOnLockscreen -> true 190 // Parent priority is high enough to be shown on the lockscreen, do not hide. 191 entry.parent?.let(::shouldHideIfEntrySilent) == false -> false 192 // Show when silent notifications are allowed on lockscreen 193 else -> false 194 } 195 196 private fun userSettingsDisallowNotification(entry: NotificationEntry): Boolean { 197 fun disallowForUser(user: Int) = when { 198 // user is in lockdown, always disallow 199 keyguardUpdateMonitor.isUserInLockdown(user) -> true 200 // device isn't public, no need to check public-related settings, so allow 201 !lockscreenUserManager.isLockscreenPublicMode(user) -> false 202 // entry is meant to be secret on the lockscreen, disallow 203 entry.ranking.lockscreenVisibilityOverride == Notification.VISIBILITY_SECRET -> true 204 // disallow if user disallows notifications in public 205 else -> !lockscreenUserManager.userAllowsNotificationsInPublic(user) 206 } 207 val currentUser = lockscreenUserManager.currentUserId 208 val notifUser = entry.sbn.user.identifier 209 return when { 210 disallowForUser(currentUser) -> true 211 notifUser == UserHandle.USER_ALL -> false 212 notifUser == currentUser -> false 213 else -> disallowForUser(notifUser) 214 } 215 } 216 217 override fun dump(pw: PrintWriter, args: Array<out String>) = pw.asIndenting().run { 218 println("isLockedOrLocking=$isLockedOrLocking") 219 withIncreasedIndent { 220 println("keyguardStateController.isShowing=${keyguardStateController.isShowing}") 221 println("statusBarStateController.currentOrUpcomingState=" + 222 "${statusBarStateController.currentOrUpcomingState}") 223 } 224 println("hideSilentNotificationsOnLockscreen=$hideSilentNotificationsOnLockscreen") 225 } 226 227 private val isLockedOrLocking get() = 228 keyguardStateController.isShowing || 229 statusBarStateController.currentOrUpcomingState == StatusBarState.KEYGUARD 230 231 private fun readShowSilentNotificationSetting() { 232 val showSilentNotifs = 233 secureSettings.getBoolForUser(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 234 false, UserHandle.USER_CURRENT) 235 hideSilentNotificationsOnLockscreen = !showSilentNotifs 236 } 237 } 238