From 3abfc4d5894835b2d8cdaff8bb175b8643470e4f Mon Sep 17 00:00:00 2001 From: Caitlin Shkuratov Date: Mon, 13 Jan 2025 20:34:31 +0000 Subject: [SB][Notif] Don't allow call notif to also show in a promoted notif chip Currently if an app posts a notification with CallStyle.Ongoing that *also* meets the promoted notification criteria, the status bar would incorrectly show 2 chips for the same notification: One because it's a call, and another because it's promoted. This CL: 1) Filters out call notifications from promoted notifications so there won't be duplicate chips. (Call notifications need to take priority over promoted notifications, which is why I'm keeping the call notification Flow the same and doing the filtering on the other Flow.) 2) Updates the call chip to use the notification's coloring if the call notification also matches the promotion criteria. This makes the call chip look like a promoted notification chip, while ensuring the call chip still always shows the 00:01 timer. Fixes: 388521980 Bug: 364653005 Flag: com.android.systemui.status_bar_notification_chips Test: Post a CallStyle.Ongoing notification that's also colorized & has FLAG_ONGOING_EVENT set -> verify only a single chip is shown. Verify that chip uses the notification color, not the theme color. Test: Post a CallStyle.Ongoing notification and a different promoted notification -> verify call chip is shown first Change-Id: I67427a4c8aa4b0d0890f9ef621e56aa87cf67b64 --- .../call/ui/viewmodel/CallChipViewModelTest.kt | 92 ++++++++++++++++++++-- .../StatusBarNotificationChipsInteractorTest.kt | 32 ++++++++ .../phone/ongoingcall/OngoingCallControllerTest.kt | 22 ++++++ .../domain/interactor/OngoingCallInteractorTest.kt | 11 ++- .../chips/call/ui/viewmodel/CallChipViewModel.kt | 13 ++- .../StatusBarNotificationChipsInteractor.kt | 71 ++++++++++------- .../ui/viewmodel/NotifChipsViewModel.kt | 8 +- .../statusbar/chips/ui/model/ColorsModel.kt | 11 +++ .../interactor/ActiveNotificationsInteractor.kt | 19 +++-- .../phone/ongoingcall/OngoingCallController.kt | 8 ++ .../domain/interactor/OngoingCallInteractor.kt | 1 + .../ongoingcall/shared/model/OngoingCallModel.kt | 8 +- .../shared/model/OngoingCallModelBuilder.kt | 4 +- 13 files changed, 246 insertions(+), 54 deletions(-) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt index ac3089d9286b..56a4ed078670 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt @@ -30,10 +30,12 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.activityStarter import com.android.systemui.res.R import com.android.systemui.statusbar.StatusBarIconView +import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer import com.android.systemui.statusbar.core.StatusBarConnectedDisplays +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel @@ -64,7 +66,7 @@ class CallChipViewModelTest : SysuiTestCase() { .thenReturn(chipBackgroundView) } - private val underTest = kosmos.callChipViewModel + private val underTest by lazy { kosmos.callChipViewModel } @Test fun chip_noCall_isHidden() = @@ -219,27 +221,93 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - fun chip_positiveStartTime_colorsAreThemed() = + fun chip_positiveStartTime_notPromoted_colorsAreThemed() = testScope.runTest { val latest by collectLastValue(underTest.chip) - repo.setOngoingCallState(inCallModel(startTimeMs = 1000)) + repo.setOngoingCallState(inCallModel(startTimeMs = 1000, promotedContent = null)) assertThat((latest as OngoingActivityChipModel.Shown).colors) .isEqualTo(ColorsModel.Themed) } @Test - fun chip_zeroStartTime_colorsAreThemed() = + fun chip_zeroStartTime_notPromoted_colorsAreThemed() = testScope.runTest { val latest by collectLastValue(underTest.chip) - repo.setOngoingCallState(inCallModel(startTimeMs = 0)) + repo.setOngoingCallState(inCallModel(startTimeMs = 0, promotedContent = null)) + + assertThat((latest as OngoingActivityChipModel.Shown).colors) + .isEqualTo(ColorsModel.Themed) + } + + @Test + @DisableFlags(StatusBarNotifChips.FLAG_NAME) + fun chip_positiveStartTime_promoted_notifChipsFlagOff_colorsAreThemed() = + testScope.runTest { + val latest by collectLastValue(underTest.chip) + + repo.setOngoingCallState( + inCallModel(startTimeMs = 1000, promotedContent = PROMOTED_CONTENT_WITH_COLOR) + ) assertThat((latest as OngoingActivityChipModel.Shown).colors) .isEqualTo(ColorsModel.Themed) } + @Test + @DisableFlags(StatusBarNotifChips.FLAG_NAME) + fun chip_zeroStartTime_promoted_notifChipsFlagOff_colorsAreThemed() = + testScope.runTest { + val latest by collectLastValue(underTest.chip) + + repo.setOngoingCallState( + inCallModel(startTimeMs = 0, promotedContent = PROMOTED_CONTENT_WITH_COLOR) + ) + + assertThat((latest as OngoingActivityChipModel.Shown).colors) + .isEqualTo(ColorsModel.Themed) + } + + @Test + @EnableFlags(StatusBarNotifChips.FLAG_NAME) + fun chip_positiveStartTime_promoted_notifChipsFlagOn_colorsAreCustom() = + testScope.runTest { + val latest by collectLastValue(underTest.chip) + + repo.setOngoingCallState( + inCallModel(startTimeMs = 1000, promotedContent = PROMOTED_CONTENT_WITH_COLOR) + ) + + assertThat((latest as OngoingActivityChipModel.Shown).colors) + .isEqualTo( + ColorsModel.Custom( + backgroundColorInt = PROMOTED_BACKGROUND_COLOR, + primaryTextColorInt = PROMOTED_PRIMARY_TEXT_COLOR, + ) + ) + } + + @Test + @EnableFlags(StatusBarNotifChips.FLAG_NAME) + fun chip_zeroStartTime_promoted_notifChipsFlagOff_colorsAreCustom() = + testScope.runTest { + val latest by collectLastValue(underTest.chip) + + repo.setOngoingCallState( + inCallModel(startTimeMs = 0, promotedContent = PROMOTED_CONTENT_WITH_COLOR) + ) + + assertThat((latest as OngoingActivityChipModel.Shown).colors) + .isEqualTo( + ColorsModel.Custom( + backgroundColorInt = PROMOTED_BACKGROUND_COLOR, + primaryTextColorInt = PROMOTED_PRIMARY_TEXT_COLOR, + ) + ) + } + @Test fun chip_resetsCorrectly() = testScope.runTest { @@ -319,5 +387,19 @@ class CallChipViewModelTest : SysuiTestCase() { } else { mock() } + + private val PROMOTED_CONTENT_WITH_COLOR = + PromotedNotificationContentModel.Builder("notif") + .apply { + this.colors = + PromotedNotificationContentModel.Colors( + backgroundColor = PROMOTED_BACKGROUND_COLOR, + primaryTextColor = PROMOTED_PRIMARY_TEXT_COLOR, + ) + } + .build() + + private const val PROMOTED_BACKGROUND_COLOR = 65 + private const val PROMOTED_PRIMARY_TEXT_COLOR = 98 } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt index ee4a52d35d68..e89c929a5827 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt @@ -36,6 +36,7 @@ import com.android.systemui.statusbar.notification.data.repository.ActiveNotific import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel +import com.android.systemui.statusbar.notification.shared.CallType import com.android.systemui.testKosmos import com.android.systemui.util.time.fakeSystemClock import com.google.common.truth.Truth.assertThat @@ -178,6 +179,37 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() { assertThat(latest!![1].statusBarChipIconView).isEqualTo(secondIcon) } + /** Regression test for b/388521980. */ + @Test + @EnableFlags(StatusBarNotifChips.FLAG_NAME) + fun notificationChips_callNotifIsAlsoPromoted_callNotifExcluded() = + kosmos.runTest { + val latest by collectLastValue(underTest.notificationChips) + + setNotifs( + listOf( + activeNotificationModel( + key = "promotedNormal", + statusBarChipIcon = mock(), + promotedContent = + PromotedNotificationContentModel.Builder("promotedNormal").build(), + callType = CallType.None, + ), + activeNotificationModel( + key = "promotedCall", + statusBarChipIcon = mock(), + promotedContent = + PromotedNotificationContentModel.Builder("promotedCall").build(), + callType = CallType.Ongoing, + ), + ) + ) + + // Verify the promoted call notification is not included + assertThat(latest).hasSize(1) + assertThat(latest!![0].key).isEqualTo("promotedNormal") + } + @Test @EnableFlags(StatusBarNotifChips.FLAG_NAME) fun notificationChips_notifUpdatesGoThrough() = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt index 6da06a36f63d..02135f6a7836 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt @@ -41,6 +41,7 @@ import com.android.systemui.statusbar.notification.data.model.activeNotification import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.notification.shared.CallType import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository @@ -168,6 +169,27 @@ class OngoingCallControllerTest : SysuiTestCase() { assertThat((repoState as OngoingCallModel.InCall).notificationIconView).isEqualTo(icon) } + @Test + fun interactorHasOngoingCallNotif_repoHasPromotedContent() = + testScope.runTest { + val promotedContent = PromotedNotificationContentModel.Builder("ongoingNotif").build() + setNotifOnRepo( + activeNotificationModel( + key = "ongoingNotif", + callType = CallType.Ongoing, + uid = CALL_UID, + statusBarChipIcon = mock(), + whenTime = 567, + promotedContent = promotedContent, + ) + ) + + val repoState = ongoingCallRepository.ongoingCallState.value + assertThat(repoState).isInstanceOf(OngoingCallModel.InCall::class.java) + assertThat((repoState as OngoingCallModel.InCall).promotedContent) + .isEqualTo(promotedContent) + } + @Test fun notifRepoHasOngoingCallNotif_isOngoingCallNotif_windowControllerUpdated() { setCallNotifOnRepo() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt index 8fb95e843ec1..14263c4b1b9b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt @@ -35,6 +35,7 @@ import com.android.systemui.statusbar.gesture.swipeStatusBarAwayGestureHandler import com.android.systemui.statusbar.notification.data.model.activeNotificationModel import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.shared.CallType import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore @@ -69,33 +70,37 @@ class OngoingCallInteractorTest : SysuiTestCase() { } @Test - fun ongoingCallNotification_setsNotificationIconAndIntent() = + fun ongoingCallNotification_setsAllFields() = kosmos.runTest { val latest by collectLastValue(underTest.ongoingCallState) // Set up notification with icon view and intent val testIconView: StatusBarIconView = mock() val testIntent: PendingIntent = mock() + val testPromotedContent = + PromotedNotificationContentModel.Builder("promotedCall").build() repository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { addIndividualNotif( activeNotificationModel( - key = "notif1", + key = "promotedCall", whenTime = 1000L, callType = CallType.Ongoing, statusBarChipIcon = testIconView, contentIntent = testIntent, + promotedContent = testPromotedContent, ) ) } .build() - // Verify model is InCall and has the correct icon and intent. + // Verify model is InCall and has the correct icon, intent, and promoted content. assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java) val model = latest as OngoingCallModel.InCall assertThat(model.notificationIconView).isSameInstanceAs(testIconView) assertThat(model.intent).isSameInstanceAs(testIntent) + assertThat(model.promotedContent).isSameInstanceAs(testPromotedContent) } @Test diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt index 86954d569199..4fb8f724c971 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt @@ -30,7 +30,9 @@ import com.android.systemui.res.R import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad import com.android.systemui.statusbar.chips.StatusBarChipsLog import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor +import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.chips.ui.model.ColorsModel +import com.android.systemui.statusbar.chips.ui.model.ColorsModel.Companion.toCustomColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel @@ -76,13 +78,20 @@ constructor( OngoingActivityChipModel.ChipIcon.SingleColorIcon(phoneIcon) } + val colors = + if (StatusBarNotifChips.isEnabled && state.promotedContent != null) { + state.promotedContent.toCustomColorsModel() + } else { + ColorsModel.Themed + } + // This block mimics OngoingCallController#updateChip. if (state.startTimeMs <= 0L) { // If the start time is invalid, don't show a timer and show just an // icon. See b/192379214. OngoingActivityChipModel.Shown.IconOnly( icon = icon, - colors = ColorsModel.Themed, + colors = colors, getOnClickListener(state), ) } else { @@ -91,7 +100,7 @@ constructor( systemClock.elapsedRealtime() OngoingActivityChipModel.Shown.Timer( icon = icon, - colors = ColorsModel.Themed, + colors = colors, startTimeMs = startTimeInElapsedRealtime, getOnClickListener(state), ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt index 2121f94caced..4fad01d9f448 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt @@ -28,6 +28,7 @@ import com.android.systemui.statusbar.chips.StatusBarChipsLog import com.android.systemui.statusbar.chips.notification.domain.model.NotificationChipModel import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor +import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor.Companion.isOngoingCallNotification import com.android.systemui.util.kotlin.pairwise import com.android.systemui.util.time.SystemClock import javax.inject.Inject @@ -41,6 +42,7 @@ import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map /** An interactor for the notification chips shown in the status bar. */ @SysUISingleton @@ -88,45 +90,56 @@ constructor( private val promotedNotificationInteractors = MutableStateFlow>(emptyList()) + /** + * The notifications that are promoted and ongoing. + * + * Explicitly does *not* include any ongoing call notifications, even if the call notifications + * meet the promotion criteria. Those call notifications will be handled by + * [com.android.systemui.statusbar.chips.call.domain.CallChipInteractor] instead. See + * b/388521980. + */ + private val promotedOngoingNotifications = + activeNotificationsInteractor.promotedOngoingNotifications.map { notifs -> + notifs.filterNot { it.isOngoingCallNotification() } + } + override fun start() { if (!StatusBarNotifChips.isEnabled) { return } backgroundScope.launch("StatusBarNotificationChipsInteractor") { - activeNotificationsInteractor.promotedOngoingNotifications - .pairwise(initialValue = emptyList()) - .collect { (oldNotifs, currentNotifs) -> - val removedNotifKeys = - oldNotifs.map { it.key }.minus(currentNotifs.map { it.key }.toSet()) - removedNotifKeys.forEach { removedNotifKey -> - val wasRemoved = promotedNotificationInteractorMap.remove(removedNotifKey) - if (wasRemoved == null) { - logger.w({ - "Attempted to remove $str1 from interactor map but it wasn't present" - }) { - str1 = removedNotifKey - } + promotedOngoingNotifications.pairwise(initialValue = emptyList()).collect { + (oldNotifs, currentNotifs) -> + val removedNotifKeys = + oldNotifs.map { it.key }.minus(currentNotifs.map { it.key }.toSet()) + removedNotifKeys.forEach { removedNotifKey -> + val wasRemoved = promotedNotificationInteractorMap.remove(removedNotifKey) + if (wasRemoved == null) { + logger.w({ + "Attempted to remove $str1 from interactor map but it wasn't present" + }) { + str1 = removedNotifKey } } + } - currentNotifs.forEach { notif -> - val interactor = - promotedNotificationInteractorMap.computeIfAbsent(notif.key) { - singleNotificationChipInteractorFactory.create( - notif, - creationTime = systemClock.currentTimeMillis(), - ) - } - interactor.setNotification(notif) - } - logger.d({ "Interactors: $str1" }) { - str1 = - promotedNotificationInteractorMap.keys.joinToString(separator = " /// ") - } - promotedNotificationInteractors.value = - promotedNotificationInteractorMap.values.toList() + currentNotifs.forEach { notif -> + val interactor = + promotedNotificationInteractorMap.computeIfAbsent(notif.key) { + singleNotificationChipInteractorFactory.create( + notif, + creationTime = systemClock.currentTimeMillis(), + ) + } + interactor.setNotification(notif) } + logger.d({ "Interactors: $str1" }) { + str1 = promotedNotificationInteractorMap.keys.joinToString(separator = " /// ") + } + promotedNotificationInteractors.value = + promotedNotificationInteractorMap.values.toList() + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt index ec3a5b271e35..18b0dee1c08f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt @@ -23,7 +23,7 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.chips.notification.domain.interactor.StatusBarNotificationChipsInteractor import com.android.systemui.statusbar.chips.notification.domain.model.NotificationChipModel import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips -import com.android.systemui.statusbar.chips.ui.model.ColorsModel +import com.android.systemui.statusbar.chips.ui.model.ColorsModel.Companion.toCustomColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor @@ -72,11 +72,7 @@ constructor( StatusBarConnectedDisplays.assertInNewMode() OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon(this.key) } - val colors = - ColorsModel.Custom( - backgroundColorInt = this.promotedContent.colors.backgroundColor, - primaryTextColorInt = this.promotedContent.colors.primaryTextColor, - ) + val colors = this.promotedContent.toCustomColorsModel() val onClickListener = View.OnClickListener { // The notification pipeline needs everything to run on the main thread, so keep diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt index cac25d04f1a5..25f90f9a0065 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt @@ -21,6 +21,7 @@ import android.content.res.ColorStateList import androidx.annotation.ColorInt import com.android.settingslib.Utils import com.android.systemui.res.R +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel /** Model representing how the chip in the status bar should be colored. */ sealed interface ColorsModel { @@ -55,4 +56,14 @@ sealed interface ColorsModel { override fun text(context: Context) = context.getColor(android.R.color.white) } + + companion object { + /** Converts the promoted notification colors to a [Custom] colors model. */ + fun PromotedNotificationContentModel.toCustomColorsModel(): Custom { + return Custom( + backgroundColorInt = this.colors.backgroundColor, + primaryTextColorInt = this.colors.primaryTextColor, + ) + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt index 0c040c855368..502fb51ba5c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt @@ -76,11 +76,14 @@ constructor( val allNotificationsCountValue: Int get() = repository.activeNotifications.value.individuals.size - /** The notifications that are promoted and ongoing. Sorted by priority order. */ + /** + * The notifications that are promoted and ongoing. + * + * This *may* include ongoing call notifications if the call notification also meets promotion + * criteria. + */ val promotedOngoingNotifications: Flow> = if (StatusBarNotifChips.isEnabled) { - // TODO(b/364653005): [ongoingCallNotification] should be incorporated into this flow - // instead of being separate. topLevelRepresentativeNotifications .map { notifs -> notifs.filter { it.promotedContent != null } } .distinctUntilChanged() @@ -98,10 +101,10 @@ constructor( val ongoingCallNotification: Flow = allRepresentativeNotifications .map { notifMap -> - // Once a call has started, its `whenTime` should stay the same, so we can use it as - // a stable sort value. notifMap.values - .filter { it.callType == CallType.Ongoing } + .filter { it.isOngoingCallNotification() } + // Once a call has started, its `whenTime` should stay the same, so we can use + // it as a stable sort value. .minByOrNull { it.whenTime } } .distinctUntilChanged() @@ -153,4 +156,8 @@ constructor( fun setNotifStats(notifStats: NotifStats) { repository.notifStats.value = notifStats } + + companion object { + fun ActiveNotificationModel.isOngoingCallNotification() = this.callType == CallType.Ongoing + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt index 4eb69babfadb..a29934fa3a16 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt @@ -39,6 +39,7 @@ import com.android.systemui.statusbar.chips.ui.view.ChipChronometer import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.notification.shared.CallType import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository @@ -159,6 +160,7 @@ constructor( notificationIconView = currentInfo.notificationIconView, intent = currentInfo.intent, notificationKey = currentInfo.key, + promotedContent = currentInfo.promotedContent, ) } else { return OngoingCallModel.NoCall @@ -215,6 +217,7 @@ constructor( notifModel.statusBarChipIconView, notifModel.contentIntent, notifModel.uid, + notifModel.promotedContent, isOngoing = true, statusBarSwipedAway = callNotificationInfo?.statusBarSwipedAway ?: false, ) @@ -334,6 +337,11 @@ constructor( val notificationIconView: StatusBarIconView?, val intent: PendingIntent?, val uid: Int, + /** + * If the call notification also meets promoted notification criteria, this field is filled + * in with the content related to promotion. Otherwise null. + */ + val promotedContent: PromotedNotificationContentModel?, /** True if the call is currently ongoing (as opposed to incoming, screening, etc.). */ val isOngoing: Boolean, /** True if the user has swiped away the status bar while in this phone call. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt index 2bfbf4826053..99141f592a2e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt @@ -165,6 +165,7 @@ constructor( notificationIconView = model.statusBarChipIconView, intent = model.contentIntent, notificationKey = model.key, + promotedContent = model.promotedContent, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt index 1a5dcc16f3db..7d00e9d58e5b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone.ongoingcall.shared.model import android.app.PendingIntent import com.android.systemui.statusbar.StatusBarIconView +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel /** Represents the state of any ongoing calls. */ sealed interface OngoingCallModel { @@ -25,8 +26,8 @@ sealed interface OngoingCallModel { data object NoCall : OngoingCallModel /** - * There is an ongoing call but the call app is currently visible, so we don't need to show - * the chip. + * There is an ongoing call but the call app is currently visible, so we don't need to show the + * chip. */ data object InCallWithVisibleApp : OngoingCallModel @@ -41,11 +42,14 @@ sealed interface OngoingCallModel { * @property notificationIconView the [android.app.Notification.getSmallIcon] that's set on the * call notification. We may use this icon in the chip instead of the default phone icon. * @property intent the intent associated with the call notification. + * @property promotedContent if the call notification also meets promoted notification criteria, + * this field is filled in with the content related to promotion. Otherwise null. */ data class InCall( val startTimeMs: Long, val notificationIconView: StatusBarIconView?, val intent: PendingIntent?, val notificationKey: String, + val promotedContent: PromotedNotificationContentModel?, ) : OngoingCallModel } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt index 766b280334c8..f4e74fe0e6bb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone.ongoingcall.shared.model import android.app.PendingIntent import com.android.systemui.statusbar.StatusBarIconView +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel /** Helper for building [OngoingCallModel.InCall] instances in tests. */ fun inCallModel( @@ -25,4 +26,5 @@ fun inCallModel( notificationIcon: StatusBarIconView? = null, intent: PendingIntent? = null, notificationKey: String = "test", -) = OngoingCallModel.InCall(startTimeMs, notificationIcon, intent, notificationKey) + promotedContent: PromotedNotificationContentModel? = null, +) = OngoingCallModel.InCall(startTimeMs, notificationIcon, intent, notificationKey, promotedContent) -- cgit v1.2.3-59-g8ed1b