Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt +22 −22 Original line number Original line Diff line number Diff line Loading @@ -35,8 +35,7 @@ import org.junit.runner.RunWith @SmallTest @SmallTest @RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class) class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() { class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() { override val provider: VisualInterruptionDecisionProvider override val provider by lazy { get() = NotificationInterruptStateProviderWrapper( NotificationInterruptStateProviderWrapper( NotificationInterruptStateProviderImpl( NotificationInterruptStateProviderImpl( powerManager, powerManager, Loading @@ -57,6 +56,7 @@ class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecision ) ) .also { it.mUseHeadsUp = true } .also { it.mUseHeadsUp = true } ) ) } // Tests of internals of the wrapper: // Tests of internals of the wrapper: Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt +292 −94 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.app.NotificationManager.IMPORTANCE_HIGH import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE import android.app.PendingIntent import android.app.PendingIntent import android.app.PendingIntent.FLAG_MUTABLE import android.app.PendingIntent.FLAG_MUTABLE import android.content.Context import android.content.Intent import android.content.Intent import android.content.pm.UserInfo import android.content.pm.UserInfo import android.graphics.drawable.Icon import android.graphics.drawable.Icon Loading Loading @@ -53,6 +54,7 @@ import com.android.systemui.util.settings.FakeGlobalSettings import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.utils.leaks.FakeBatteryController import com.android.systemui.utils.leaks.FakeBatteryController import com.android.systemui.utils.leaks.LeakCheckedTest import com.android.systemui.utils.leaks.LeakCheckedTest import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test Loading Loading @@ -80,6 +82,23 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { protected abstract val provider: VisualInterruptionDecisionProvider protected abstract val provider: VisualInterruptionDecisionProvider private val neverSuppresses = object : NotificationInterruptSuppressor {} private val alwaysSuppressesInterruptions = object : NotificationInterruptSuppressor { override fun suppressInterruptions(entry: NotificationEntry?) = true } private val alwaysSuppressesAwakeInterruptions = object : NotificationInterruptSuppressor { override fun suppressAwakeInterruptions(entry: NotificationEntry?) = true } private val alwaysSuppressesAwakeHeadsUp = object : NotificationInterruptSuppressor { override fun suppressAwakeHeadsUp(entry: NotificationEntry?) = true } @Before @Before fun setUp() { fun setUp() { globalSettings.putInt(HEADS_UP_NOTIFICATIONS_ENABLED, HEADS_UP_ON) globalSettings.putInt(HEADS_UP_NOTIFICATIONS_ENABLED, HEADS_UP_ON) Loading @@ -87,154 +106,333 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { val user = UserInfo(ActivityManager.getCurrentUser(), "Current user", /* flags = */ 0) val user = UserInfo(ActivityManager.getCurrentUser(), "Current user", /* flags = */ 0) userTracker.set(listOf(user), /* currentUserIndex = */ 0) userTracker.set(listOf(user), /* currentUserIndex = */ 0) whenever(headsUpManager.isSnoozed(any())).thenReturn(false) whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any())) whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any())) .thenReturn(false) .thenReturn(false) } } @Test @Test fun testShouldPeek() { fun testShouldPeek() { ensureStateForPeek() ensurePeekState() assertShouldHeadsUp(buildPeekEntry()) } assertTrue(provider.makeUnloggedHeadsUpDecision(createPeekEntry()).shouldInterrupt) @Test fun testShouldPeek_defaultLegacySuppressor() { ensurePeekState() provider.addLegacySuppressor(neverSuppresses) assertShouldHeadsUp(buildPeekEntry()) } } @Test @Test fun testShouldPulse() { fun testShouldNotPeek_legacySuppressInterruptions() { ensureStateForPulse() ensurePeekState() provider.addLegacySuppressor(alwaysSuppressesInterruptions) assertShouldNotHeadsUp(buildPeekEntry()) } assertTrue(provider.makeUnloggedHeadsUpDecision(createPulseEntry()).shouldInterrupt) @Test fun testShouldNotPeek_legacySuppressAwakeInterruptions() { ensurePeekState() provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) assertShouldNotHeadsUp(buildPeekEntry()) } } @Test @Test fun testShouldFsi_awake() { fun testShouldNotPeek_legacySuppressAwakeHeadsUp() { ensureStateForAwakeFsi() ensurePeekState() provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) assertShouldNotHeadsUp(buildPeekEntry()) } assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) @Test fun testShouldPulse() { ensurePulseState() assertShouldHeadsUp(buildPulseEntry()) } } @Test @Test fun testShouldFsi_dreaming() { fun testShouldPulse_defaultLegacySuppressor() { ensureStateForDreamingFsi() ensurePulseState() provider.addLegacySuppressor(neverSuppresses) assertShouldHeadsUp(buildPulseEntry()) } assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) @Test fun testShouldNotPulse_legacySuppressInterruptions() { ensurePulseState() provider.addLegacySuppressor(alwaysSuppressesInterruptions) assertShouldNotHeadsUp(buildPulseEntry()) } } @Test @Test fun testShouldFsi_keyguard() { fun testShouldPulse_legacySuppressAwakeInterruptions() { ensureStateForKeyguardFsi() ensurePulseState() provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) assertShouldHeadsUp(buildPulseEntry()) } assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) @Test fun testShouldPulse_legacySuppressAwakeHeadsUp() { ensurePulseState() provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) assertShouldHeadsUp(buildPulseEntry()) } } @Test @Test fun testShouldBubble() { fun testShouldBubble() { assertTrue(provider.makeAndLogBubbleDecision(createBubbleEntry()).shouldInterrupt) ensureBubbleState() assertShouldBubble(buildBubbleEntry()) } @Test fun testShouldBubble_defaultLegacySuppressor() { ensureBubbleState() provider.addLegacySuppressor(neverSuppresses) assertShouldBubble(buildBubbleEntry()) } @Test fun testShouldNotBubble_legacySuppressInterruptions() { ensureBubbleState() provider.addLegacySuppressor(alwaysSuppressesInterruptions) assertShouldNotBubble(buildBubbleEntry()) } @Test fun testShouldNotBubble_legacySuppressAwakeInterruptions() { ensureBubbleState() provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) assertShouldNotBubble(buildBubbleEntry()) } } private fun ensureStateForPeek() { @Test whenever(powerManager.isScreenOn).thenReturn(true) fun testShouldBubble_legacySuppressAwakeHeadsUp() { statusBarStateController.dozing = false ensureBubbleState() statusBarStateController.dreaming = false provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) assertShouldBubble(buildBubbleEntry()) } } private fun ensureStateForPulse() { @Test ambientDisplayConfiguration.fakePulseOnNotificationEnabled = true fun testShouldFsi_notInteractive() { batteryController.setIsAodPowerSave(false) ensureNotInteractiveFsiState() statusBarStateController.dozing = true assertShouldFsi(buildFsiEntry()) } } private fun ensureStateForAwakeFsi() { @Test whenever(powerManager.isInteractive).thenReturn(false) fun testShouldFsi_dreaming() { statusBarStateController.dreaming = false ensureDreamingFsiState() statusBarStateController.state = SHADE assertShouldFsi(buildFsiEntry()) } @Test fun testShouldFsi_keyguard() { ensureKeyguardFsiState() assertShouldFsi(buildFsiEntry()) } private data class State( var hunSnoozed: Boolean? = null, var isAodPowerSave: Boolean? = null, var isDozing: Boolean? = null, var isDreaming: Boolean? = null, var isInteractive: Boolean? = null, var isScreenOn: Boolean? = null, var keyguardShouldHideNotification: Boolean? = null, var pulseOnNotificationsEnabled: Boolean? = null, var statusBarState: Int? = null, ) private fun setState(state: State): Unit = state.run { hunSnoozed?.let { whenever(headsUpManager.isSnoozed(TEST_PACKAGE)).thenReturn(it) } isAodPowerSave?.let { batteryController.setIsAodPowerSave(it) } isDozing?.let { statusBarStateController.dozing = it } isDreaming?.let { statusBarStateController.dreaming = it } isInteractive?.let { whenever(powerManager.isInteractive).thenReturn(it) } isScreenOn?.let { whenever(powerManager.isScreenOn).thenReturn(it) } keyguardShouldHideNotification?.let { whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any())) .thenReturn(it) } } private fun ensureStateForDreamingFsi() { pulseOnNotificationsEnabled?.let { whenever(powerManager.isInteractive).thenReturn(true) ambientDisplayConfiguration.fakePulseOnNotificationEnabled = it statusBarStateController.dreaming = true statusBarStateController.state = SHADE } } private fun ensureStateForKeyguardFsi() { statusBarState?.let { statusBarStateController.state = it } whenever(powerManager.isInteractive).thenReturn(true) statusBarStateController.dreaming = false statusBarStateController.state = KEYGUARD } } private fun createNotif( private fun ensureState(block: State.() -> Unit) = hasFsi: Boolean = false, State() bubbleMetadata: BubbleMetadata? = null ): Notification { return Notification.Builder(context, TEST_CHANNEL_ID) .apply { .apply { setContentTitle(TEST_CONTENT_TITLE) keyguardShouldHideNotification = false setContentText(TEST_CONTENT_TEXT) apply(block) } .run(this::setState) private fun ensurePeekState(block: State.() -> Unit = {}) = ensureState { hunSnoozed = false isDozing = false isDreaming = false isScreenOn = true run(block) } if (hasFsi) { private fun ensurePulseState(block: State.() -> Unit = {}) = ensureState { setFullScreenIntent(mock(), /* highPriority = */ true) isAodPowerSave = false isDozing = true pulseOnNotificationsEnabled = true run(block) } } if (bubbleMetadata != null) { private fun ensureBubbleState(block: State.() -> Unit = {}) = ensureState(block) setBubbleMetadata(bubbleMetadata) private fun ensureNotInteractiveFsiState(block: State.() -> Unit = {}) = ensureState { isDreaming = false isInteractive = false statusBarState = SHADE run(block) } } private fun ensureDreamingFsiState(block: State.() -> Unit = {}) = ensureState { isDreaming = true isInteractive = true statusBarState = SHADE run(block) } } .setContentTitle(TEST_CONTENT_TITLE) .setContentText(TEST_CONTENT_TEXT) private fun ensureKeyguardFsiState(block: State.() -> Unit = {}) = ensureState { .build() isDreaming = false isInteractive = true statusBarState = KEYGUARD run(block) } private fun assertShouldHeadsUp(entry: NotificationEntry) = provider.makeUnloggedHeadsUpDecision(entry).let { assertTrue("unexpected suppressed HUN: ${it.logReason}", it.shouldInterrupt) } private fun assertShouldNotHeadsUp(entry: NotificationEntry) = provider.makeUnloggedHeadsUpDecision(entry).let { assertFalse("unexpected unsuppressed HUN: ${it.logReason}", it.shouldInterrupt) } private fun assertShouldBubble(entry: NotificationEntry) = provider.makeAndLogBubbleDecision(entry).let { assertTrue("unexpected suppressed bubble: ${it.logReason}", it.shouldInterrupt) } private fun assertShouldNotBubble(entry: NotificationEntry) = provider.makeAndLogBubbleDecision(entry).let { assertFalse("unexpected unsuppressed bubble: ${it.logReason}", it.shouldInterrupt) } private fun assertShouldFsi(entry: NotificationEntry) = provider.makeUnloggedFullScreenIntentDecision(entry).let { assertTrue("unexpected suppressed FSI: ${it.logReason}", it.shouldInterrupt) } } private fun createBubbleMetadata(): BubbleMetadata { private fun assertShouldNotFsi(entry: NotificationEntry) = val pendingIntent = provider.makeUnloggedFullScreenIntentDecision(entry).let { assertFalse("unexpected unsuppressed FSI: ${it.logReason}", it.shouldInterrupt) } private class EntryBuilder(val context: Context) { var importance = IMPORTANCE_DEFAULT var suppressedVisualEffects: Int? = null var whenMs: Long? = null var visibilityOverride: Int? = null var hasFsi = false var canBubble: Boolean? = null var hasBubbleMetadata = false var bubbleSuppressNotification: Boolean? = null private fun buildBubbleMetadata() = BubbleMetadata.Builder( PendingIntent.getActivity( PendingIntent.getActivity( context, context, /* requestCode = */ 0, /* requestCode = */ 0, Intent().setPackage(context.packageName), Intent().setPackage(context.packageName), FLAG_MUTABLE FLAG_MUTABLE ), Icon.createWithResource(context.resources, R.drawable.android) ) ) .apply { bubbleSuppressNotification?.let { setSuppressNotification(it) } } .build() val icon = Icon.createWithResource(context.resources, R.drawable.android) fun build() = Notification.Builder(context, TEST_CHANNEL_ID) .apply { setContentTitle(TEST_CONTENT_TITLE) setContentText(TEST_CONTENT_TEXT) return BubbleMetadata.Builder(pendingIntent, icon).build() if (hasFsi) { setFullScreenIntent(mock(), /* highPriority = */ true) } } private fun createEntry( whenMs?.let { setWhen(it) } notif: Notification, importance: Int = IMPORTANCE_DEFAULT, if (hasBubbleMetadata) { canBubble: Boolean? = null setBubbleMetadata(buildBubbleMetadata()) ): NotificationEntry { } return NotificationEntryBuilder() } .build() .let { NotificationEntryBuilder().setNotification(it) } .apply { .apply { setPkg(TEST_PACKAGE) setPkg(TEST_PACKAGE) setOpPkg(TEST_PACKAGE) setOpPkg(TEST_PACKAGE) setTag(TEST_TAG) setTag(TEST_TAG) setChannel(NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance)) setNotification(notif) setImportance(importance) setImportance(importance) setChannel(NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance)) if (canBubble != null) { canBubble?.let { setCanBubble(it) } setCanBubble(canBubble) } } .build()!! .also { modifyRanking(it) .apply { suppressedVisualEffects?.let { setSuppressedVisualEffects(it) } visibilityOverride?.let { setVisibilityOverride(it) } } } .build() .build() } } } private fun createPeekEntry() = createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH) private fun buildEntry(block: EntryBuilder.() -> Unit) = EntryBuilder(context).also(block).build() private fun createPulseEntry() = private fun buildPeekEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH).also { importance = IMPORTANCE_HIGH modifyRanking(it).setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build() run(block) } } private fun createFsiEntry() = private fun buildPulseEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { createEntry(notif = createNotif(hasFsi = true), importance = IMPORTANCE_HIGH) importance = IMPORTANCE_DEFAULT visibilityOverride = VISIBILITY_NO_OVERRIDE run(block) } private fun createBubbleEntry() = private fun buildFsiEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { createEntry( importance = IMPORTANCE_HIGH notif = createNotif(bubbleMetadata = createBubbleMetadata()), hasFsi = true importance = IMPORTANCE_HIGH, run(block) } private fun buildBubbleEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { canBubble = true canBubble = true ) hasBubbleMetadata = true run(block) } private fun whenAgo(whenAgeMs: Long) = systemClock.currentTimeMillis() - whenAgeMs } } private const val TEST_CONTENT_TITLE = "Test Content Title" private const val TEST_CONTENT_TITLE = "Test Content Title" Loading packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt +1 −1 Original line number Original line Diff line number Diff line Loading @@ -104,7 +104,7 @@ class FakeStatusBarStateController : SysuiStatusBarStateController { override fun isDreaming() = dreaming override fun isDreaming() = dreaming override fun setIsDreaming(drreaming: Boolean): Boolean { override fun setIsDreaming(dreaming: Boolean): Boolean { dreaming != this.dreaming || return false dreaming != this.dreaming || return false this.dreaming = dreaming this.dreaming = dreaming callbacks.forEach { it.onDreamingChanged(dreaming) } callbacks.forEach { it.onDreamingChanged(dreaming) } Loading Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt +22 −22 Original line number Original line Diff line number Diff line Loading @@ -35,8 +35,7 @@ import org.junit.runner.RunWith @SmallTest @SmallTest @RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class) class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() { class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() { override val provider: VisualInterruptionDecisionProvider override val provider by lazy { get() = NotificationInterruptStateProviderWrapper( NotificationInterruptStateProviderWrapper( NotificationInterruptStateProviderImpl( NotificationInterruptStateProviderImpl( powerManager, powerManager, Loading @@ -57,6 +56,7 @@ class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecision ) ) .also { it.mUseHeadsUp = true } .also { it.mUseHeadsUp = true } ) ) } // Tests of internals of the wrapper: // Tests of internals of the wrapper: Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt +292 −94 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.app.NotificationManager.IMPORTANCE_HIGH import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE import android.app.PendingIntent import android.app.PendingIntent import android.app.PendingIntent.FLAG_MUTABLE import android.app.PendingIntent.FLAG_MUTABLE import android.content.Context import android.content.Intent import android.content.Intent import android.content.pm.UserInfo import android.content.pm.UserInfo import android.graphics.drawable.Icon import android.graphics.drawable.Icon Loading Loading @@ -53,6 +54,7 @@ import com.android.systemui.util.settings.FakeGlobalSettings import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.utils.leaks.FakeBatteryController import com.android.systemui.utils.leaks.FakeBatteryController import com.android.systemui.utils.leaks.LeakCheckedTest import com.android.systemui.utils.leaks.LeakCheckedTest import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test Loading Loading @@ -80,6 +82,23 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { protected abstract val provider: VisualInterruptionDecisionProvider protected abstract val provider: VisualInterruptionDecisionProvider private val neverSuppresses = object : NotificationInterruptSuppressor {} private val alwaysSuppressesInterruptions = object : NotificationInterruptSuppressor { override fun suppressInterruptions(entry: NotificationEntry?) = true } private val alwaysSuppressesAwakeInterruptions = object : NotificationInterruptSuppressor { override fun suppressAwakeInterruptions(entry: NotificationEntry?) = true } private val alwaysSuppressesAwakeHeadsUp = object : NotificationInterruptSuppressor { override fun suppressAwakeHeadsUp(entry: NotificationEntry?) = true } @Before @Before fun setUp() { fun setUp() { globalSettings.putInt(HEADS_UP_NOTIFICATIONS_ENABLED, HEADS_UP_ON) globalSettings.putInt(HEADS_UP_NOTIFICATIONS_ENABLED, HEADS_UP_ON) Loading @@ -87,154 +106,333 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { val user = UserInfo(ActivityManager.getCurrentUser(), "Current user", /* flags = */ 0) val user = UserInfo(ActivityManager.getCurrentUser(), "Current user", /* flags = */ 0) userTracker.set(listOf(user), /* currentUserIndex = */ 0) userTracker.set(listOf(user), /* currentUserIndex = */ 0) whenever(headsUpManager.isSnoozed(any())).thenReturn(false) whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any())) whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any())) .thenReturn(false) .thenReturn(false) } } @Test @Test fun testShouldPeek() { fun testShouldPeek() { ensureStateForPeek() ensurePeekState() assertShouldHeadsUp(buildPeekEntry()) } assertTrue(provider.makeUnloggedHeadsUpDecision(createPeekEntry()).shouldInterrupt) @Test fun testShouldPeek_defaultLegacySuppressor() { ensurePeekState() provider.addLegacySuppressor(neverSuppresses) assertShouldHeadsUp(buildPeekEntry()) } } @Test @Test fun testShouldPulse() { fun testShouldNotPeek_legacySuppressInterruptions() { ensureStateForPulse() ensurePeekState() provider.addLegacySuppressor(alwaysSuppressesInterruptions) assertShouldNotHeadsUp(buildPeekEntry()) } assertTrue(provider.makeUnloggedHeadsUpDecision(createPulseEntry()).shouldInterrupt) @Test fun testShouldNotPeek_legacySuppressAwakeInterruptions() { ensurePeekState() provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) assertShouldNotHeadsUp(buildPeekEntry()) } } @Test @Test fun testShouldFsi_awake() { fun testShouldNotPeek_legacySuppressAwakeHeadsUp() { ensureStateForAwakeFsi() ensurePeekState() provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) assertShouldNotHeadsUp(buildPeekEntry()) } assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) @Test fun testShouldPulse() { ensurePulseState() assertShouldHeadsUp(buildPulseEntry()) } } @Test @Test fun testShouldFsi_dreaming() { fun testShouldPulse_defaultLegacySuppressor() { ensureStateForDreamingFsi() ensurePulseState() provider.addLegacySuppressor(neverSuppresses) assertShouldHeadsUp(buildPulseEntry()) } assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) @Test fun testShouldNotPulse_legacySuppressInterruptions() { ensurePulseState() provider.addLegacySuppressor(alwaysSuppressesInterruptions) assertShouldNotHeadsUp(buildPulseEntry()) } } @Test @Test fun testShouldFsi_keyguard() { fun testShouldPulse_legacySuppressAwakeInterruptions() { ensureStateForKeyguardFsi() ensurePulseState() provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) assertShouldHeadsUp(buildPulseEntry()) } assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt) @Test fun testShouldPulse_legacySuppressAwakeHeadsUp() { ensurePulseState() provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) assertShouldHeadsUp(buildPulseEntry()) } } @Test @Test fun testShouldBubble() { fun testShouldBubble() { assertTrue(provider.makeAndLogBubbleDecision(createBubbleEntry()).shouldInterrupt) ensureBubbleState() assertShouldBubble(buildBubbleEntry()) } @Test fun testShouldBubble_defaultLegacySuppressor() { ensureBubbleState() provider.addLegacySuppressor(neverSuppresses) assertShouldBubble(buildBubbleEntry()) } @Test fun testShouldNotBubble_legacySuppressInterruptions() { ensureBubbleState() provider.addLegacySuppressor(alwaysSuppressesInterruptions) assertShouldNotBubble(buildBubbleEntry()) } @Test fun testShouldNotBubble_legacySuppressAwakeInterruptions() { ensureBubbleState() provider.addLegacySuppressor(alwaysSuppressesAwakeInterruptions) assertShouldNotBubble(buildBubbleEntry()) } } private fun ensureStateForPeek() { @Test whenever(powerManager.isScreenOn).thenReturn(true) fun testShouldBubble_legacySuppressAwakeHeadsUp() { statusBarStateController.dozing = false ensureBubbleState() statusBarStateController.dreaming = false provider.addLegacySuppressor(alwaysSuppressesAwakeHeadsUp) assertShouldBubble(buildBubbleEntry()) } } private fun ensureStateForPulse() { @Test ambientDisplayConfiguration.fakePulseOnNotificationEnabled = true fun testShouldFsi_notInteractive() { batteryController.setIsAodPowerSave(false) ensureNotInteractiveFsiState() statusBarStateController.dozing = true assertShouldFsi(buildFsiEntry()) } } private fun ensureStateForAwakeFsi() { @Test whenever(powerManager.isInteractive).thenReturn(false) fun testShouldFsi_dreaming() { statusBarStateController.dreaming = false ensureDreamingFsiState() statusBarStateController.state = SHADE assertShouldFsi(buildFsiEntry()) } @Test fun testShouldFsi_keyguard() { ensureKeyguardFsiState() assertShouldFsi(buildFsiEntry()) } private data class State( var hunSnoozed: Boolean? = null, var isAodPowerSave: Boolean? = null, var isDozing: Boolean? = null, var isDreaming: Boolean? = null, var isInteractive: Boolean? = null, var isScreenOn: Boolean? = null, var keyguardShouldHideNotification: Boolean? = null, var pulseOnNotificationsEnabled: Boolean? = null, var statusBarState: Int? = null, ) private fun setState(state: State): Unit = state.run { hunSnoozed?.let { whenever(headsUpManager.isSnoozed(TEST_PACKAGE)).thenReturn(it) } isAodPowerSave?.let { batteryController.setIsAodPowerSave(it) } isDozing?.let { statusBarStateController.dozing = it } isDreaming?.let { statusBarStateController.dreaming = it } isInteractive?.let { whenever(powerManager.isInteractive).thenReturn(it) } isScreenOn?.let { whenever(powerManager.isScreenOn).thenReturn(it) } keyguardShouldHideNotification?.let { whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any())) .thenReturn(it) } } private fun ensureStateForDreamingFsi() { pulseOnNotificationsEnabled?.let { whenever(powerManager.isInteractive).thenReturn(true) ambientDisplayConfiguration.fakePulseOnNotificationEnabled = it statusBarStateController.dreaming = true statusBarStateController.state = SHADE } } private fun ensureStateForKeyguardFsi() { statusBarState?.let { statusBarStateController.state = it } whenever(powerManager.isInteractive).thenReturn(true) statusBarStateController.dreaming = false statusBarStateController.state = KEYGUARD } } private fun createNotif( private fun ensureState(block: State.() -> Unit) = hasFsi: Boolean = false, State() bubbleMetadata: BubbleMetadata? = null ): Notification { return Notification.Builder(context, TEST_CHANNEL_ID) .apply { .apply { setContentTitle(TEST_CONTENT_TITLE) keyguardShouldHideNotification = false setContentText(TEST_CONTENT_TEXT) apply(block) } .run(this::setState) private fun ensurePeekState(block: State.() -> Unit = {}) = ensureState { hunSnoozed = false isDozing = false isDreaming = false isScreenOn = true run(block) } if (hasFsi) { private fun ensurePulseState(block: State.() -> Unit = {}) = ensureState { setFullScreenIntent(mock(), /* highPriority = */ true) isAodPowerSave = false isDozing = true pulseOnNotificationsEnabled = true run(block) } } if (bubbleMetadata != null) { private fun ensureBubbleState(block: State.() -> Unit = {}) = ensureState(block) setBubbleMetadata(bubbleMetadata) private fun ensureNotInteractiveFsiState(block: State.() -> Unit = {}) = ensureState { isDreaming = false isInteractive = false statusBarState = SHADE run(block) } } private fun ensureDreamingFsiState(block: State.() -> Unit = {}) = ensureState { isDreaming = true isInteractive = true statusBarState = SHADE run(block) } } .setContentTitle(TEST_CONTENT_TITLE) .setContentText(TEST_CONTENT_TEXT) private fun ensureKeyguardFsiState(block: State.() -> Unit = {}) = ensureState { .build() isDreaming = false isInteractive = true statusBarState = KEYGUARD run(block) } private fun assertShouldHeadsUp(entry: NotificationEntry) = provider.makeUnloggedHeadsUpDecision(entry).let { assertTrue("unexpected suppressed HUN: ${it.logReason}", it.shouldInterrupt) } private fun assertShouldNotHeadsUp(entry: NotificationEntry) = provider.makeUnloggedHeadsUpDecision(entry).let { assertFalse("unexpected unsuppressed HUN: ${it.logReason}", it.shouldInterrupt) } private fun assertShouldBubble(entry: NotificationEntry) = provider.makeAndLogBubbleDecision(entry).let { assertTrue("unexpected suppressed bubble: ${it.logReason}", it.shouldInterrupt) } private fun assertShouldNotBubble(entry: NotificationEntry) = provider.makeAndLogBubbleDecision(entry).let { assertFalse("unexpected unsuppressed bubble: ${it.logReason}", it.shouldInterrupt) } private fun assertShouldFsi(entry: NotificationEntry) = provider.makeUnloggedFullScreenIntentDecision(entry).let { assertTrue("unexpected suppressed FSI: ${it.logReason}", it.shouldInterrupt) } } private fun createBubbleMetadata(): BubbleMetadata { private fun assertShouldNotFsi(entry: NotificationEntry) = val pendingIntent = provider.makeUnloggedFullScreenIntentDecision(entry).let { assertFalse("unexpected unsuppressed FSI: ${it.logReason}", it.shouldInterrupt) } private class EntryBuilder(val context: Context) { var importance = IMPORTANCE_DEFAULT var suppressedVisualEffects: Int? = null var whenMs: Long? = null var visibilityOverride: Int? = null var hasFsi = false var canBubble: Boolean? = null var hasBubbleMetadata = false var bubbleSuppressNotification: Boolean? = null private fun buildBubbleMetadata() = BubbleMetadata.Builder( PendingIntent.getActivity( PendingIntent.getActivity( context, context, /* requestCode = */ 0, /* requestCode = */ 0, Intent().setPackage(context.packageName), Intent().setPackage(context.packageName), FLAG_MUTABLE FLAG_MUTABLE ), Icon.createWithResource(context.resources, R.drawable.android) ) ) .apply { bubbleSuppressNotification?.let { setSuppressNotification(it) } } .build() val icon = Icon.createWithResource(context.resources, R.drawable.android) fun build() = Notification.Builder(context, TEST_CHANNEL_ID) .apply { setContentTitle(TEST_CONTENT_TITLE) setContentText(TEST_CONTENT_TEXT) return BubbleMetadata.Builder(pendingIntent, icon).build() if (hasFsi) { setFullScreenIntent(mock(), /* highPriority = */ true) } } private fun createEntry( whenMs?.let { setWhen(it) } notif: Notification, importance: Int = IMPORTANCE_DEFAULT, if (hasBubbleMetadata) { canBubble: Boolean? = null setBubbleMetadata(buildBubbleMetadata()) ): NotificationEntry { } return NotificationEntryBuilder() } .build() .let { NotificationEntryBuilder().setNotification(it) } .apply { .apply { setPkg(TEST_PACKAGE) setPkg(TEST_PACKAGE) setOpPkg(TEST_PACKAGE) setOpPkg(TEST_PACKAGE) setTag(TEST_TAG) setTag(TEST_TAG) setChannel(NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance)) setNotification(notif) setImportance(importance) setImportance(importance) setChannel(NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance)) if (canBubble != null) { canBubble?.let { setCanBubble(it) } setCanBubble(canBubble) } } .build()!! .also { modifyRanking(it) .apply { suppressedVisualEffects?.let { setSuppressedVisualEffects(it) } visibilityOverride?.let { setVisibilityOverride(it) } } } .build() .build() } } } private fun createPeekEntry() = createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH) private fun buildEntry(block: EntryBuilder.() -> Unit) = EntryBuilder(context).also(block).build() private fun createPulseEntry() = private fun buildPeekEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH).also { importance = IMPORTANCE_HIGH modifyRanking(it).setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build() run(block) } } private fun createFsiEntry() = private fun buildPulseEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { createEntry(notif = createNotif(hasFsi = true), importance = IMPORTANCE_HIGH) importance = IMPORTANCE_DEFAULT visibilityOverride = VISIBILITY_NO_OVERRIDE run(block) } private fun createBubbleEntry() = private fun buildFsiEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { createEntry( importance = IMPORTANCE_HIGH notif = createNotif(bubbleMetadata = createBubbleMetadata()), hasFsi = true importance = IMPORTANCE_HIGH, run(block) } private fun buildBubbleEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { canBubble = true canBubble = true ) hasBubbleMetadata = true run(block) } private fun whenAgo(whenAgeMs: Long) = systemClock.currentTimeMillis() - whenAgeMs } } private const val TEST_CONTENT_TITLE = "Test Content Title" private const val TEST_CONTENT_TITLE = "Test Content Title" Loading
packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt +1 −1 Original line number Original line Diff line number Diff line Loading @@ -104,7 +104,7 @@ class FakeStatusBarStateController : SysuiStatusBarStateController { override fun isDreaming() = dreaming override fun isDreaming() = dreaming override fun setIsDreaming(drreaming: Boolean): Boolean { override fun setIsDreaming(dreaming: Boolean): Boolean { dreaming != this.dreaming || return false dreaming != this.dreaming || return false this.dreaming = dreaming this.dreaming = dreaming callbacks.forEach { it.onDreamingChanged(dreaming) } callbacks.forEach { it.onDreamingChanged(dreaming) } Loading