diff options
| author | 2025-01-15 09:23:16 -0800 | |
|---|---|---|
| committer | 2025-01-15 09:23:16 -0800 | |
| commit | 3232c75ca49604c1dc14f7c6fcec23cdc6d42d43 (patch) | |
| tree | 32c4a562f72b18e7e11f28c59a5e9c7af12c89ae | |
| parent | 51e33fd3a69900f62895bf38a7150485daebd984 (diff) | |
| parent | 3abfc4d5894835b2d8cdaff8bb175b8643470e4f (diff) | |
Merge "[SB][Notif] Don't allow call notif to also show in a promoted notif chip" into main
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,28 +221,94 @@ 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 { val latest by collectLastValue(underTest.chip) @@ -319,5 +387,19 @@ class CallChipViewModelTest : SysuiTestCase() { } else { mock<StatusBarIconView>() } + + 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 @@ -169,6 +170,27 @@ class OngoingCallControllerTest : SysuiTestCase() { } @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<List<SingleNotificationChipInteractor>>(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<List<ActiveNotificationModel>> = 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<ActiveNotificationModel?> = 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) |