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

Commit e84628f9 authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[SB][Chips] Squish 2 chips even when ChipsModernization is on.

Ideally we could do this in Compose and do it smartly (e.g. if we can fit the
first chip with text and the second chip as icon-only we should do that), but
given our time constraints, let's not worry about doing it in Compose for now.

Bug: 392895330
Bug: 364653005
Change-Id: I8bf6563876dcb9b49a7a99b874e72bf810c92963
Flag: com.android.systemui.status_bar_notification_chips
Test: enable chips_modernization and then trigger 2 timer chips (e.g. call &
screen record) -> verify both chips show and show as icon only

Change-Id: I862c7efa3667df18b150b6d3bf7619297c5a292a
parent fe0c4034
Loading
Loading
Loading
Loading
+95 −4
Original line number Diff line number Diff line
@@ -293,7 +293,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {

    @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
    @Test
    fun chipsLegacy_twoTimerChips_isSmallPortrait_andChipsModernizationDisabled_bothSquished() =
    fun chipsLegacy_twoTimerChips_isSmallPortrait_bothSquished() =
        kosmos.runTest {
            screenRecordState.value = ScreenRecordModel.Recording
            addOngoingCallState(key = "call")
@@ -307,6 +307,22 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {
                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
        }

    @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
    @Test
    fun chips_twoTimerChips_isSmallPortrait_bothSquished() =
        kosmos.runTest {
            screenRecordState.value = ScreenRecordModel.Recording
            addOngoingCallState(key = "call")

            val latest by collectLastValue(underTest.chips)

            // Squished chips are icon only
            assertThat(latest!!.active[0])
                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
            assertThat(latest!!.active[1])
                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
        }

    @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
    @Test
    fun chipsLegacy_countdownChipAndTimerChip_countdownNotSquished_butTimerSquished() =
@@ -324,6 +340,23 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {
                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
        }

    @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
    @Test
    fun chips_countdownChipAndTimerChip_countdownNotSquished_butTimerSquished() =
        kosmos.runTest {
            screenRecordState.value = ScreenRecordModel.Starting(millisUntilStarted = 2000)
            addOngoingCallState(key = "call")

            val latest by collectLastValue(underTest.chips)

            // The screen record countdown isn't squished to icon-only
            assertThat(latest!!.active[0])
                .isInstanceOf(OngoingActivityChipModel.Active.Countdown::class.java)
            // But the call chip *is* squished
            assertThat(latest!!.active[1])
                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
        }

    @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
    @Test
    fun chipsLegacy_numberOfChipsChanges_chipsGetSquishedAndUnsquished() =
@@ -360,6 +393,38 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {
                .isInstanceOf(OngoingActivityChipModel.Inactive::class.java)
        }

    @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
    @Test
    fun chips_numberOfChipsChanges_chipsGetSquishedAndUnsquished() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.chips)

            // WHEN there's only one chip
            screenRecordState.value = ScreenRecordModel.Recording
            removeOngoingCallState(key = "call")

            // The screen record isn't squished because it's the only one
            assertThat(latest!!.active[0])
                .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)

            // WHEN there's 2 chips
            addOngoingCallState(key = "call")

            // THEN they both become squished
            assertThat(latest!!.active[0])
                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
            // But the call chip *is* squished
            assertThat(latest!!.active[1])
                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)

            // WHEN we go back down to 1 chip
            screenRecordState.value = ScreenRecordModel.DoingNothing

            // THEN the remaining chip unsquishes
            assertThat(latest!!.active[0])
                .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
        }

    @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
    @Test
    fun chipsLegacy_twoChips_isLandscape_notSquished() =
@@ -383,6 +448,29 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {
                .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
        }

    @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
    @Test
    fun chips_twoChips_isLandscape_notSquished() =
        kosmos.runTest {
            screenRecordState.value = ScreenRecordModel.Recording
            addOngoingCallState(key = "call")

            // WHEN we're in landscape
            val config =
                Configuration(kosmos.mainResources.configuration).apply {
                    orientation = Configuration.ORIENTATION_LANDSCAPE
                }
            kosmos.fakeConfigurationRepository.onConfigurationChange(config)

            val latest by collectLastValue(underTest.chips)

            // THEN the chips aren't squished (squished chips would be icon only)
            assertThat(latest!!.active[0])
                .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
            assertThat(latest!!.active[1])
                .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
        }

    @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
    @Test
    fun chipsLegacy_twoChips_isLargeScreen_notSquished() =
