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