diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt index aeae89cb3223e..7e53d5431353f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -31,6 +31,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.notification.stack.StackStateAnimator import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.KeyguardBypassController +import com.android.systemui.statusbar.phone.KeyguardBypassController.OnBypassStateChangedListener import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener @@ -38,7 +39,6 @@ import java.io.PrintWriter import javax.inject.Inject import kotlin.math.min - @SysUISingleton class NotificationWakeUpCoordinator @Inject constructor( dumpManager: DumpManager, @@ -68,6 +68,7 @@ class NotificationWakeUpCoordinator @Inject constructor( private var mLinearDozeAmount: Float = 0.0f private var mDozeAmount: Float = 0.0f private var mDozeAmountSource: String = "init" + private var mNotifsHiddenByDozeAmountOverride: Boolean = false private var mNotificationVisibleAmount = 0.0f private var mNotificationsVisible = false private var mNotificationsVisibleForExpansion = false @@ -130,6 +131,7 @@ class NotificationWakeUpCoordinator @Inject constructor( } } } + /** * True if we can show pulsing heads up notifications */ @@ -149,10 +151,19 @@ class NotificationWakeUpCoordinator @Inject constructor( return canShow } + private val bypassStateChangedListener = object : OnBypassStateChangedListener { + override fun onBypassStateChanged(isEnabled: Boolean) { + // When the bypass state changes, we have to check whether we should re-show the + // notifications by clearing the doze amount override which hides them. + maybeClearDozeAmountOverrideHidingNotifs() + } + } + init { dumpManager.registerDumpable(this) mHeadsUpManager.addListener(this) statusBarStateController.addCallback(this) + bypassController.registerOnBypassStateChangedListener(bypassStateChangedListener) addListener(object : WakeUpListener { override fun onFullyHiddenChanged(isFullyHidden: Boolean) { if (isFullyHidden && mNotificationsVisibleForExpansion) { @@ -261,12 +272,18 @@ class NotificationWakeUpCoordinator @Inject constructor( setDozeAmount(linear, eased, source = "StatusBar") } - fun setDozeAmount(linear: Float, eased: Float, source: String) { + fun setDozeAmount( + linear: Float, + eased: Float, + source: String, + hidesNotifsByOverride: Boolean = false + ) { val changed = linear != mLinearDozeAmount logger.logSetDozeAmount(linear, eased, source, statusBarStateController.state, changed) mLinearDozeAmount = linear mDozeAmount = eased mDozeAmountSource = source + mNotifsHiddenByDozeAmountOverride = hidesNotifsByOverride mStackScrollerController.setDozeAmount(mDozeAmount) updateHideAmount() if (changed && linear == 0.0f) { @@ -295,6 +312,8 @@ class NotificationWakeUpCoordinator @Inject constructor( return } + maybeClearDozeAmountOverrideHidingNotifs() + if (bypassController.bypassEnabled && newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED && (!statusBarStateController.isDozing || shouldAnimateVisibility())) { @@ -325,7 +344,8 @@ class NotificationWakeUpCoordinator @Inject constructor( private fun overrideDozeAmountIfBypass(): Boolean { if (bypassController.bypassEnabled) { if (statusBarStateController.state == StatusBarState.KEYGUARD) { - setDozeAmount(1f, 1f, source = "Override: bypass (keyguard)") + setDozeAmount(1f, 1f, source = "Override: bypass (keyguard)", + hidesNotifsByOverride = true) } else { setDozeAmount(0f, 0f, source = "Override: bypass (shade)") } @@ -334,6 +354,37 @@ class NotificationWakeUpCoordinator @Inject constructor( return false } + /** + * If the last [setDozeAmount] call was an override to hide notifications, then this call will + * check for the set of states that may have caused that override, and if none of them still + * apply, and the device is awake or not on the keyguard, then dozeAmount will be reset to 0. + * This fixes bugs where the bypass state changing could result in stale overrides, hiding + * notifications either on the inside screen or even after unlock. + */ + private fun maybeClearDozeAmountOverrideHidingNotifs() { + if (mNotifsHiddenByDozeAmountOverride) { + val onKeyguard = statusBarStateController.state == StatusBarState.KEYGUARD + val dozing = statusBarStateController.isDozing + val bypass = bypassController.bypassEnabled + val animating = + screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard() + // Overrides are set by [overrideDozeAmountIfAnimatingScreenOff] and + // [overrideDozeAmountIfBypass] based on 'animating' and 'bypass' respectively, so only + // clear the override if both those conditions are cleared. But also require either + // !dozing or !onKeyguard because those conditions should indicate that we intend + // notifications to be visible, and thus it is safe to unhide them. + val willRemove = (!onKeyguard || !dozing) && !bypass && !animating + logger.logMaybeClearDozeAmountOverrideHidingNotifs( + willRemove = willRemove, + onKeyguard = onKeyguard, dozing = dozing, + bypass = bypass, animating = animating, + ) + if (willRemove) { + setDozeAmount(0f, 0f, source = "Removed: $mDozeAmountSource") + } + } + } + /** * If we're playing the screen off animation, force the notification doze amount to be 1f (fully * dozing). This is needed so that the notifications aren't briefly visible as the screen turns @@ -344,7 +395,8 @@ class NotificationWakeUpCoordinator @Inject constructor( */ private fun overrideDozeAmountIfAnimatingScreenOff(linearDozeAmount: Float): Boolean { if (screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard()) { - setDozeAmount(1f, 1f, source = "Override: animating screen off") + setDozeAmount(1f, 1f, source = "Override: animating screen off", + hidesNotifsByOverride = true) return true } @@ -430,6 +482,7 @@ class NotificationWakeUpCoordinator @Inject constructor( pw.println("mLinearDozeAmount: $mLinearDozeAmount") pw.println("mDozeAmount: $mDozeAmount") pw.println("mDozeAmountSource: $mDozeAmountSource") + pw.println("mNotifsHiddenByDozeAmountOverride: $mNotifsHiddenByDozeAmountOverride") pw.println("mNotificationVisibleAmount: $mNotificationVisibleAmount") pw.println("mNotificationsVisible: $mNotificationsVisible") pw.println("mNotificationsVisibleForExpansion: $mNotificationsVisibleForExpansion") diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt index de18b0c4307d1..44645315ca802 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt @@ -46,6 +46,25 @@ constructor(@NotificationLog private val buffer: LogBuffer) { ) } + fun logMaybeClearDozeAmountOverrideHidingNotifs( + willRemove: Boolean, + onKeyguard: Boolean, + dozing: Boolean, + bypass: Boolean, + animating: Boolean, + ) { + buffer.log( + TAG, + DEBUG, + { + str1 = + "willRemove=$willRemove onKeyguard=$onKeyguard dozing=$dozing" + + " bypass=$bypass animating=$animating" + }, + { "maybeClearDozeAmountOverrideHidingNotifs() $str1" } + ) + } + fun logOnDozeAmountChanged(linear: Float, eased: Float) { buffer.log( TAG,