@@ -402,16 +490,19 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {
                .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
        }

    @Test
    @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
    fun chips_twoChips_chipsModernizationEnabled_notSquished() =
    @Test
    fun chips_twoChips_isLargeScreen_notSquished() =
        kosmos.runTest {
            screenRecordState.value = ScreenRecordModel.Recording
            addOngoingCallState(key = "call")

            // WHEN we're on a large screen
            kosmos.displayStateRepository.setIsLargeScreen(true)

            val latest by collectLastValue(underTest.chips)

            // Squished chips would be icon only
            // THEN the chips aren't squished (squished chips would be icon only)
            assertThat(latest!!.active[0])
                .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
            assertThat(latest!!.active[1])
+51 −13
Original line number Diff line number Diff line
@@ -214,7 +214,6 @@ constructor(
                    if (
                        secondaryChip is InternalChipModel.Active &&
                            StatusBarNotifChips.isEnabled &&
                            !StatusBarChipsModernization.isEnabled &&
                            !isScreenReasonablyLarge
                    ) {
                        // If we have two showing chips and we don't have a ton of room
@@ -222,8 +221,10 @@ constructor(
                        // possible so that we have the highest chance of showing both chips (as
                        // opposed to showing the primary chip with a lot of text and completely
                        // hiding the secondary chip).
                        // Also: If StatusBarChipsModernization is enabled, then we'll do the
                        // squishing in Compose instead.
                        // TODO(b/392895330): If StatusBarChipsModernization is enabled, do the
                        // squishing in Compose instead, and be smart about it (e.g. if we have
                        // room for the first chip to show text and the second chip to be icon-only,
                        // do that instead of always squishing both chips.)
                        InternalMultipleOngoingActivityChipsModel(
                            primaryChip.squish(),
                            secondaryChip.squish(),
@@ -237,24 +238,31 @@ constructor(

    /** Squishes the chip down to the smallest content possible. */
    private fun InternalChipModel.Active.squish(): InternalChipModel.Active {
        return when (model) {
        return if (model.shouldSquish()) {
            InternalChipModel.Active(this.type, this.model.toIconOnly())
        } else {
            this
        }
    }

    private fun OngoingActivityChipModel.Active.shouldSquish(): Boolean {
        return when (this) {
            // Icon-only is already maximum squished
            is OngoingActivityChipModel.Active.IconOnly -> this
            is OngoingActivityChipModel.Active.IconOnly,
            // Countdown shows just a single digit, so already maximum squished
            is OngoingActivityChipModel.Active.Countdown -> this
            // The other chips have icon+text, so we should hide the text
            is OngoingActivityChipModel.Active.Countdown -> false
            // The other chips have icon+text, so we can squish them by hiding text
            is OngoingActivityChipModel.Active.Timer,
            is OngoingActivityChipModel.Active.ShortTimeDelta,
            is OngoingActivityChipModel.Active.Text ->
                InternalChipModel.Active(this.type, this.model.toIconOnly())
            is OngoingActivityChipModel.Active.Text -> true
        }
    }

    private fun OngoingActivityChipModel.Active.toIconOnly(): OngoingActivityChipModel.Active {
        // If this chip doesn't have an icon, then it only has text and we should continue showing
        // its text. (This is theoretically impossible because
        // [OngoingActivityChipModel.Active.Countdown] is the only chip without an icon, but protect
        // against it just in case.)
        // [OngoingActivityChipModel.Active.Countdown] is the only chip without an icon and
        // [shouldSquish] returns false for that model, but protect against it just in case.)
        val currentIcon = icon ?: return this
        return OngoingActivityChipModel.Active.IconOnly(
            key,
@@ -271,8 +279,38 @@ constructor(
     */
    val chips: StateFlow<MultipleOngoingActivityChipsModel> =
        if (StatusBarChipsModernization.isEnabled) {
            incomingChipBundle
                .map { bundle -> rankChips(bundle) }
            combine(
                    incomingChipBundle.map { bundle -> rankChips(bundle) },
                    isScreenReasonablyLarge,
                ) { rankedChips, isScreenReasonablyLarge ->
                    if (
                        StatusBarNotifChips.isEnabled &&
                            !isScreenReasonablyLarge &&
                            rankedChips.active.filter { !it.isHidden }.size >= 2
                    ) {
                        // If we have at least two showing chips and we don't have a ton of room
                        // (!isScreenReasonablyLarge), then we want to make both of them as small as
                        // possible so that we have the highest chance of showing both chips (as
                        // opposed to showing the first chip with a lot of text and completely
                        // hiding the other chips).
                        val squishedActiveChips =
                            rankedChips.active.map {
                                if (!it.isHidden && it.shouldSquish()) {
                                    it.toIconOnly()
                                } else {
                                    it
                                }
                            }

                        MultipleOngoingActivityChipsModel(
                            active = squishedActiveChips,
                            overflow = rankedChips.overflow,
                            inactive = rankedChips.inactive,
                        )
                    } else {
                        rankedChips
                    }
                }
                .stateIn(scope, SharingStarted.Lazily, MultipleOngoingActivityChipsModel())
        } else {
            MutableStateFlow(MultipleOngoingActivityChipsModel()).asStateFlow()