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

Commit a4050465 authored by Caitlin Shkuratov's avatar Caitlin Shkuratov Committed by Julia Tuttle
Browse files

[SB][Notif] Don't show `when` time in chip if it's now-ish or in the past.

Most apps set their `when` to just be the current time (or they don't
set it at all and system_server automatically fills in the time as the
current time), which would cause the status bar notification chip to show
"now". "now" probably isn't correct for most of these apps, so just show
nothing if the `when` is now-ish or in the past.

Fixes: 393369213
Bug: 364653005
Flag: com.android.systemui.status_bar_notification_chips

Test: Send promoted notification with `when` in future -> verify chip
shows time
Test: Send promoted notification when `when` equal to current time ->
verify chip doesn't show any text
Test: Send promoted notification with `when` in the past -> verify chip
doesn't show any text

Test: atest NotifChipsViewModelTest

Change-Id: Ia585542a8fd67a49f09b60eced0f6d5c9a092021
parent 7e34b391
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,
                        )
                }
+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
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
import com.android.systemui.util.time.fakeSystemClock

val Kosmos.notifChipsViewModel: NotifChipsViewModel by
    Kosmos.Fixture {
@@ -29,5 +30,6 @@ val Kosmos.notifChipsViewModel: NotifChipsViewModel by
            applicationCoroutineScope,
            statusBarNotificationChipsInteractor,
            headsUpNotificationInteractor,
            fakeSystemClock,
        )
    }