Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt +89 −60 Original line number Diff line number Diff line Loading @@ -26,16 +26,15 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.data.repository.notificationListenerSettingsRepository import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior 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.data.repository.getPipelineModels import com.android.systemui.statusbar.notification.data.repository.getPopulatedActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor import com.android.systemui.statusbar.notification.promoted.domain.interactor.aodPromotedNotificationInteractor import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentBuilder import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style.Base import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModels import com.android.systemui.statusbar.notification.shared.ActiveBundleModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.notification.shared.ActivePipelineEntryModel import com.android.systemui.statusbar.notification.shared.byAssociatedNotifModel import com.android.systemui.statusbar.notification.shared.byIconIsAmbient import com.android.systemui.statusbar.notification.shared.byIconNotifKey Loading Loading @@ -74,13 +73,15 @@ class NotificationIconsInteractorTest : SysuiTestCase() { kosmos.applicationContext, ) private lateinit var testIcons: List<ActivePipelineEntryModel> @Before fun setup() { testScope.apply { activeNotificationListRepository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { testIcons.forEach(::addIndividualNotif) } .build() kosmos.getPopulatedActiveNotificationsStore() testIcons = activeNotificationListRepository.activeNotifications.value.getPipelineModels() } } Loading Loading @@ -108,7 +109,12 @@ class NotificationIconsInteractorTest : SysuiTestCase() { assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) .containsNoneIn( testIcons.filter { (it is ActiveNotificationModel && it.isSuppressedFromStatusBar) || (it is ActiveBundleModel && it.key == "bundle2") } ) } @Test Loading @@ -117,7 +123,7 @@ class NotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.filteredNotifSet(showLowPriority = false)) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSilent }) .containsNoneIn(testIcons.filter { it is ActiveNotificationModel && it.isSilent }) } @Test Loading @@ -126,7 +132,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.filteredNotifSet(showDismissed = false)) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isRowDismissed } ) } @Test Loading @@ -136,7 +144,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { collectLastValue(underTest.filteredNotifSet(showRepliedMessages = false)) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isLastMessageFromReply } ) } @Test Loading @@ -146,7 +156,7 @@ class NotificationIconsInteractorTest : SysuiTestCase() { notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isPulsing }) .containsNoneIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } @Test Loading @@ -156,7 +166,7 @@ class NotificationIconsInteractorTest : SysuiTestCase() { notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) .containsAnyIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } @Test Loading @@ -165,7 +175,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = true)) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.promotedContent != null }) .containsAnyIn( testIcons.filter { it is ActiveNotificationModel && it.promotedContent != null } ) } } Loading @@ -175,7 +187,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = false)) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.promotedContent != null }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.promotedContent != null } ) } } } Loading @@ -190,12 +204,19 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { private val underTest get() = kosmos.alwaysOnDisplayNotificationIconsInteractor private val activeNotificationListRepository get() = kosmos.activeNotificationListRepository private lateinit var testIcons: List<ActivePipelineEntryModel> @Before fun setup() { kosmos.activeNotificationListRepository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { testIcons.forEach(::addIndividualNotif) } .build() testScope.apply { activeNotificationListRepository.activeNotifications.value = kosmos.getPopulatedActiveNotificationsStore() testIcons = activeNotificationListRepository.activeNotifications.value.getPipelineModels() } } @Test Loading @@ -213,7 +234,12 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) .containsNoneIn( testIcons.filter { (it is ActiveNotificationModel && it.isSuppressedFromStatusBar) || (it is ActiveBundleModel && it.key == "bundle2") } ) } @Test Loading @@ -222,7 +248,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isRowDismissed } ) } @Test Loading @@ -231,7 +259,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isLastMessageFromReply } ) } @Test Loading @@ -242,7 +272,7 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) .containsAnyIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } @Test Loading @@ -253,7 +283,7 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) .containsAnyIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } @Test Loading @@ -264,7 +294,7 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isPulsing }) .containsNoneIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } @Test Loading @@ -275,7 +305,7 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) .containsAnyIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } } Loading @@ -291,13 +321,18 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationListenerSettingsRepository, ) private val activeNotificationListRepository get() = kosmos.activeNotificationListRepository private lateinit var testIcons: List<ActivePipelineEntryModel> @Before fun setup() { testScope.apply { kosmos.activeNotificationListRepository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { testIcons.forEach(::addIndividualNotif) } .build() activeNotificationListRepository.activeNotifications.value = kosmos.getPopulatedActiveNotificationsStore() testIcons = activeNotificationListRepository.activeNotifications.value.getPipelineModels() } } Loading @@ -316,7 +351,12 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) .containsNoneIn( testIcons.filter { (it is ActiveNotificationModel && it.isSuppressedFromStatusBar) || (it is ActiveBundleModel && it.key == "bundle2") } ) } @Test Loading @@ -326,7 +366,11 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationListenerSettingsRepository.showSilentStatusIcons.value = false assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSilent }) .containsNoneIn( testIcons.filter { (it is ActiveNotificationModel && it.isSilent) || (it is ActiveBundleModel) } ) } @Test Loading @@ -336,7 +380,11 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationListenerSettingsRepository.showSilentStatusIcons.value = true assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isSilent }) .containsAnyIn( testIcons.filter { (it is ActiveNotificationModel && it.isSilent) || (it is ActiveBundleModel) } ) } @Test Loading @@ -345,7 +393,9 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isRowDismissed } ) } @Test Loading @@ -354,7 +404,9 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isLastMessageFromReply } ) } @Test Loading @@ -366,26 +418,3 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).contains("notif5") } } private val testIcons = listOf( activeNotificationModel(key = "notif1", groupKey = "g1"), activeNotificationModel(key = "notif2", groupKey = "g2", isAmbient = true), activeNotificationModel(key = "notif3", groupKey = "g3", isRowDismissed = true), activeNotificationModel(key = "notif4", groupKey = "g4", isSilent = true), activeNotificationModel(key = "notif5", groupKey = "g5", isLastMessageFromReply = true), activeNotificationModel(key = "notif6", groupKey = "g6", isSuppressedFromStatusBar = true), activeNotificationModel(key = "notif7", groupKey = "g7", isPulsing = true), activeNotificationModel( key = "notif8", groupKey = "g8", promotedContent = promotedContent("notif8", Base), ), ) private fun promotedContent( key: String, style: PromotedNotificationContentModel.Style, ): PromotedNotificationContentModels { return PromotedNotificationContentBuilder(key).applyToShared { this.style = style }.build() } packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt +30 −9 Original line number Diff line number Diff line Loading @@ -22,11 +22,31 @@ val byKey: Correspondence<ActiveNotificationModel, String> = Correspondence.transforming({ it.key }, "has a key of") val byIconIsAmbient: Correspondence<ActiveNotificationIconModel, Boolean> = Correspondence.transforming({ it.isAmbient }, "has an isAmbient value of") val byAssociatedNotifModel: Correspondence<ActiveNotificationIconModel, ActiveNotificationModel> = val byAssociatedNotifModel: Correspondence<ActiveNotificationIconModel, ActivePipelineEntryModel> = Correspondence.transforming( /* actualTransform = */ { it }, /* expectedTransform = */ { expected -> checkNotNull(expected) when (expected) { is ActiveBundleModel -> ActiveNotificationIconModel( expected.key, expected.key, expected.icon, expected.icon, expected.icon, false, ) is ActiveNotificationGroupModel -> ActiveNotificationIconModel( expected.key, expected.summary.groupKey!!, expected.summary.shelfIcon, expected.summary.statusBarIcon, expected.summary.aodIcon, expected.summary.isAmbient, ) is ActiveNotificationModel -> ActiveNotificationIconModel( expected.key, expected.groupKey!!, Loading @@ -35,6 +55,7 @@ val byAssociatedNotifModel: Correspondence<ActiveNotificationIconModel, ActiveNo expected.aodIcon, expected.isAmbient, ) } }, /* description = */ "is icon model of", ) Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt +6 −7 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import android.content.Context import android.graphics.drawable.Icon import android.service.notification.StatusBarNotification import android.util.ArrayMap import androidx.annotation.DrawableRes import com.android.app.tracing.traceSection import com.android.internal.logging.InstanceId import com.android.systemui.dagger.qualifiers.Main Loading Loading @@ -122,7 +121,7 @@ private class ActiveNotificationsStoreBuilder( builder.addBundle( existingModels.createOrReuseBundle( key = entry.key, iconResId = entry.bundleRepository.bundleIcon, icon = Icon.createWithResource(context, entry.bundleRepository.bundleIcon), children = childModels, ) ) Loading Loading @@ -412,21 +411,21 @@ private fun StatusBarNotification.toCallType(): CallType = private fun ActiveNotificationsStore.createOrReuseBundle( key: String, @DrawableRes iconResId: Int, icon: Icon, children: List<ActiveNotificationEntryModel>, ): ActiveBundleModel { return bundles[key]?.takeIf { it.isCurrent(key, iconResId, children) } ?: ActiveBundleModel(key, iconResId, children) return bundles[key]?.takeIf { it.isCurrent(key, icon, children) } ?: ActiveBundleModel(key, icon, children) } private fun ActiveBundleModel.isCurrent( key: String, @DrawableRes iconResId: Int, icon: Icon, children: List<ActiveNotificationEntryModel>, ): Boolean { return when { key != this.key -> false iconResId != this.iconResId -> false icon.resId != this.icon.resId -> false !hasSameInstances(children, this.children) -> false else -> true } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt +28 −4 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import com.android.systemui.statusbar.notification.data.repository.Notifications import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor import com.android.systemui.statusbar.notification.promoted.domain.interactor.AODPromotedNotificationInteractor import com.android.systemui.statusbar.notification.shared.ActiveBundleModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationEntryModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.wm.shell.bubbles.Bubbles Loading Loading @@ -90,7 +91,11 @@ constructor( // bundles are located in the silent section, so only include them // if we're showing low priority icons is ActiveBundleModel -> if (showLowPriority) Either.first(it.toIconModel()) else null if (shouldShowBundleIcon(it, showAmbient, showLowPriority)) { Either.first(it.toIconModel()) } else { null } is ActiveNotificationGroupModel -> Either.second(it.summary) is ActiveNotificationModel -> Either.second(it) } Loading Loading @@ -120,6 +125,25 @@ constructor( } } private fun shouldShowBundleIcon( model: ActiveBundleModel, showAmbient: Boolean, showLowPriority: Boolean, ): Boolean { return when { !showLowPriority -> false !showAmbient && areAllChildrenSuppressed(model.children) -> false else -> true } } private fun areAllChildrenSuppressed(children: List<ActiveNotificationEntryModel>): Boolean { return children.none { (it is ActiveNotificationModel && !it.isSuppressedFromStatusBar) || (it is ActiveNotificationGroupModel && !areAllChildrenSuppressed(it.children)) } } private fun shouldShowNotificationIcon( model: ActiveNotificationModel, forceShowHeadsUp: Boolean, Loading Loading @@ -150,9 +174,9 @@ constructor( ActiveNotificationIconModel( notifKey = key, groupKey = key, shelfIcon = Icon.createWithResource(appContext, iconResId), statusBarIcon = Icon.createWithResource(appContext, iconResId), aodIcon = null, shelfIcon = icon, statusBarIcon = icon, aodIcon = icon, isAmbient = false, ) } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt +1 −2 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.shared import android.app.PendingIntent import android.graphics.drawable.Icon import android.util.Log import androidx.annotation.DrawableRes import com.android.internal.logging.InstanceId import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel Loading @@ -35,7 +34,7 @@ sealed class ActivePipelineEntryModel /** Model for a bundle of notifications. */ data class ActiveBundleModel( val key: String, @DrawableRes val iconResId: Int, val icon: Icon, val children: List<ActiveNotificationEntryModel>, ) : ActivePipelineEntryModel() Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt +89 −60 Original line number Diff line number Diff line Loading @@ -26,16 +26,15 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.data.repository.notificationListenerSettingsRepository import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior 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.data.repository.getPipelineModels import com.android.systemui.statusbar.notification.data.repository.getPopulatedActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor import com.android.systemui.statusbar.notification.promoted.domain.interactor.aodPromotedNotificationInteractor import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentBuilder import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style.Base import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModels import com.android.systemui.statusbar.notification.shared.ActiveBundleModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.notification.shared.ActivePipelineEntryModel import com.android.systemui.statusbar.notification.shared.byAssociatedNotifModel import com.android.systemui.statusbar.notification.shared.byIconIsAmbient import com.android.systemui.statusbar.notification.shared.byIconNotifKey Loading Loading @@ -74,13 +73,15 @@ class NotificationIconsInteractorTest : SysuiTestCase() { kosmos.applicationContext, ) private lateinit var testIcons: List<ActivePipelineEntryModel> @Before fun setup() { testScope.apply { activeNotificationListRepository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { testIcons.forEach(::addIndividualNotif) } .build() kosmos.getPopulatedActiveNotificationsStore() testIcons = activeNotificationListRepository.activeNotifications.value.getPipelineModels() } } Loading Loading @@ -108,7 +109,12 @@ class NotificationIconsInteractorTest : SysuiTestCase() { assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) .containsNoneIn( testIcons.filter { (it is ActiveNotificationModel && it.isSuppressedFromStatusBar) || (it is ActiveBundleModel && it.key == "bundle2") } ) } @Test Loading @@ -117,7 +123,7 @@ class NotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.filteredNotifSet(showLowPriority = false)) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSilent }) .containsNoneIn(testIcons.filter { it is ActiveNotificationModel && it.isSilent }) } @Test Loading @@ -126,7 +132,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.filteredNotifSet(showDismissed = false)) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isRowDismissed } ) } @Test Loading @@ -136,7 +144,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { collectLastValue(underTest.filteredNotifSet(showRepliedMessages = false)) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isLastMessageFromReply } ) } @Test Loading @@ -146,7 +156,7 @@ class NotificationIconsInteractorTest : SysuiTestCase() { notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isPulsing }) .containsNoneIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } @Test Loading @@ -156,7 +166,7 @@ class NotificationIconsInteractorTest : SysuiTestCase() { notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) .containsAnyIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } @Test Loading @@ -165,7 +175,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = true)) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.promotedContent != null }) .containsAnyIn( testIcons.filter { it is ActiveNotificationModel && it.promotedContent != null } ) } } Loading @@ -175,7 +187,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = false)) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.promotedContent != null }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.promotedContent != null } ) } } } Loading @@ -190,12 +204,19 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { private val underTest get() = kosmos.alwaysOnDisplayNotificationIconsInteractor private val activeNotificationListRepository get() = kosmos.activeNotificationListRepository private lateinit var testIcons: List<ActivePipelineEntryModel> @Before fun setup() { kosmos.activeNotificationListRepository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { testIcons.forEach(::addIndividualNotif) } .build() testScope.apply { activeNotificationListRepository.activeNotifications.value = kosmos.getPopulatedActiveNotificationsStore() testIcons = activeNotificationListRepository.activeNotifications.value.getPipelineModels() } } @Test Loading @@ -213,7 +234,12 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) .containsNoneIn( testIcons.filter { (it is ActiveNotificationModel && it.isSuppressedFromStatusBar) || (it is ActiveBundleModel && it.key == "bundle2") } ) } @Test Loading @@ -222,7 +248,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isRowDismissed } ) } @Test Loading @@ -231,7 +259,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isLastMessageFromReply } ) } @Test Loading @@ -242,7 +272,7 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) .containsAnyIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } @Test Loading @@ -253,7 +283,7 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) .containsAnyIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } @Test Loading @@ -264,7 +294,7 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isPulsing }) .containsNoneIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } @Test Loading @@ -275,7 +305,7 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) .containsAnyIn(testIcons.filter { it is ActiveNotificationModel && it.isPulsing }) } } Loading @@ -291,13 +321,18 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationListenerSettingsRepository, ) private val activeNotificationListRepository get() = kosmos.activeNotificationListRepository private lateinit var testIcons: List<ActivePipelineEntryModel> @Before fun setup() { testScope.apply { kosmos.activeNotificationListRepository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { testIcons.forEach(::addIndividualNotif) } .build() activeNotificationListRepository.activeNotifications.value = kosmos.getPopulatedActiveNotificationsStore() testIcons = activeNotificationListRepository.activeNotifications.value.getPipelineModels() } } Loading @@ -316,7 +351,12 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) .containsNoneIn( testIcons.filter { (it is ActiveNotificationModel && it.isSuppressedFromStatusBar) || (it is ActiveBundleModel && it.key == "bundle2") } ) } @Test Loading @@ -326,7 +366,11 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationListenerSettingsRepository.showSilentStatusIcons.value = false assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSilent }) .containsNoneIn( testIcons.filter { (it is ActiveNotificationModel && it.isSilent) || (it is ActiveBundleModel) } ) } @Test Loading @@ -336,7 +380,11 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { kosmos.notificationListenerSettingsRepository.showSilentStatusIcons.value = true assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isSilent }) .containsAnyIn( testIcons.filter { (it is ActiveNotificationModel && it.isSilent) || (it is ActiveBundleModel) } ) } @Test Loading @@ -345,7 +393,9 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isRowDismissed } ) } @Test Loading @@ -354,7 +404,9 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) .containsNoneIn( testIcons.filter { it is ActiveNotificationModel && it.isLastMessageFromReply } ) } @Test Loading @@ -366,26 +418,3 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).contains("notif5") } } private val testIcons = listOf( activeNotificationModel(key = "notif1", groupKey = "g1"), activeNotificationModel(key = "notif2", groupKey = "g2", isAmbient = true), activeNotificationModel(key = "notif3", groupKey = "g3", isRowDismissed = true), activeNotificationModel(key = "notif4", groupKey = "g4", isSilent = true), activeNotificationModel(key = "notif5", groupKey = "g5", isLastMessageFromReply = true), activeNotificationModel(key = "notif6", groupKey = "g6", isSuppressedFromStatusBar = true), activeNotificationModel(key = "notif7", groupKey = "g7", isPulsing = true), activeNotificationModel( key = "notif8", groupKey = "g8", promotedContent = promotedContent("notif8", Base), ), ) private fun promotedContent( key: String, style: PromotedNotificationContentModel.Style, ): PromotedNotificationContentModels { return PromotedNotificationContentBuilder(key).applyToShared { this.style = style }.build() }
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt +30 −9 Original line number Diff line number Diff line Loading @@ -22,11 +22,31 @@ val byKey: Correspondence<ActiveNotificationModel, String> = Correspondence.transforming({ it.key }, "has a key of") val byIconIsAmbient: Correspondence<ActiveNotificationIconModel, Boolean> = Correspondence.transforming({ it.isAmbient }, "has an isAmbient value of") val byAssociatedNotifModel: Correspondence<ActiveNotificationIconModel, ActiveNotificationModel> = val byAssociatedNotifModel: Correspondence<ActiveNotificationIconModel, ActivePipelineEntryModel> = Correspondence.transforming( /* actualTransform = */ { it }, /* expectedTransform = */ { expected -> checkNotNull(expected) when (expected) { is ActiveBundleModel -> ActiveNotificationIconModel( expected.key, expected.key, expected.icon, expected.icon, expected.icon, false, ) is ActiveNotificationGroupModel -> ActiveNotificationIconModel( expected.key, expected.summary.groupKey!!, expected.summary.shelfIcon, expected.summary.statusBarIcon, expected.summary.aodIcon, expected.summary.isAmbient, ) is ActiveNotificationModel -> ActiveNotificationIconModel( expected.key, expected.groupKey!!, Loading @@ -35,6 +55,7 @@ val byAssociatedNotifModel: Correspondence<ActiveNotificationIconModel, ActiveNo expected.aodIcon, expected.isAmbient, ) } }, /* description = */ "is icon model of", ) Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt +6 −7 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import android.content.Context import android.graphics.drawable.Icon import android.service.notification.StatusBarNotification import android.util.ArrayMap import androidx.annotation.DrawableRes import com.android.app.tracing.traceSection import com.android.internal.logging.InstanceId import com.android.systemui.dagger.qualifiers.Main Loading Loading @@ -122,7 +121,7 @@ private class ActiveNotificationsStoreBuilder( builder.addBundle( existingModels.createOrReuseBundle( key = entry.key, iconResId = entry.bundleRepository.bundleIcon, icon = Icon.createWithResource(context, entry.bundleRepository.bundleIcon), children = childModels, ) ) Loading Loading @@ -412,21 +411,21 @@ private fun StatusBarNotification.toCallType(): CallType = private fun ActiveNotificationsStore.createOrReuseBundle( key: String, @DrawableRes iconResId: Int, icon: Icon, children: List<ActiveNotificationEntryModel>, ): ActiveBundleModel { return bundles[key]?.takeIf { it.isCurrent(key, iconResId, children) } ?: ActiveBundleModel(key, iconResId, children) return bundles[key]?.takeIf { it.isCurrent(key, icon, children) } ?: ActiveBundleModel(key, icon, children) } private fun ActiveBundleModel.isCurrent( key: String, @DrawableRes iconResId: Int, icon: Icon, children: List<ActiveNotificationEntryModel>, ): Boolean { return when { key != this.key -> false iconResId != this.iconResId -> false icon.resId != this.icon.resId -> false !hasSameInstances(children, this.children) -> false else -> true } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt +28 −4 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import com.android.systemui.statusbar.notification.data.repository.Notifications import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor import com.android.systemui.statusbar.notification.promoted.domain.interactor.AODPromotedNotificationInteractor import com.android.systemui.statusbar.notification.shared.ActiveBundleModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationEntryModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.wm.shell.bubbles.Bubbles Loading Loading @@ -90,7 +91,11 @@ constructor( // bundles are located in the silent section, so only include them // if we're showing low priority icons is ActiveBundleModel -> if (showLowPriority) Either.first(it.toIconModel()) else null if (shouldShowBundleIcon(it, showAmbient, showLowPriority)) { Either.first(it.toIconModel()) } else { null } is ActiveNotificationGroupModel -> Either.second(it.summary) is ActiveNotificationModel -> Either.second(it) } Loading Loading @@ -120,6 +125,25 @@ constructor( } } private fun shouldShowBundleIcon( model: ActiveBundleModel, showAmbient: Boolean, showLowPriority: Boolean, ): Boolean { return when { !showLowPriority -> false !showAmbient && areAllChildrenSuppressed(model.children) -> false else -> true } } private fun areAllChildrenSuppressed(children: List<ActiveNotificationEntryModel>): Boolean { return children.none { (it is ActiveNotificationModel && !it.isSuppressedFromStatusBar) || (it is ActiveNotificationGroupModel && !areAllChildrenSuppressed(it.children)) } } private fun shouldShowNotificationIcon( model: ActiveNotificationModel, forceShowHeadsUp: Boolean, Loading Loading @@ -150,9 +174,9 @@ constructor( ActiveNotificationIconModel( notifKey = key, groupKey = key, shelfIcon = Icon.createWithResource(appContext, iconResId), statusBarIcon = Icon.createWithResource(appContext, iconResId), aodIcon = null, shelfIcon = icon, statusBarIcon = icon, aodIcon = icon, isAmbient = false, ) } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt +1 −2 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.shared import android.app.PendingIntent import android.graphics.drawable.Icon import android.util.Log import androidx.annotation.DrawableRes import com.android.internal.logging.InstanceId import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel Loading @@ -35,7 +34,7 @@ sealed class ActivePipelineEntryModel /** Model for a bundle of notifications. */ data class ActiveBundleModel( val key: String, @DrawableRes val iconResId: Int, val icon: Icon, val children: List<ActiveNotificationEntryModel>, ) : ActivePipelineEntryModel() Loading