Migrate HUN/FSI checks to new Provider
Update HeadsUpCoordinator and associated tests to use the new VisualInterruptionDecisionProvider interface instead of the old NotificationInterruptStateProvider one. Bug: 261728888 Test: atest HeadsUpCoordinatorTest Change-Id: I5db314c6b6d7c378cc88add64376d5bc077a659f
This commit is contained in:
@@ -38,8 +38,7 @@ import com.android.systemui.statusbar.notification.collection.provider.LaunchFul
|
||||
import com.android.systemui.statusbar.notification.collection.render.NodeController
|
||||
import com.android.systemui.statusbar.notification.dagger.IncomingHeader
|
||||
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
|
||||
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider
|
||||
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
|
||||
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
|
||||
import com.android.systemui.statusbar.notification.logKey
|
||||
import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager
|
||||
@@ -69,12 +68,12 @@ class HeadsUpCoordinator @Inject constructor(
|
||||
private val mSystemClock: SystemClock,
|
||||
private val mHeadsUpManager: HeadsUpManager,
|
||||
private val mHeadsUpViewBinder: HeadsUpViewBinder,
|
||||
private val mNotificationInterruptStateProvider: NotificationInterruptStateProvider,
|
||||
private val mVisualInterruptionDecisionProvider: VisualInterruptionDecisionProvider,
|
||||
private val mRemoteInputManager: NotificationRemoteInputManager,
|
||||
private val mLaunchFullScreenIntentProvider: LaunchFullScreenIntentProvider,
|
||||
private val mFlags: NotifPipelineFlags,
|
||||
@IncomingHeader private val mIncomingHeaderController: NodeController,
|
||||
@Main private val mExecutor: DelayableExecutor,
|
||||
@Main private val mExecutor: DelayableExecutor
|
||||
) : Coordinator {
|
||||
private val mEntriesBindingUntil = ArrayMap<String, Long>()
|
||||
private val mEntriesUpdateTimes = ArrayMap<String, Long>()
|
||||
@@ -388,18 +387,21 @@ class HeadsUpCoordinator @Inject constructor(
|
||||
override fun onEntryAdded(entry: NotificationEntry) {
|
||||
// First check whether this notification should launch a full screen intent, and
|
||||
// launch it if needed.
|
||||
val fsiDecision = mNotificationInterruptStateProvider.getFullScreenIntentDecision(entry)
|
||||
mNotificationInterruptStateProvider.logFullScreenIntentDecision(entry, fsiDecision)
|
||||
if (fsiDecision.shouldLaunch) {
|
||||
val fsiDecision =
|
||||
mVisualInterruptionDecisionProvider.makeUnloggedFullScreenIntentDecision(entry)
|
||||
mVisualInterruptionDecisionProvider.logFullScreenIntentDecision(fsiDecision)
|
||||
if (fsiDecision.shouldInterrupt) {
|
||||
mLaunchFullScreenIntentProvider.launchFullScreenIntent(entry)
|
||||
} else if (fsiDecision == FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND) {
|
||||
} else if (fsiDecision.wouldInterruptWithoutDnd) {
|
||||
// If DND was the only reason this entry was suppressed, note it for potential
|
||||
// reconsideration on later ranking updates.
|
||||
addForFSIReconsideration(entry, mSystemClock.currentTimeMillis())
|
||||
}
|
||||
|
||||
// shouldHeadsUp includes check for whether this notification should be filtered
|
||||
val shouldHeadsUpEver = mNotificationInterruptStateProvider.shouldHeadsUp(entry)
|
||||
// makeAndLogHeadsUpDecision includes check for whether this notification should be
|
||||
// filtered
|
||||
val shouldHeadsUpEver =
|
||||
mVisualInterruptionDecisionProvider.makeAndLogHeadsUpDecision(entry).shouldInterrupt
|
||||
mPostedEntries[entry.key] = PostedEntry(
|
||||
entry,
|
||||
wasAdded = true,
|
||||
@@ -420,7 +422,8 @@ class HeadsUpCoordinator @Inject constructor(
|
||||
* up again.
|
||||
*/
|
||||
override fun onEntryUpdated(entry: NotificationEntry) {
|
||||
val shouldHeadsUpEver = mNotificationInterruptStateProvider.shouldHeadsUp(entry)
|
||||
val shouldHeadsUpEver =
|
||||
mVisualInterruptionDecisionProvider.makeAndLogHeadsUpDecision(entry).shouldInterrupt
|
||||
val shouldHeadsUpAgain = shouldHunAgain(entry)
|
||||
val isAlerting = mHeadsUpManager.isAlerting(entry.key)
|
||||
val isBinding = isEntryBinding(entry)
|
||||
@@ -510,26 +513,26 @@ class HeadsUpCoordinator @Inject constructor(
|
||||
// If any of these entries are no longer suppressed, launch the FSI now.
|
||||
if (isCandidateForFSIReconsideration(entry)) {
|
||||
val decision =
|
||||
mNotificationInterruptStateProvider.getFullScreenIntentDecision(entry)
|
||||
if (decision.shouldLaunch) {
|
||||
mVisualInterruptionDecisionProvider.makeUnloggedFullScreenIntentDecision(
|
||||
entry
|
||||
)
|
||||
if (decision.shouldInterrupt) {
|
||||
// Log both the launch of the full screen and also that this was via a
|
||||
// ranking update, and finally revoke candidacy for FSI reconsideration
|
||||
mLogger.logEntryUpdatedToFullScreen(entry.key, decision.name)
|
||||
mNotificationInterruptStateProvider.logFullScreenIntentDecision(
|
||||
entry, decision)
|
||||
mLogger.logEntryUpdatedToFullScreen(entry.key, decision.logReason)
|
||||
mVisualInterruptionDecisionProvider.logFullScreenIntentDecision(decision)
|
||||
mLaunchFullScreenIntentProvider.launchFullScreenIntent(entry)
|
||||
mFSIUpdateCandidates.remove(entry.key)
|
||||
|
||||
// if we launch the FSI then this is no longer a candidate for HUN
|
||||
continue
|
||||
} else if (decision == FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND) {
|
||||
} else if (decision.wouldInterruptWithoutDnd) {
|
||||
// decision has not changed; no need to log
|
||||
} else {
|
||||
// some other condition is now blocking FSI; log that and revoke candidacy
|
||||
// for FSI reconsideration
|
||||
mLogger.logEntryDisqualifiedFromFullScreen(entry.key, decision.name)
|
||||
mNotificationInterruptStateProvider.logFullScreenIntentDecision(
|
||||
entry, decision)
|
||||
mLogger.logEntryDisqualifiedFromFullScreen(entry.key, decision.logReason)
|
||||
mVisualInterruptionDecisionProvider.logFullScreenIntentDecision(decision)
|
||||
mFSIUpdateCandidates.remove(entry.key)
|
||||
}
|
||||
}
|
||||
@@ -539,13 +542,18 @@ class HeadsUpCoordinator @Inject constructor(
|
||||
// state
|
||||
// - if it is present in PostedEntries and the previous state of shouldHeadsUp
|
||||
// differs from the updated one
|
||||
val shouldHeadsUpEver = mNotificationInterruptStateProvider.checkHeadsUp(entry,
|
||||
/* log= */ false)
|
||||
val decision =
|
||||
mVisualInterruptionDecisionProvider.makeUnloggedHeadsUpDecision(entry)
|
||||
val shouldHeadsUpEver = decision.shouldInterrupt
|
||||
val postedShouldHeadsUpEver = mPostedEntries[entry.key]?.shouldHeadsUpEver ?: false
|
||||
val shouldUpdateEntry = postedShouldHeadsUpEver != shouldHeadsUpEver
|
||||
|
||||
if (shouldUpdateEntry) {
|
||||
mLogger.logEntryUpdatedByRanking(entry.key, shouldHeadsUpEver)
|
||||
mLogger.logEntryUpdatedByRanking(
|
||||
entry.key,
|
||||
shouldHeadsUpEver,
|
||||
decision.logReason
|
||||
)
|
||||
onEntryUpdated(entry)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,12 +61,13 @@ class HeadsUpCoordinatorLogger constructor(
|
||||
})
|
||||
}
|
||||
|
||||
fun logEntryUpdatedByRanking(key: String, shouldHun: Boolean) {
|
||||
fun logEntryUpdatedByRanking(key: String, shouldHun: Boolean, reason: String) {
|
||||
buffer.log(TAG, LogLevel.DEBUG, {
|
||||
str1 = key
|
||||
bool1 = shouldHun
|
||||
str2 = reason
|
||||
}, {
|
||||
"updating entry via ranking applied: $str1 updated shouldHeadsUp=$bool1"
|
||||
"updating entry via ranking applied: $str1 updated shouldHeadsUp=$bool1 because $str2"
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,10 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No
|
||||
import com.android.systemui.statusbar.notification.collection.provider.LaunchFullScreenIntentProvider
|
||||
import com.android.systemui.statusbar.notification.collection.render.NodeController
|
||||
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
|
||||
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider
|
||||
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
|
||||
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.DecisionImpl
|
||||
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.FullScreenIntentDecisionImpl
|
||||
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
|
||||
import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback
|
||||
import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager
|
||||
@@ -52,6 +54,7 @@ import com.android.systemui.util.mockito.withArgCaptor
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import java.util.ArrayList
|
||||
import java.util.function.Consumer
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
@@ -86,7 +89,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
|
||||
private val logger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true)
|
||||
private val headsUpManager: HeadsUpManager = mock()
|
||||
private val headsUpViewBinder: HeadsUpViewBinder = mock()
|
||||
private val notificationInterruptStateProvider: NotificationInterruptStateProvider = mock()
|
||||
private val visualInterruptionDecisionProvider: VisualInterruptionDecisionProvider = mock()
|
||||
private val remoteInputManager: NotificationRemoteInputManager = mock()
|
||||
private val endLifetimeExtension: OnEndLifetimeExtensionCallback = mock()
|
||||
private val headerController: NodeController = mock()
|
||||
@@ -114,7 +117,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
|
||||
systemClock,
|
||||
headsUpManager,
|
||||
headsUpViewBinder,
|
||||
notificationInterruptStateProvider,
|
||||
visualInterruptionDecisionProvider,
|
||||
remoteInputManager,
|
||||
launchFullScreenIntentProvider,
|
||||
flags,
|
||||
@@ -168,8 +171,11 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
|
||||
groupChild2 = helper.createChildNotification(GROUP_ALERT_ALL, 2, "child", 250)
|
||||
groupChild3 = helper.createChildNotification(GROUP_ALERT_ALL, 3, "child", 150)
|
||||
|
||||
// Set the default HUN decision
|
||||
setDefaultShouldHeadsUp(false)
|
||||
|
||||
// Set the default FSI decision
|
||||
setShouldFullScreen(any(), FullScreenIntentDecision.NO_FULL_SCREEN_INTENT)
|
||||
setDefaultShouldFullScreen(FullScreenIntentDecision.NO_FULL_SCREEN_INTENT)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1006,31 +1012,59 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
|
||||
verify(launchFullScreenIntentProvider, never()).launchFullScreenIntent(entry)
|
||||
}
|
||||
|
||||
private fun setShouldHeadsUp(entry: NotificationEntry, should: Boolean = true) {
|
||||
whenever(notificationInterruptStateProvider.shouldHeadsUp(entry)).thenReturn(should)
|
||||
whenever(notificationInterruptStateProvider.checkHeadsUp(eq(entry), any()))
|
||||
.thenReturn(should)
|
||||
private fun setDefaultShouldHeadsUp(should: Boolean) {
|
||||
whenever(visualInterruptionDecisionProvider.makeAndLogHeadsUpDecision(any()))
|
||||
.thenReturn(DecisionImpl.of(should))
|
||||
whenever(visualInterruptionDecisionProvider.makeUnloggedHeadsUpDecision(any()))
|
||||
.thenReturn(DecisionImpl.of(should))
|
||||
}
|
||||
|
||||
private fun setShouldFullScreen(entry: NotificationEntry, decision: FullScreenIntentDecision) {
|
||||
whenever(notificationInterruptStateProvider.getFullScreenIntentDecision(entry))
|
||||
.thenReturn(decision)
|
||||
private fun setShouldHeadsUp(entry: NotificationEntry, should: Boolean = true) {
|
||||
whenever(visualInterruptionDecisionProvider.makeAndLogHeadsUpDecision(entry))
|
||||
.thenReturn(DecisionImpl.of(should))
|
||||
whenever(visualInterruptionDecisionProvider.makeUnloggedHeadsUpDecision(entry))
|
||||
.thenReturn(DecisionImpl.of(should))
|
||||
}
|
||||
|
||||
private fun setDefaultShouldFullScreen(
|
||||
originalDecision: FullScreenIntentDecision
|
||||
) {
|
||||
val provider = visualInterruptionDecisionProvider
|
||||
whenever(provider.makeUnloggedFullScreenIntentDecision(any())).thenAnswer {
|
||||
val entry: NotificationEntry = it.getArgument(0)
|
||||
FullScreenIntentDecisionImpl(entry, originalDecision)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setShouldFullScreen(
|
||||
entry: NotificationEntry,
|
||||
originalDecision: FullScreenIntentDecision
|
||||
) {
|
||||
whenever(
|
||||
visualInterruptionDecisionProvider.makeUnloggedFullScreenIntentDecision(entry)
|
||||
).thenAnswer {
|
||||
FullScreenIntentDecisionImpl(entry, originalDecision)
|
||||
}
|
||||
}
|
||||
|
||||
private fun verifyLoggedFullScreenIntentDecision(
|
||||
entry: NotificationEntry,
|
||||
decision: FullScreenIntentDecision
|
||||
originalDecision: FullScreenIntentDecision
|
||||
) {
|
||||
verify(notificationInterruptStateProvider).logFullScreenIntentDecision(entry, decision)
|
||||
val decision = withArgCaptor {
|
||||
verify(visualInterruptionDecisionProvider).logFullScreenIntentDecision(capture())
|
||||
}
|
||||
check(decision is FullScreenIntentDecisionImpl)
|
||||
assertEquals(entry, decision.originalEntry)
|
||||
assertEquals(originalDecision, decision.originalDecision)
|
||||
}
|
||||
|
||||
private fun verifyNoFullScreenIntentDecisionLogged() {
|
||||
verify(notificationInterruptStateProvider, never())
|
||||
.logFullScreenIntentDecision(any(), any())
|
||||
verify(visualInterruptionDecisionProvider, never()).logFullScreenIntentDecision(any())
|
||||
}
|
||||
|
||||
private fun clearInterruptionProviderInvocations() {
|
||||
clearInvocations(notificationInterruptStateProvider)
|
||||
clearInvocations(visualInterruptionDecisionProvider)
|
||||
}
|
||||
|
||||
private fun finishBind(entry: NotificationEntry) {
|
||||
|
||||
Reference in New Issue
Block a user