diff options
7 files changed, 147 insertions, 59 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt index a901c5f8ae2a..87f11f131f32 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.interruption +import android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST import android.app.Notification import android.app.Notification.BubbleMetadata import android.app.Notification.CATEGORY_EVENT @@ -23,6 +24,8 @@ import android.app.Notification.CATEGORY_REMINDER import android.app.Notification.VISIBILITY_PRIVATE import android.app.NotificationManager.IMPORTANCE_DEFAULT import android.app.NotificationManager.IMPORTANCE_HIGH +import android.content.pm.PackageManager +import android.content.pm.PackageManager.PERMISSION_GRANTED import android.database.ContentObserver import android.hardware.display.AmbientDisplayConfiguration import android.os.Handler @@ -234,6 +237,7 @@ class AvalancheSuppressor( private val avalancheProvider: AvalancheProvider, private val systemClock: SystemClock, private val systemSettings: SystemSettings, + private val packageManager: PackageManager, ) : VisualInterruptionFilter( types = setOf(PEEK, PULSE), @@ -249,6 +253,7 @@ class AvalancheSuppressor( ALLOW_CATEGORY_EVENT, ALLOW_FSI_WITH_PERMISSION_ON, ALLOW_COLORIZED, + ALLOW_EMERGENCY, SUPPRESS } @@ -299,13 +304,20 @@ class AvalancheSuppressor( if (entry.sbn.notification.isColorized) { return State.ALLOW_COLORIZED } + if (entry.sbn.notification.isColorized) { + return State.ALLOW_COLORIZED + } + if ( + packageManager.checkPermission(RECEIVE_EMERGENCY_BROADCAST, entry.sbn.packageName) == + PERMISSION_GRANTED + ) { + return State.ALLOW_EMERGENCY + } return State.SUPPRESS } private fun isCooldownEnabled(): Boolean { - return systemSettings.getInt( - Settings.System.NOTIFICATION_COOLDOWN_ENABLED, - /* def */ 1 - ) == 1 + return systemSettings.getInt(Settings.System.NOTIFICATION_COOLDOWN_ENABLED, /* def */ 1) == + 1 } } 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 e6d97c211dc5..f68e194aace2 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 @@ -15,6 +15,7 @@ */ package com.android.systemui.statusbar.notification.interruption +import android.content.pm.PackageManager import android.hardware.display.AmbientDisplayConfiguration import android.os.Handler import android.os.PowerManager @@ -63,7 +64,8 @@ constructor( private val uiEventLogger: UiEventLogger, private val userTracker: UserTracker, private val avalancheProvider: AvalancheProvider, - private val systemSettings: SystemSettings + private val systemSettings: SystemSettings, + private val packageManager: PackageManager ) : VisualInterruptionDecisionProvider { init { @@ -172,7 +174,9 @@ constructor( addFilter(AlertKeyguardVisibilitySuppressor(keyguardNotificationVisibilityProvider)) if (NotificationAvalancheSuppression.isEnabled) { - addFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) + addFilter( + AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager) + ) avalancheProvider.register() } started = true @@ -232,14 +236,17 @@ constructor( private fun makeLoggablePeekDecision(entry: NotificationEntry): LoggableDecision = checkConditions(PEEK) - ?: checkFilters(PEEK, entry) ?: checkSuppressInterruptions(entry) - ?: checkSuppressAwakeInterruptions(entry) ?: checkSuppressAwakeHeadsUp(entry) - ?: LoggableDecision.unsuppressed + ?: checkFilters(PEEK, entry) + ?: checkSuppressInterruptions(entry) + ?: checkSuppressAwakeInterruptions(entry) + ?: checkSuppressAwakeHeadsUp(entry) + ?: LoggableDecision.unsuppressed private fun makeLoggablePulseDecision(entry: NotificationEntry): LoggableDecision = checkConditions(PULSE) - ?: checkFilters(PULSE, entry) ?: checkSuppressInterruptions(entry) - ?: LoggableDecision.unsuppressed + ?: checkFilters(PULSE, entry) + ?: checkSuppressInterruptions(entry) + ?: LoggableDecision.unsuppressed override fun makeAndLogBubbleDecision(entry: NotificationEntry): Decision = traceSection("VisualInterruptionDecisionProviderImpl#makeAndLogBubbleDecision") { @@ -252,8 +259,10 @@ constructor( private fun makeLoggableBubbleDecision(entry: NotificationEntry): LoggableDecision = checkConditions(BUBBLE) - ?: checkFilters(BUBBLE, entry) ?: checkSuppressInterruptions(entry) - ?: checkSuppressAwakeInterruptions(entry) ?: LoggableDecision.unsuppressed + ?: checkFilters(BUBBLE, entry) + ?: checkSuppressInterruptions(entry) + ?: checkSuppressAwakeInterruptions(entry) + ?: LoggableDecision.unsuppressed private fun logDecision( type: VisualInterruptionType, 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 1870194f21f4..eeb51a684d42 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 @@ -16,9 +16,11 @@ package com.android.systemui.statusbar.notification.interruption +import android.Manifest.permission import android.app.Notification.CATEGORY_EVENT import android.app.Notification.CATEGORY_REMINDER import android.app.NotificationManager +import android.content.pm.PackageManager.PERMISSION_GRANTED import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -28,6 +30,8 @@ import com.android.systemui.statusbar.notification.interruption.VisualInterrupti import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito.anyString +import org.mockito.Mockito.`when` @SmallTest @RunWith(AndroidJUnit4::class) @@ -51,7 +55,8 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro uiEventLogger, userTracker, avalancheProvider, - systemSettings + systemSettings, + packageManager ) } @@ -83,14 +88,18 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro fun testAvalancheFilter_duringAvalanche_allowConversationFromAfterEvent() { avalancheProvider.startTime = whenAgo(10) - withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) { + withFilter( + AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager) + ) { ensurePeekState() - assertShouldHeadsUp(buildEntry { - importance = NotificationManager.IMPORTANCE_HIGH - isConversation = true - isImportantConversation = false - whenMs = whenAgo(5) - }) + assertShouldHeadsUp( + buildEntry { + importance = NotificationManager.IMPORTANCE_HIGH + isConversation = true + isImportantConversation = false + whenMs = whenAgo(5) + } + ) } } @@ -98,14 +107,18 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro fun testAvalancheFilter_duringAvalanche_suppressConversationFromBeforeEvent() { avalancheProvider.startTime = whenAgo(10) - withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) { + withFilter( + AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager) + ) { ensurePeekState() - assertShouldNotHeadsUp(buildEntry { - importance = NotificationManager.IMPORTANCE_DEFAULT - isConversation = true - isImportantConversation = false - whenMs = whenAgo(15) - }) + assertShouldNotHeadsUp( + buildEntry { + importance = NotificationManager.IMPORTANCE_DEFAULT + isConversation = true + isImportantConversation = false + whenMs = whenAgo(15) + } + ) } } @@ -113,12 +126,16 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro fun testAvalancheFilter_duringAvalanche_allowHighPriorityConversation() { avalancheProvider.startTime = whenAgo(10) - withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) { + withFilter( + AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager) + ) { ensurePeekState() - assertShouldHeadsUp(buildEntry { - importance = NotificationManager.IMPORTANCE_HIGH - isImportantConversation = true - }) + assertShouldHeadsUp( + buildEntry { + importance = NotificationManager.IMPORTANCE_HIGH + isImportantConversation = true + } + ) } } @@ -126,12 +143,16 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro fun testAvalancheFilter_duringAvalanche_allowCall() { avalancheProvider.startTime = whenAgo(10) - withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) { + withFilter( + AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager) + ) { ensurePeekState() - assertShouldHeadsUp(buildEntry { - importance = NotificationManager.IMPORTANCE_HIGH - isCall = true - }) + assertShouldHeadsUp( + buildEntry { + importance = NotificationManager.IMPORTANCE_HIGH + isCall = true + } + ) } } @@ -139,12 +160,16 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro fun testAvalancheFilter_duringAvalanche_allowCategoryReminder() { avalancheProvider.startTime = whenAgo(10) - withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) { + withFilter( + AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager) + ) { ensurePeekState() - assertShouldHeadsUp(buildEntry { - importance = NotificationManager.IMPORTANCE_HIGH - category = CATEGORY_REMINDER - }) + assertShouldHeadsUp( + buildEntry { + importance = NotificationManager.IMPORTANCE_HIGH + category = CATEGORY_REMINDER + } + ) } } @@ -152,12 +177,16 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro fun testAvalancheFilter_duringAvalanche_allowCategoryEvent() { avalancheProvider.startTime = whenAgo(10) - withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) { + withFilter( + AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager) + ) { ensurePeekState() - assertShouldHeadsUp(buildEntry { - importance = NotificationManager.IMPORTANCE_HIGH - category = CATEGORY_EVENT - }) + assertShouldHeadsUp( + buildEntry { + importance = NotificationManager.IMPORTANCE_HIGH + category = CATEGORY_EVENT + } + ) } } @@ -165,7 +194,9 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro fun testAvalancheFilter_duringAvalanche_allowFsi() { avalancheProvider.startTime = whenAgo(10) - withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) { + withFilter( + AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager) + ) { assertFsiNotSuppressed() } } @@ -174,16 +205,44 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro fun testAvalancheFilter_duringAvalanche_allowColorized() { avalancheProvider.startTime = whenAgo(10) - withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) { + withFilter( + AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager) + ) { ensurePeekState() - assertShouldHeadsUp(buildEntry { - importance = NotificationManager.IMPORTANCE_HIGH - isColorized = true - }) + assertShouldHeadsUp( + buildEntry { + importance = NotificationManager.IMPORTANCE_HIGH + isColorized = true + } + ) } } @Test + fun testAvalancheFilter_duringAvalanche_allowEmergency() { + avalancheProvider.startTime = whenAgo(10) + + `when`( + packageManager.checkPermission( + org.mockito.Mockito.eq(permission.RECEIVE_EMERGENCY_BROADCAST), + anyString() + ) + ).thenReturn(PERMISSION_GRANTED) + + withFilter( + AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager) + ) { + ensurePeekState() + assertShouldHeadsUp( + buildEntry { + importance = NotificationManager.IMPORTANCE_HIGH + } + ) + } + } + + + @Test fun testPeekCondition_suppressesOnlyPeek() { withCondition(TestCondition(types = setOf(PEEK)) { true }) { assertPeekSuppressed() 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 3b979a7c1386..71e7dc522e20 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 @@ -42,6 +42,7 @@ import android.app.PendingIntent import android.app.PendingIntent.FLAG_MUTABLE import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.content.pm.UserInfo import android.graphics.drawable.Icon import android.hardware.display.FakeAmbientDisplayConfiguration @@ -129,6 +130,7 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() { protected val userTracker = FakeUserTracker() protected val avalancheProvider: AvalancheProvider = mock() lateinit var systemSettings: SystemSettings + protected val packageManager: PackageManager = mock() protected abstract val provider: VisualInterruptionDecisionProvider diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt index 60aaa646fced..61c008b55ad0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt @@ -15,11 +15,11 @@ */ package com.android.systemui.statusbar.notification.interruption +import android.content.pm.PackageManager import android.hardware.display.AmbientDisplayConfiguration import android.os.Handler import android.os.PowerManager import com.android.internal.logging.UiEventLogger -import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.settings.UserTracker @@ -53,7 +53,8 @@ object VisualInterruptionDecisionProviderTestUtil { uiEventLogger: UiEventLogger, userTracker: UserTracker, avalancheProvider: AvalancheProvider, - systemSettings: SystemSettings + systemSettings: SystemSettings, + packageManager: PackageManager, ): VisualInterruptionDecisionProvider { return if (VisualInterruptionRefactor.isEnabled) { VisualInterruptionDecisionProviderImpl( @@ -73,7 +74,8 @@ object VisualInterruptionDecisionProviderTestUtil { uiEventLogger, userTracker, avalancheProvider, - systemSettings + systemSettings, + packageManager ) } else { NotificationInterruptStateProviderWrapper( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index f3f16f7d59f8..cde241bbe918 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -57,6 +57,7 @@ import android.app.WallpaperManager; import android.app.trust.TrustManager; import android.content.BroadcastReceiver; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.devicestate.DeviceState; @@ -339,6 +340,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor; @Mock private KeyboardShortcuts mKeyboardShortcuts; @Mock private KeyboardShortcutListSearch mKeyboardShortcutListSearch; + @Mock private PackageManager mPackageManager; private ShadeController mShadeController; private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); @@ -392,7 +394,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mock(UiEventLogger.class), mUserTracker, mAvalancheProvider, - mSystemSettings); + mSystemSettings, + mPackageManager); mVisualInterruptionDecisionProvider.start(); mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index df781108cf79..daea7b94ac4f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -467,7 +467,8 @@ public class BubblesTest extends SysuiTestCase { mock(UiEventLogger.class), mock(UserTracker.class), mock(AvalancheProvider.class), - mock(SystemSettings.class) + mock(SystemSettings.class), + mock(PackageManager.class) ); interruptionDecisionProvider.start(); |