Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt +95 −4 Original line number Diff line number Diff line Loading @@ -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") Loading @@ -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() = Loading @@ -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() = Loading Loading @@ -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() = Loading @@ -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() = Loading @@ -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]) Loading packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt +51 −13 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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(), Loading @@ -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, Loading @@ -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() Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt +95 −4 Original line number Diff line number Diff line Loading @@ -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") Loading @@ -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() = Loading @@ -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() = Loading Loading @@ -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() = Loading @@ -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() = Loading @@ -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]) Loading
packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt +51 −13 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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(), Loading @@ -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, Loading @@ -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() Loading