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

Commit e978a45c authored by Julia Tuttle's avatar Julia Tuttle Committed by Android (Google) Code Review
Browse files

Merge "Create common superclass for old and new provider tests" into main

parents 10ccd333 bfbd1b8b
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -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() {
+221 −0
Original line number Diff line number Diff line
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"
+68 −0
Original line number Diff line number Diff line
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")
}
+159 −0
Original line number Diff line number Diff line
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!!)
    }
}
+6 −1
Original line number Diff line number Diff line
@@ -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;
    }