Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f9a3dd3 authored by Julia Tuttle's avatar Julia Tuttle
Browse files

Add VisualInterruptionSuppressor logic tests

Bug: 261728888
Test: atest VisualInterruptionDecisionProviderImplTest
Flag: ACONFIG com.android.systemui.visual_interruptions_refactor DEVELOPMENT
Change-Id: I563a12bbba7b036c2c2da75b7260caab136abd49
parent 84e94f27
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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)
+180 −0
Original line number Diff line number Diff line
@@ -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)
    }
}
+21 −21
Original line number Diff line number Diff line
@@ -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)