Merge "Create common superclass for old and new provider tests" into main
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
index cbb0894..947bcfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
@@ -2,7 +2,6 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision.FSI_DEVICE_NOT_INTERACTIVE
@@ -19,7 +18,30 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class NotificationInterruptStateProviderWrapperTest : SysuiTestCase() {
+class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() {
+ override val provider: VisualInterruptionDecisionProvider
+ get() =
+ NotificationInterruptStateProviderWrapper(
+ NotificationInterruptStateProviderImpl(
+ context.contentResolver,
+ powerManager,
+ ambientDisplayConfiguration,
+ batteryController,
+ statusBarStateController,
+ keyguardStateController,
+ headsUpManager,
+ logger,
+ mainHandler,
+ flags,
+ keyguardNotificationVisibilityProvider,
+ uiEventLogger,
+ userTracker,
+ deviceProvisionedController
+ )
+ .also { it.mUseHeadsUp = true }
+ )
+
+ // Tests of internals of the wrapper:
@Test
fun decisionOfTrue() {
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
new file mode 100644
index 0000000..6f4bbd5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
@@ -0,0 +1,221 @@
+package com.android.systemui.statusbar.notification.interruption
+
+import android.app.ActivityManager
+import android.app.Notification
+import android.app.Notification.BubbleMetadata
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_MUTABLE
+import android.content.Intent
+import android.content.pm.UserInfo
+import android.graphics.drawable.Icon
+import android.hardware.display.FakeAmbientDisplayConfiguration
+import android.os.Handler
+import android.os.PowerManager
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.statusbar.FakeStatusBarStateController
+import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.utils.leaks.FakeBatteryController
+import com.android.systemui.utils.leaks.LeakCheckedTest
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.`when` as whenever
+
+abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() {
+ private val leakCheck = LeakCheckedTest.SysuiLeakCheck()
+
+ protected val ambientDisplayConfiguration = FakeAmbientDisplayConfiguration(context)
+ protected val batteryController = FakeBatteryController(leakCheck)
+ protected val deviceProvisionedController: DeviceProvisionedController = mock()
+ protected val flags: NotifPipelineFlags = mock()
+ protected val headsUpManager: HeadsUpManager = mock()
+ protected val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider =
+ mock()
+ protected val keyguardStateController: KeyguardStateController = mock()
+ protected val logger: NotificationInterruptLogger = mock()
+ protected val mainHandler: Handler = mock()
+ protected val powerManager: PowerManager = mock()
+ protected val statusBarStateController = FakeStatusBarStateController()
+ protected val uiEventLogger = UiEventLoggerFake()
+ protected val userTracker = FakeUserTracker()
+
+ protected abstract val provider: VisualInterruptionDecisionProvider
+
+ @Before
+ fun setUp() {
+ val user = UserInfo(ActivityManager.getCurrentUser(), "Current user", /* flags = */ 0)
+ userTracker.set(listOf(user), /* currentUserIndex = */ 0)
+
+ whenever(headsUpManager.isSnoozed(any())).thenReturn(false)
+ whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any()))
+ .thenReturn(false)
+ }
+
+ @Test
+ fun testShouldPeek() {
+ ensureStateForPeek()
+
+ assertTrue(provider.makeUnloggedHeadsUpDecision(createPeekEntry()).shouldInterrupt)
+ }
+
+ @Test
+ fun testShouldPulse() {
+ ensureStateForPulse()
+
+ assertTrue(provider.makeUnloggedHeadsUpDecision(createPulseEntry()).shouldInterrupt)
+ }
+
+ @Test
+ fun testShouldFsi_awake() {
+ ensureStateForAwakeFsi()
+
+ assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt)
+ }
+
+ @Test
+ fun testShouldFsi_dreaming() {
+ ensureStateForDreamingFsi()
+
+ assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt)
+ }
+
+ @Test
+ fun testShouldFsi_keyguard() {
+ ensureStateForKeyguardFsi()
+
+ assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt)
+ }
+
+ @Test
+ fun testShouldBubble() {
+ assertTrue(provider.makeAndLogBubbleDecision(createBubbleEntry()).shouldInterrupt)
+ }
+
+ private fun ensureStateForPeek() {
+ whenever(powerManager.isScreenOn).thenReturn(true)
+ statusBarStateController.dozing = false
+ statusBarStateController.dreaming = false
+ }
+
+ private fun ensureStateForPulse() {
+ ambientDisplayConfiguration.fakePulseOnNotificationEnabled = true
+ batteryController.setIsAodPowerSave(false)
+ statusBarStateController.dozing = true
+ }
+
+ private fun ensureStateForAwakeFsi() {
+ whenever(powerManager.isInteractive).thenReturn(false)
+ statusBarStateController.dreaming = false
+ statusBarStateController.state = SHADE
+ }
+
+ private fun ensureStateForDreamingFsi() {
+ whenever(powerManager.isInteractive).thenReturn(true)
+ statusBarStateController.dreaming = true
+ statusBarStateController.state = SHADE
+ }
+
+ private fun ensureStateForKeyguardFsi() {
+ whenever(powerManager.isInteractive).thenReturn(true)
+ statusBarStateController.dreaming = false
+ statusBarStateController.state = KEYGUARD
+ }
+
+ private fun createNotif(
+ hasFsi: Boolean = false,
+ bubbleMetadata: BubbleMetadata? = null
+ ): Notification {
+ return Notification.Builder(context, TEST_CHANNEL_ID)
+ .apply {
+ setContentTitle(TEST_CONTENT_TITLE)
+ setContentText(TEST_CONTENT_TEXT)
+
+ if (hasFsi) {
+ setFullScreenIntent(mock(), /* highPriority = */ true)
+ }
+
+ if (bubbleMetadata != null) {
+ setBubbleMetadata(bubbleMetadata)
+ }
+ }
+ .setContentTitle(TEST_CONTENT_TITLE)
+ .setContentText(TEST_CONTENT_TEXT)
+ .build()
+ }
+
+ private fun createBubbleMetadata(): BubbleMetadata {
+ val pendingIntent =
+ PendingIntent.getActivity(
+ context,
+ /* requestCode = */ 0,
+ Intent().setPackage(context.packageName),
+ FLAG_MUTABLE
+ )
+
+ val icon = Icon.createWithResource(context.resources, R.drawable.android)
+
+ return BubbleMetadata.Builder(pendingIntent, icon).build()
+ }
+
+ private fun createEntry(
+ notif: Notification,
+ importance: Int = IMPORTANCE_DEFAULT,
+ canBubble: Boolean? = null
+ ): NotificationEntry {
+ return NotificationEntryBuilder()
+ .apply {
+ setPkg(TEST_PACKAGE)
+ setOpPkg(TEST_PACKAGE)
+ setTag(TEST_TAG)
+ setChannel(NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance))
+ setNotification(notif)
+ setImportance(importance)
+
+ if (canBubble != null) {
+ setCanBubble(canBubble)
+ }
+ }
+ .build()
+ }
+
+ private fun createPeekEntry() = createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH)
+
+ private fun createPulseEntry() =
+ createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH).also {
+ modifyRanking(it).setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build()
+ }
+
+ private fun createFsiEntry() =
+ createEntry(notif = createNotif(hasFsi = true), importance = IMPORTANCE_HIGH)
+
+ private fun createBubbleEntry() =
+ createEntry(
+ notif = createNotif(bubbleMetadata = createBubbleMetadata()),
+ importance = IMPORTANCE_HIGH,
+ canBubble = true
+ )
+}
+
+private const val TEST_CONTENT_TITLE = "Test Content Title"
+private const val TEST_CONTENT_TEXT = "Test content text"
+private const val TEST_CHANNEL_ID = "test_channel"
+private const val TEST_CHANNEL_NAME = "Test Channel"
+private const val TEST_PACKAGE = "test_package"
+private const val TEST_TAG = "test_tag"
diff --git a/packages/SystemUI/tests/utils/src/android/hardware/display/FakeAmbientDisplayConfiguration.kt b/packages/SystemUI/tests/utils/src/android/hardware/display/FakeAmbientDisplayConfiguration.kt
new file mode 100644
index 0000000..cdd0ff7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/android/hardware/display/FakeAmbientDisplayConfiguration.kt
@@ -0,0 +1,68 @@
+package android.hardware.display
+
+import android.content.Context
+
+class FakeAmbientDisplayConfiguration(context: Context) : AmbientDisplayConfiguration(context) {
+ var fakePulseOnNotificationEnabled = true
+
+ override fun pulseOnNotificationEnabled(user: Int) = fakePulseOnNotificationEnabled
+
+ override fun pulseOnNotificationAvailable() = TODO("Not yet implemented")
+
+ override fun pickupGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun dozePickupSensorAvailable() = TODO("Not yet implemented")
+
+ override fun tapGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun tapSensorAvailable() = TODO("Not yet implemented")
+
+ override fun doubleTapGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun doubleTapSensorAvailable() = TODO("Not yet implemented")
+
+ override fun quickPickupSensorEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun screenOffUdfpsEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun wakeScreenGestureAvailable() = TODO("Not yet implemented")
+
+ override fun wakeLockScreenGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun wakeDisplayGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun getWakeLockScreenDebounce() = TODO("Not yet implemented")
+
+ override fun doubleTapSensorType() = TODO("Not yet implemented")
+
+ override fun tapSensorTypeMapping() = TODO("Not yet implemented")
+
+ override fun longPressSensorType() = TODO("Not yet implemented")
+
+ override fun udfpsLongPressSensorType() = TODO("Not yet implemented")
+
+ override fun quickPickupSensorType() = TODO("Not yet implemented")
+
+ override fun pulseOnLongPressEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun alwaysOnEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun alwaysOnAvailable() = TODO("Not yet implemented")
+
+ override fun alwaysOnAvailableForUser(user: Int) = TODO("Not yet implemented")
+
+ override fun ambientDisplayComponent() = TODO("Not yet implemented")
+
+ override fun accessibilityInversionEnabled(user: Int) = TODO("Not yet implemented")
+
+ override fun ambientDisplayAvailable() = TODO("Not yet implemented")
+
+ override fun dozeSuppressed(user: Int) = TODO("Not yet implemented")
+
+ override fun disableDozeSettings(userId: Int) = TODO("Not yet implemented")
+
+ override fun disableDozeSettings(shouldDisableNonUserConfigurable: Boolean, userId: Int) =
+ TODO("Not yet implemented")
+
+ override fun restoreDozeSettings(userId: Int) = TODO("Not yet implemented")
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt
new file mode 100644
index 0000000..19fdb6d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt
@@ -0,0 +1,159 @@
+package com.android.systemui.statusbar
+
+import android.view.View
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+
+class FakeStatusBarStateController : SysuiStatusBarStateController {
+ @JvmField var state = StatusBarState.SHADE
+
+ @JvmField var upcomingState = StatusBarState.SHADE
+
+ @JvmField var lastState = StatusBarState.SHADE
+
+ @JvmField var dozing = false
+
+ @JvmField var expanded = false
+
+ @JvmField var pulsing = false
+
+ @JvmField var dreaming = false
+
+ @JvmField var dozeAmount = 0.0f
+
+ @JvmField var interpolatedDozeAmount = 0.0f
+
+ @JvmField var dozeAmountTarget = 0.0f
+
+ @JvmField var leaveOpen = false
+
+ @JvmField var keyguardRequested = false
+
+ var lastSetDozeAmountView: View? = null
+ private set
+
+ var lastSetDozeAmountAnimated = false
+ private set
+
+ var lastSystemBarAppearance = 0
+ private set
+
+ var lastSystemBarBehavior = 0
+ private set
+
+ var lastSystemBarRequestedVisibleTypes = 0
+ private set
+
+ var lastSystemBarPackageName: String? = null
+ private set
+
+ private val _callbacks = mutableSetOf<StatusBarStateController.StateListener>()
+
+ @JvmField val callbacks: Set<StatusBarStateController.StateListener> = _callbacks
+
+ private var fullscreen = false
+
+ override fun start() {}
+
+ override fun getState() = state
+
+ override fun setState(newState: Int, force: Boolean): Boolean {
+ val oldState = this.state
+ newState != oldState || force || return false
+
+ callbacks.forEach { it.onStatePreChange(oldState, newState) }
+ this.lastState = oldState
+ this.state = newState
+ setUpcomingState(newState)
+ callbacks.forEach { it.onStateChanged(newState) }
+ callbacks.forEach { it.onStatePostChange() }
+ return true
+ }
+
+ override fun getCurrentOrUpcomingState() = upcomingState
+
+ override fun setUpcomingState(upcomingState: Int) {
+ upcomingState != this.upcomingState || return
+ this.upcomingState = upcomingState
+ callbacks.forEach { it.onUpcomingStateChanged(upcomingState) }
+ }
+
+ override fun isDozing() = dozing
+
+ override fun setIsDozing(dozing: Boolean): Boolean {
+ dozing != this.dozing || return false
+ this.dozing = dozing
+ callbacks.forEach { it.onDozingChanged(dozing) }
+ return true
+ }
+
+ override fun isExpanded() = expanded
+
+ fun fakeShadeExpansionFullyChanged(expanded: Boolean) {
+ expanded != this.expanded || return
+ this.expanded = expanded
+ callbacks.forEach { it.onExpandedChanged(expanded) }
+ }
+
+ override fun isPulsing() = pulsing
+
+ override fun setPulsing(pulsing: Boolean) {
+ pulsing != this.pulsing || return
+ this.pulsing = pulsing
+ callbacks.forEach { it.onPulsingChanged(pulsing) }
+ }
+
+ override fun isDreaming() = dreaming
+
+ override fun setIsDreaming(drreaming: Boolean): Boolean {
+ dreaming != this.dreaming || return false
+ this.dreaming = dreaming
+ callbacks.forEach { it.onDreamingChanged(dreaming) }
+ return true
+ }
+
+ override fun getDozeAmount() = dozeAmount
+
+ override fun setAndInstrumentDozeAmount(view: View?, dozeAmount: Float, animated: Boolean) {
+ dozeAmountTarget = dozeAmount
+ lastSetDozeAmountView = view
+ lastSetDozeAmountAnimated = animated
+ if (!animated) {
+ this.dozeAmount = dozeAmount
+ }
+ }
+
+ override fun leaveOpenOnKeyguardHide() = leaveOpen
+
+ override fun setLeaveOpenOnKeyguardHide(leaveOpen: Boolean) {
+ this.leaveOpen = leaveOpen
+ }
+
+ override fun getInterpolatedDozeAmount() = interpolatedDozeAmount
+
+ fun fakeInterpolatedDozeAmountChanged(interpolatedDozeAmount: Float) {
+ this.interpolatedDozeAmount = interpolatedDozeAmount
+ callbacks.forEach { it.onDozeAmountChanged(dozeAmount, interpolatedDozeAmount) }
+ }
+
+ override fun goingToFullShade() = state == StatusBarState.SHADE && leaveOpen
+
+ override fun fromShadeLocked() = lastState == StatusBarState.SHADE_LOCKED
+
+ override fun isKeyguardRequested(): Boolean = keyguardRequested
+
+ override fun setKeyguardRequested(keyguardRequested: Boolean) {
+ this.keyguardRequested = keyguardRequested
+ }
+
+ override fun addCallback(listener: StatusBarStateController.StateListener?) {
+ _callbacks.add(listener!!)
+ }
+
+ override fun addCallback(listener: StatusBarStateController.StateListener?, rank: Int) {
+ throw RuntimeException("addCallback with rank unsupported")
+ }
+
+ override fun removeCallback(listener: StatusBarStateController.StateListener?) {
+ _callbacks.remove(listener!!)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
index eaa109d..209cac6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
@@ -25,6 +25,7 @@
public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCallback>
implements BatteryController {
+ private boolean mIsAodPowerSave = false;
private boolean mWirelessCharging;
public FakeBatteryController(LeakCheck test) {
@@ -63,7 +64,7 @@
@Override
public boolean isAodPowerSave() {
- return false;
+ return mIsAodPowerSave;
}
@Override
@@ -71,6 +72,10 @@
return mWirelessCharging;
}
+ public void setIsAodPowerSave(boolean isAodPowerSave) {
+ mIsAodPowerSave = isAodPowerSave;
+ }
+
public void setWirelessCharging(boolean wirelessCharging) {
mWirelessCharging = wirelessCharging;
}