diff options
| author | 2023-11-01 22:49:10 -0400 | |
|---|---|---|
| committer | 2023-11-01 22:55:01 -0400 | |
| commit | 5f9a3dd31b57d83f1bdd7304155a1efd7d299ed7 (patch) | |
| tree | 8dc944c98704b08ad394a701344863caebf39a33 | |
| parent | 84e94f27d4bffc93be07f6a98cf6d07e5d7a73fe (diff) | |
Add VisualInterruptionSuppressor logic tests
Bug: 261728888
Test: atest VisualInterruptionDecisionProviderImplTest
Flag: ACONFIG com.android.systemui.visual_interruptions_refactor DEVELOPMENT
Change-Id: I563a12bbba7b036c2c2da75b7260caab136abd49
3 files changed, 212 insertions, 21 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt index f0fe56db9fdd..2730683a31c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt @@ -19,6 +19,7 @@ import android.hardware.display.AmbientDisplayConfiguration import android.os.Handler import android.os.PowerManager import android.util.Log +import com.android.internal.annotations.VisibleForTesting import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.settings.UserTracker @@ -106,11 +107,21 @@ constructor( condition.start() } + @VisibleForTesting + fun removeCondition(condition: VisualInterruptionCondition) { + conditions.remove(condition) + } + fun addFilter(filter: VisualInterruptionFilter) { filters.add(filter) filter.start() } + @VisibleForTesting + fun removeFilter(filter: VisualInterruptionFilter) { + filters.remove(filter) + } + override fun makeUnloggedHeadsUpDecision(entry: NotificationEntry): Decision { check(started) return makeHeadsUpDecision(entry) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt index eda65e671676..80d941a40cb5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt @@ -18,6 +18,11 @@ package com.android.systemui.statusbar.notification.interruption import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.BUBBLE +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PEEK +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE +import org.junit.Test import org.junit.runner.RunWith @SmallTest @@ -38,4 +43,179 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro userTracker, ) } + + @Test + fun testNothingCondition_suppressesNothing() { + withCondition(TestCondition(types = emptySet()) { true }) { + assertPeekNotSuppressed() + assertPulseNotSuppressed() + assertBubbleNotSuppressed() + } + } + + @Test + fun testNothingFilter_suppressesNothing() { + withFilter(TestFilter(types = emptySet()) { true }) { + assertPeekNotSuppressed() + assertPulseNotSuppressed() + assertBubbleNotSuppressed() + } + } + + @Test + fun testPeekCondition_suppressesOnlyPeek() { + withCondition(TestCondition(types = setOf(PEEK)) { true }) { + assertPeekSuppressed() + assertPulseNotSuppressed() + assertBubbleNotSuppressed() + } + } + + @Test + fun testPeekFilter_suppressesOnlyPeek() { + withFilter(TestFilter(types = setOf(PEEK)) { true }) { + assertPeekSuppressed() + assertPulseNotSuppressed() + assertBubbleNotSuppressed() + } + } + + @Test + fun testPulseCondition_suppressesOnlyPulse() { + withCondition(TestCondition(types = setOf(PULSE)) { true }) { + assertPeekNotSuppressed() + assertPulseSuppressed() + assertBubbleNotSuppressed() + } + } + + @Test + fun testPulseFilter_suppressesOnlyPulse() { + withFilter(TestFilter(types = setOf(PULSE)) { true }) { + assertPeekNotSuppressed() + assertPulseSuppressed() + assertBubbleNotSuppressed() + } + } + + @Test + fun testBubbleCondition_suppressesOnlyBubble() { + withCondition(TestCondition(types = setOf(BUBBLE)) { true }) { + assertPeekNotSuppressed() + assertPulseNotSuppressed() + assertBubbleSuppressed() + } + } + + @Test + fun testBubbleFilter_suppressesOnlyBubble() { + withFilter(TestFilter(types = setOf(BUBBLE)) { true }) { + assertPeekNotSuppressed() + assertPulseNotSuppressed() + assertBubbleSuppressed() + } + } + + @Test + fun testCondition_differentState() { + ensurePeekState() + val entry = buildPeekEntry() + + var stateShouldSuppress = false + withCondition(TestCondition(types = setOf(PEEK)) { stateShouldSuppress }) { + assertShouldHeadsUp(entry) + + stateShouldSuppress = true + assertShouldNotHeadsUp(entry) + + stateShouldSuppress = false + assertShouldHeadsUp(entry) + } + } + + @Test + fun testFilter_differentState() { + ensurePeekState() + val entry = buildPeekEntry() + + var stateShouldSuppress = false + withFilter(TestFilter(types = setOf(PEEK)) { stateShouldSuppress }) { + assertShouldHeadsUp(entry) + + stateShouldSuppress = true + assertShouldNotHeadsUp(entry) + + stateShouldSuppress = false + assertShouldHeadsUp(entry) + } + } + + @Test + fun testFilter_differentNotif() { + ensurePeekState() + + val suppressedEntry = buildPeekEntry() + val unsuppressedEntry = buildPeekEntry() + + withFilter(TestFilter(types = setOf(PEEK)) { it == suppressedEntry }) { + assertShouldNotHeadsUp(suppressedEntry) + assertShouldHeadsUp(unsuppressedEntry) + } + } + + private fun assertPeekSuppressed() { + ensurePeekState() + assertShouldNotHeadsUp(buildPeekEntry()) + } + + private fun assertPeekNotSuppressed() { + ensurePeekState() + assertShouldHeadsUp(buildPeekEntry()) + } + + private fun assertPulseSuppressed() { + ensurePulseState() + assertShouldNotHeadsUp(buildPulseEntry()) + } + + private fun assertPulseNotSuppressed() { + ensurePulseState() + assertShouldHeadsUp(buildPulseEntry()) + } + + private fun assertBubbleSuppressed() { + ensureBubbleState() + assertShouldNotBubble(buildBubbleEntry()) + } + + private fun assertBubbleNotSuppressed() { + ensureBubbleState() + assertShouldBubble(buildBubbleEntry()) + } + + private fun withCondition(condition: VisualInterruptionCondition, block: () -> Unit) { + provider.addCondition(condition) + block() + provider.removeCondition(condition) + } + + private fun withFilter(filter: VisualInterruptionFilter, block: () -> Unit) { + provider.addFilter(filter) + block() + provider.removeFilter(filter) + } + + private class TestCondition( + types: Set<VisualInterruptionType>, + val onShouldSuppress: () -> Boolean + ) : VisualInterruptionCondition(types = types, reason = "") { + override fun shouldSuppress(): Boolean = onShouldSuppress() + } + + private class TestFilter( + types: Set<VisualInterruptionType>, + val onShouldSuppress: (NotificationEntry) -> Boolean = { true } + ) : VisualInterruptionFilter(types = types, reason = "") { + override fun shouldSuppress(entry: NotificationEntry) = onShouldSuppress(entry) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt index 35ce027e8c41..7f12b22f2b4e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt @@ -494,7 +494,7 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { assertShouldFsi(buildFsiEntry()) } - private data class State( + protected data class State( var hunSettingEnabled: Boolean? = null, var hunSnoozed: Boolean? = null, var isAodPowerSave: Boolean? = null, @@ -507,7 +507,7 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { var statusBarState: Int? = null, ) - private fun setState(state: State): Unit = + protected fun setState(state: State): Unit = state.run { hunSettingEnabled?.let { val newSetting = if (it) HEADS_UP_ON else HEADS_UP_OFF @@ -538,7 +538,7 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { statusBarState?.let { statusBarStateController.state = it } } - private fun ensureState(block: State.() -> Unit) = + protected fun ensureState(block: State.() -> Unit) = State() .apply { keyguardShouldHideNotification = false @@ -546,7 +546,7 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { } .run(this::setState) - private fun ensurePeekState(block: State.() -> Unit = {}) = ensureState { + protected fun ensurePeekState(block: State.() -> Unit = {}) = ensureState { hunSettingEnabled = true hunSnoozed = false isDozing = false @@ -555,67 +555,67 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { run(block) } - private fun ensurePulseState(block: State.() -> Unit = {}) = ensureState { + protected fun ensurePulseState(block: State.() -> Unit = {}) = ensureState { isAodPowerSave = false isDozing = true pulseOnNotificationsEnabled = true run(block) } - private fun ensureBubbleState(block: State.() -> Unit = {}) = ensureState(block) + protected fun ensureBubbleState(block: State.() -> Unit = {}) = ensureState(block) - private fun ensureNotInteractiveFsiState(block: State.() -> Unit = {}) = ensureState { + protected fun ensureNotInteractiveFsiState(block: State.() -> Unit = {}) = ensureState { isDreaming = false isInteractive = false statusBarState = SHADE run(block) } - private fun ensureDreamingFsiState(block: State.() -> Unit = {}) = ensureState { + protected fun ensureDreamingFsiState(block: State.() -> Unit = {}) = ensureState { isDreaming = true isInteractive = true statusBarState = SHADE run(block) } - private fun ensureKeyguardFsiState(block: State.() -> Unit = {}) = ensureState { + protected fun ensureKeyguardFsiState(block: State.() -> Unit = {}) = ensureState { isDreaming = false isInteractive = true statusBarState = KEYGUARD run(block) } - private fun assertShouldHeadsUp(entry: NotificationEntry) = + protected fun assertShouldHeadsUp(entry: NotificationEntry) = provider.makeUnloggedHeadsUpDecision(entry).let { assertTrue("unexpected suppressed HUN: ${it.logReason}", it.shouldInterrupt) } - private fun assertShouldNotHeadsUp(entry: NotificationEntry) = + protected fun assertShouldNotHeadsUp(entry: NotificationEntry) = provider.makeUnloggedHeadsUpDecision(entry).let { assertFalse("unexpected unsuppressed HUN: ${it.logReason}", it.shouldInterrupt) } - private fun assertShouldBubble(entry: NotificationEntry) = + protected fun assertShouldBubble(entry: NotificationEntry) = provider.makeAndLogBubbleDecision(entry).let { assertTrue("unexpected suppressed bubble: ${it.logReason}", it.shouldInterrupt) } - private fun assertShouldNotBubble(entry: NotificationEntry) = + protected fun assertShouldNotBubble(entry: NotificationEntry) = provider.makeAndLogBubbleDecision(entry).let { assertFalse("unexpected unsuppressed bubble: ${it.logReason}", it.shouldInterrupt) } - private fun assertShouldFsi(entry: NotificationEntry) = + protected fun assertShouldFsi(entry: NotificationEntry) = provider.makeUnloggedFullScreenIntentDecision(entry).let { assertTrue("unexpected suppressed FSI: ${it.logReason}", it.shouldInterrupt) } - private fun assertShouldNotFsi(entry: NotificationEntry) = + protected fun assertShouldNotFsi(entry: NotificationEntry) = provider.makeUnloggedFullScreenIntentDecision(entry).let { assertFalse("unexpected unsuppressed FSI: ${it.logReason}", it.shouldInterrupt) } - private class EntryBuilder(val context: Context) { + protected class EntryBuilder(val context: Context) { var importance = IMPORTANCE_DEFAULT var suppressedVisualEffects: Int? = null var whenMs: Long? = null @@ -708,27 +708,27 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { } } - private fun buildEntry(block: EntryBuilder.() -> Unit) = + protected fun buildEntry(block: EntryBuilder.() -> Unit) = EntryBuilder(context).also(block).build() - private fun buildPeekEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { + protected fun buildPeekEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { importance = IMPORTANCE_HIGH run(block) } - private fun buildPulseEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { + protected fun buildPulseEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { importance = IMPORTANCE_DEFAULT visibilityOverride = VISIBILITY_NO_OVERRIDE run(block) } - private fun buildBubbleEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { + protected fun buildBubbleEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { canBubble = true hasBubbleMetadata = true run(block) } - private fun buildFsiEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { + protected fun buildFsiEntry(block: EntryBuilder.() -> Unit = {}) = buildEntry { importance = IMPORTANCE_HIGH hasFsi = true run(block) |