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

Commit 7cf697d9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I2d2c73fd,Ia585542a into main

* changes:
  [Notif] Implement a min display time of 3sec for pinned-by-user HUNs.
  [SB][Notif] Don't show `when` time in chip if it's now-ish or in the past.
parents bf6bdff4 de70cf1a
Loading
Loading
Loading
Loading
+171 −12
Original line number Diff line number Diff line
@@ -49,8 +49,11 @@ import com.android.systemui.statusbar.notification.shared.ActiveNotificationMode
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.testKosmos
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Before
import org.junit.runner.RunWith
@@ -286,13 +289,15 @@ class NotifChipsViewModelTest : SysuiTestCase() {
    fun chips_hasShortCriticalText_usesTextInsteadOfTime() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 30.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.shortCriticalText = "Arrived"
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 6543L,
                            time = currentTime + 30.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }
@@ -340,13 +345,15 @@ class NotifChipsViewModelTest : SysuiTestCase() {
    fun chips_basicTime_timeHiddenIfAutomaticallyPromoted() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 30.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.wasPromotedAutomatically = true
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 6543L,
                            time = currentTime + 30.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }
@@ -370,13 +377,15 @@ class NotifChipsViewModelTest : SysuiTestCase() {
    fun chips_basicTime_timeShownIfNotAutomaticallyPromoted() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 30.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.wasPromotedAutomatically = false
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 6543L,
                            time = currentTime + 30.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }
@@ -397,18 +406,117 @@ class NotifChipsViewModelTest : SysuiTestCase() {

    @Test
    @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
    fun chips_basicTime_isShortTimeDelta() =
    fun chips_basicTime_timeInFuture_isShortTimeDelta() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 3.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 6543L,
                            time = currentTime + 13.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }

            setNotifs(
                listOf(
                    activeNotificationModel(
                        key = "notif",
                        statusBarChipIcon = createStatusBarIconViewOrNull(),
                        promotedContent = promotedContentBuilder.build(),
                    )
                )
            )

            assertThat(latest).hasSize(1)
            assertThat(latest!![0])
                .isInstanceOf(OngoingActivityChipModel.Active.ShortTimeDelta::class.java)
        }

    @Test
    @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
    fun chips_basicTime_timeLessThanOneMinInFuture_isIconOnly() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 3.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = currentTime + 500,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }

            setNotifs(
                listOf(
                    activeNotificationModel(
                        key = "notif",
                        statusBarChipIcon = createStatusBarIconViewOrNull(),
                        promotedContent = promotedContentBuilder.build(),
                    )
                )
            )

            assertThat(latest).hasSize(1)
            assertThat(latest!![0])
                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
        }

    @Test
    @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
    fun chips_basicTime_timeIsNow_isIconOnly() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 62.seconds.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = currentTime,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }

            setNotifs(
                listOf(
                    activeNotificationModel(
                        key = "notif",
                        statusBarChipIcon = createStatusBarIconViewOrNull(),
                        promotedContent = promotedContentBuilder.build(),
                    )
                )
            )

            assertThat(latest).hasSize(1)
            assertThat(latest!![0])
                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
        }

    @Test
    @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
    fun chips_basicTime_timeInPast_isIconOnly() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 62.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = currentTime - 2.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }

            setNotifs(
                listOf(
                    activeNotificationModel(
@@ -419,6 +527,45 @@ class NotifChipsViewModelTest : SysuiTestCase() {
                )
            )

            assertThat(latest).hasSize(1)
            assertThat(latest!![0])
                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
        }

    // Not necessarily the behavior we *want* to have, but it's the currently implemented behavior.
    @Test
    @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
    fun chips_basicTime_timeIsInFuture_thenTimeAdvances_stillShortTimeDelta() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 30.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = currentTime + 3.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }

            setNotifs(
                listOf(
                    activeNotificationModel(
                        key = "notif",
                        statusBarChipIcon = createStatusBarIconViewOrNull(),
                        promotedContent = promotedContentBuilder.build(),
                    )
                )
            )

            assertThat(latest).hasSize(1)
            assertThat(latest!![0])
                .isInstanceOf(OngoingActivityChipModel.Active.ShortTimeDelta::class.java)

            fakeSystemClock.advanceTime(5.minutes.inWholeMilliseconds)

            assertThat(latest).hasSize(1)
            assertThat(latest!![0])
                .isInstanceOf(OngoingActivityChipModel.Active.ShortTimeDelta::class.java)
@@ -429,12 +576,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
    fun chips_countUpTime_isTimer() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 30.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 6543L,
                            time = currentTime + 10.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.CountUp,
                        )
                }
