diff options
| author | 2023-10-20 15:51:35 -0400 | |
|---|---|---|
| committer | 2023-10-27 01:02:29 -0400 | |
| commit | bfbd1b8b5cb1553df4635030ea31ae6ee185b128 (patch) | |
| tree | d5527790c2defd71103dddfb4d2550f291cfd928 | |
| parent | 18ed69633bd642bcf9b4cc4aaec3fb9bde8436fb (diff) | |
Create common superclass for old and new provider tests
This does not yet test the legacy suppressor interface; that will come
in a later CL.
Bug: 261728888
Test: atest NotificationInterruptStateProviderWrapperTest
Flag: none needed, not instantiated yet
Change-Id: Iacc17ab6461cb02f4ed62965e2ae7bce097692c5
5 files changed, 478 insertions, 3 deletions
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 cbb08946a1b0..947bcfb5011b 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 @@ package com.android.systemui.statusbar.notification.interruption 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 @@ import org.junit.runner.RunWith @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 000000000000..6f4bbd5e21fc --- /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 000000000000..cdd0ff7c38f7 --- /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 000000000000..19fdb6ddad02 --- /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 eaa109d672f8..209cac6688a2 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 @@ import java.io.PrintWriter; public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCallback> implements BatteryController { + private boolean mIsAodPowerSave = false; private boolean mWirelessCharging; public FakeBatteryController(LeakCheck test) { @@ -63,7 +64,7 @@ public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCal @Override public boolean isAodPowerSave() { - return false; + return mIsAodPowerSave; } @Override @@ -71,6 +72,10 @@ public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCal return mWirelessCharging; } + public void setIsAodPowerSave(boolean isAodPowerSave) { + mIsAodPowerSave = isAodPowerSave; + } + public void setWirelessCharging(boolean wirelessCharging) { mWirelessCharging = wirelessCharging; } |