@@ -457,12 +606,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
    fun chips_countDownTime_isTimer() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 30.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 6543L,
                            time = currentTime + 10.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.CountDown,
                        )
                }
@@ -485,12 +636,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
    fun chips_noHeadsUp_showsTime() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 30.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 6543L,
                            time = currentTime + 10.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }
@@ -517,12 +670,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
    fun chips_hasHeadsUpBySystem_showsTime() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 30.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 6543L,
                            time = currentTime + 10.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }
@@ -556,12 +711,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
    fun chips_hasHeadsUpByUser_forOtherNotif_showsTime() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 30.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 6543L,
                            time = currentTime + 10.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }
@@ -569,7 +726,7 @@ class NotifChipsViewModelTest : SysuiTestCase() {
                PromotedNotificationContentModel.Builder("other notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 654321L,
                            time = currentTime + 10.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }
@@ -610,12 +767,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
    fun chips_hasHeadsUpByUser_forThisNotif_onlyShowsIcon() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)
            val currentTime = 30.minutes.inWholeMilliseconds
            fakeSystemClock.setCurrentTimeMillis(currentTime)

            val promotedContentBuilder =
                PromotedNotificationContentModel.Builder("notif").apply {
                    this.time =
                        PromotedNotificationContentModel.When(
                            time = 6543L,
                            time = currentTime + 10.minutes.inWholeMilliseconds,
                            mode = PromotedNotificationContentModel.When.Mode.BasicTime,
                        )
                }
+77 −13
Original line number Diff line number Diff line
@@ -106,11 +106,15 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
            this.addOverride(R.integer.touch_acceptance_delay, TEST_TOUCH_ACCEPTANCE_TIME)
            this.addOverride(
                R.integer.heads_up_notification_minimum_time,
                TEST_MINIMUM_DISPLAY_TIME,
                TEST_MINIMUM_DISPLAY_TIME_DEFAULT,
            )
            this.addOverride(
                R.integer.heads_up_notification_minimum_time_with_throttling,
                TEST_MINIMUM_DISPLAY_TIME,
                TEST_MINIMUM_DISPLAY_TIME_DEFAULT,
            )
            this.addOverride(
                R.integer.heads_up_notification_minimum_time_for_user_initiated,
                TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED,
            )
            this.addOverride(R.integer.heads_up_notification_decay, TEST_AUTO_DISMISS_TIME)
            this.addOverride(
@@ -414,7 +418,7 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
    }

    @Test
    fun testRemoveNotification_beforeMinimumDisplayTime() {
    fun testRemoveNotification_beforeMinimumDisplayTime_notUserInitiatedHun() {
        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        useAccessibilityTimeout(false)

@@ -429,18 +433,22 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        assertThat(removedImmediately).isFalse()
        assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()

        systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong())
        systemClock.advanceTime(
            ((TEST_MINIMUM_DISPLAY_TIME_DEFAULT + TEST_AUTO_DISMISS_TIME) / 2).toLong()
        )

        assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
    }

    @Test
    fun testRemoveNotification_afterMinimumDisplayTime() {
    fun testRemoveNotification_afterMinimumDisplayTime_notUserInitiatedHun() {
        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        useAccessibilityTimeout(false)

        underTest.showNotification(entry)
        systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong())
        systemClock.advanceTime(
            ((TEST_MINIMUM_DISPLAY_TIME_DEFAULT + TEST_AUTO_DISMISS_TIME) / 2).toLong()
        )

        assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()

@@ -454,6 +462,57 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
    }

    @Test
    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
    fun testRemoveNotification_beforeMinimumDisplayTime_forUserInitiatedHun() {
        useAccessibilityTimeout(false)

        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        entry.row = testHelper.createRow()
        underTest.showNotification(entry, isPinnedByUser = true)

        val removedImmediately =
            underTest.removeNotification(
                entry.key,
                /* releaseImmediately = */ false,
                "beforeMinimumDisplayTime",
            )
        assertThat(removedImmediately).isFalse()
        assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()

        systemClock.advanceTime(
            ((TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED + TEST_AUTO_DISMISS_TIME) / 2).toLong()
        )

        assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
    }

    @Test
    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
    fun testRemoveNotification_afterMinimumDisplayTime_forUserInitiatedHun() {
        useAccessibilityTimeout(false)

        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        entry.row = testHelper.createRow()
        underTest.showNotification(entry, isPinnedByUser = true)

        systemClock.advanceTime(
            ((TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED + TEST_AUTO_DISMISS_TIME) / 2).toLong()
        )

        assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()

        val removedImmediately =
            underTest.removeNotification(
                entry.key,
                /* releaseImmediately = */ false,
                "afterMinimumDisplayTime",
            )

        assertThat(removedImmediately).isTrue()
        assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
    }

    @Test
    fun testRemoveNotification_releaseImmediately() {
        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
@@ -1047,16 +1106,21 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
    }

    companion object {
        const val TEST_TOUCH_ACCEPTANCE_TIME = 200
        const val TEST_A11Y_AUTO_DISMISS_TIME = 1000
        const val TEST_EXTENSION_TIME = 500
        private const val TEST_TOUCH_ACCEPTANCE_TIME = 200
        private const val TEST_A11Y_AUTO_DISMISS_TIME = 1000
        private const val TEST_EXTENSION_TIME = 500

        const val TEST_MINIMUM_DISPLAY_TIME = 400
        const val TEST_AUTO_DISMISS_TIME = 600
        const val TEST_STICKY_AUTO_DISMISS_TIME = 800
        private const val TEST_MINIMUM_DISPLAY_TIME_DEFAULT = 400
        private const val TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED = 500
        private const val TEST_AUTO_DISMISS_TIME = 600
        private const val TEST_STICKY_AUTO_DISMISS_TIME = 800

        init {
            assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME)
            assertThat(TEST_MINIMUM_DISPLAY_TIME_DEFAULT)
                .isLessThan(TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED)
            assertThat(TEST_MINIMUM_DISPLAY_TIME_DEFAULT).isLessThan(TEST_AUTO_DISMISS_TIME)
            assertThat(TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED)
                .isLessThan(TEST_AUTO_DISMISS_TIME)
            assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME)
            assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME)
        }
+3 −0
Original line number Diff line number Diff line
@@ -175,6 +175,9 @@
    <!-- Minimum display time for a heads up notification if throttling is enabled, in milliseconds. -->
    <integer name="heads_up_notification_minimum_time_with_throttling">500</integer>

    <!-- Minimum display time for a heads up notification that was shown from a user action (like tapping on a different part of the UI), in milliseconds. -->
    <integer name="heads_up_notification_minimum_time_for_user_initiated">3000</integer>

    <!-- Display time for a sticky heads up notification, in milliseconds. -->
    <integer name="sticky_heads_up_notification_time">60000</integer>

+40 −8
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.notification.domain.model.TopPinnedState
import com.android.systemui.statusbar.notification.headsup.PinnedStatus
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -51,6 +52,7 @@ constructor(
    @Application private val applicationScope: CoroutineScope,
    private val notifChipsInteractor: StatusBarNotificationChipsInteractor,
    headsUpNotificationInteractor: HeadsUpNotificationInteractor,
    private val systemClock: SystemClock,
) {
    /**
     * A flow modeling the notification chips that should be shown. Emits an empty list if there are
@@ -158,9 +160,14 @@ constructor(
                clickBehavior,
            )
        }

        when (this.promotedContent.time.mode) {
            PromotedNotificationContentModel.When.Mode.BasicTime -> {
                return OngoingActivityChipModel.Active.ShortTimeDelta(
                return if (
                    this.promotedContent.time.time >=
                        systemClock.currentTimeMillis() + FUTURE_TIME_THRESHOLD_MILLIS
                ) {
                    OngoingActivityChipModel.Active.ShortTimeDelta(
                        this.key,
                        icon,
                        colors,
@@ -168,6 +175,23 @@ constructor(
                        onClickListenerLegacy,
                        clickBehavior,
                    )
                } else {
                    // Don't show a `when` time that's close to now or in the past because it's
                    // likely that the app didn't intentionally set the `when` time to be shown in
                    // the status bar chip.
                    // TODO(b/393369213): If a notification sets a `when` time in the future and
                    // then that time comes and goes, the chip *will* start showing times in the
                    // past. Not going to fix this right now because the Compose implementation
                    // automatically handles this for us and we're hoping to launch the notification
                    // chips at the same time as the Compose chips.
                    return OngoingActivityChipModel.Active.IconOnly(
                        this.key,
                        icon,
                        colors,
                        onClickListenerLegacy,
                        clickBehavior,
                    )
                }
            }
            PromotedNotificationContentModel.When.Mode.CountUp -> {
                return OngoingActivityChipModel.Active.Timer(
@@ -204,4 +228,12 @@ constructor(
            )
        )
    }

    companion object {
        /**
         * Notifications must have a `when` time of at least 1 minute in the future in order for the
         * status bar chip to show the time.
         */
        private const val FUTURE_TIME_THRESHOLD_MILLIS = 60 * 1000
    }
}
+12 −4

File changed.

Preview size limit exceeded, changes collapsed.

Loading