Loading packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/row/BundleHeader.kt +1 −1 Original line number Diff line number Diff line Loading @@ -151,7 +151,7 @@ private fun ContentScope.BundleHeaderContent( ) if (collapsed) { val currentPreviewIcons by val currentPreviewIcons: List<Drawable> by viewModel.previewIcons.collectAsStateWithLifecycle(initialValue = emptyList()) if (currentPreviewIcons.isNotEmpty()) { BundlePreviewIcons( Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt +94 −58 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ package com.android.systemui.statusbar.notification.icon.domain.interactor import android.content.applicationContext import android.platform.test.annotations.DisableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest Loading @@ -29,21 +30,15 @@ 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.data.repository.notificationsKeyguardViewStateRepository import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor 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.byIsAmbient import com.android.systemui.statusbar.notification.shared.byIsLastMessageFromReply import com.android.systemui.statusbar.notification.shared.byIsPromoted import com.android.systemui.statusbar.notification.shared.byIsPulsing import com.android.systemui.statusbar.notification.shared.byIsRowDismissed import com.android.systemui.statusbar.notification.shared.byIsSilent import com.android.systemui.statusbar.notification.shared.byIsSuppressedFromStatusBar import com.android.systemui.statusbar.notification.shared.byKey import com.android.systemui.statusbar.notification.shared.byAssociatedNotifModel import com.android.systemui.statusbar.notification.shared.byIconIsAmbient import com.android.systemui.statusbar.notification.shared.byIconNotifKey import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor import com.android.systemui.testKosmos import com.android.systemui.util.mockito.eq Loading @@ -60,18 +55,23 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class NotificationIconsInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val activeNotificationListRepository = kosmos.activeNotificationListRepository private val notificationsKeyguardInteractor = kosmos.notificationsKeyguardInteractor private val aodPromotedNotificationInteractor = kosmos.aodPromotedNotificationInteractor private val testScope get() = kosmos.testScope private val activeNotificationListRepository get() = kosmos.activeNotificationListRepository private val notificationsKeyguardInteractor get() = kosmos.notificationsKeyguardInteractor private val underTest = NotificationIconsInteractor( kosmos.activeNotificationsInteractor, kosmos.activeNotificationListRepository, kosmos.bubblesOptional, kosmos.headsUpNotificationIconInteractor, kosmos.aodPromotedNotificationInteractor, kosmos.notificationsKeyguardViewStateRepository, kosmos.applicationContext, ) @Before Loading @@ -88,7 +88,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { fun filteredEntrySet() = testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet()) assertThat(filteredSet).containsExactlyElementsIn(testIcons) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsExactlyElementsIn(testIcons) } @Test Loading @@ -96,31 +98,35 @@ class NotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { whenever(kosmos.bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true) val filteredSet by collectLastValue(underTest.filteredNotifSet()) assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1") assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).doesNotContain("notif1") } @Test fun filteredEntrySet_noAmbient() = testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showAmbient = false)) assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true) assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byIsSuppressedFromStatusBar) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) } @Test fun filteredEntrySet_noLowPriority() = testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showLowPriority = false)) assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSilent }) } @Test fun filteredEntrySet_noDismissed() = testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showDismissed = false)) assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) } @Test Loading @@ -129,8 +135,8 @@ class NotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.filteredNotifSet(showRepliedMessages = false)) assertThat(filteredSet) .comparingElementsUsing(byIsLastMessageFromReply) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) } @Test Loading @@ -138,7 +144,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false)) notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isPulsing }) } @Test Loading @@ -146,14 +154,18 @@ class NotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false)) notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) } @Test fun filteredEntrySet_showAodPromoted() { testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = true)) assertThat(filteredSet).comparingElementsUsing(byIsPromoted).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.promotedContent != null }) } } Loading @@ -161,7 +173,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { fun filteredEntrySet_noAodPromoted() { testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = false)) assertThat(filteredSet).comparingElementsUsing(byIsPromoted).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.promotedContent != null }) } } } Loading @@ -170,9 +184,11 @@ class NotificationIconsInteractorTest : SysuiTestCase() { @RunWith(AndroidJUnit4::class) class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val testScope get() = kosmos.testScope private val underTest = kosmos.alwaysOnDisplayNotificationIconsInteractor private val underTest get() = kosmos.alwaysOnDisplayNotificationIconsInteractor @Before fun setup() { Loading @@ -187,24 +203,26 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { whenever(kosmos.bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true) val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1") assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).doesNotContain("notif1") } @Test fun filteredEntrySet_noAmbient() = testScope.runTest { val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true) assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byIsSuppressedFromStatusBar) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) } @Test fun filteredEntrySet_noDismissed() = testScope.runTest { val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) } @Test Loading @@ -212,8 +230,8 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet) .comparingElementsUsing(byIsLastMessageFromReply) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) } @Test Loading @@ -222,7 +240,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(false) kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) } @Test Loading @@ -231,7 +251,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(false) kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) } @Test Loading @@ -240,7 +262,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(true) kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isPulsing }) } @Test Loading @@ -249,7 +273,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(true) kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) } } Loading Loading @@ -280,17 +306,17 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { whenever(kosmos.bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true) val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1") assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).doesNotContain("notif1") } @Test fun filteredEntrySet_noAmbient() = testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true) assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byIsSuppressedFromStatusBar) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) } @Test Loading @@ -298,7 +324,9 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) kosmos.notificationListenerSettingsRepository.showSilentStatusIcons.value = false assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSilent }) } @Test Loading @@ -306,14 +334,18 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) kosmos.notificationListenerSettingsRepository.showSilentStatusIcons.value = true assertThat(filteredSet).comparingElementsUsing(byIsSilent).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isSilent }) } @Test fun filteredEntrySet_noDismissed() = testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) } @Test Loading @@ -321,8 +353,8 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet) .comparingElementsUsing(byIsLastMessageFromReply) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) } @Test Loading @@ -331,20 +363,24 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) kosmos.headsUpNotificationIconInteractor.setIsolatedIconNotificationKey("notif5") assertThat(filteredSet).comparingElementsUsing(byKey).contains("notif5") assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).contains("notif5") } } private val testIcons = listOf( activeNotificationModel(key = "notif1"), activeNotificationModel(key = "notif2", isAmbient = true), activeNotificationModel(key = "notif3", isRowDismissed = true), activeNotificationModel(key = "notif4", isSilent = true), activeNotificationModel(key = "notif5", isLastMessageFromReply = true), activeNotificationModel(key = "notif6", isSuppressedFromStatusBar = true), activeNotificationModel(key = "notif7", isPulsing = true), activeNotificationModel(key = "notif8", promotedContent = promotedContent("notif8", Base)), 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( Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt +19 −20 Original line number Diff line number Diff line Loading @@ -15,30 +15,29 @@ package com.android.systemui.statusbar.notification.shared import com.android.systemui.statusbar.notification.icon.domain.interactor.ActiveNotificationIconModel import com.google.common.truth.Correspondence val byKey: Correspondence<ActiveNotificationModel, String> = Correspondence.transforming({ it.key }, "has a key of") val byIsAmbient: Correspondence<ActiveNotificationModel, Boolean> = val byIconIsAmbient: Correspondence<ActiveNotificationIconModel, Boolean> = Correspondence.transforming({ it.isAmbient }, "has an isAmbient value of") val byIsSuppressedFromStatusBar: Correspondence<ActiveNotificationModel, Boolean> = val byAssociatedNotifModel: Correspondence<ActiveNotificationIconModel, ActiveNotificationModel> = Correspondence.transforming( { it.isSuppressedFromStatusBar }, "has an isSuppressedFromStatusBar value of", /* actualTransform = */ { it }, /* expectedTransform = */ { expected -> checkNotNull(expected) ActiveNotificationIconModel( expected.key, expected.groupKey!!, expected.shelfIcon, expected.statusBarIcon, expected.aodIcon, expected.isAmbient, ) val byIsSilent: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming({ it.isSilent }, "has an isSilent value of") val byIsRowDismissed: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming({ it.isRowDismissed }, "has an isRowDismissed value of") val byIsLastMessageFromReply: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming( { it.isLastMessageFromReply }, "has an isLastMessageFromReply value of", ) val byIsPulsing: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming({ it.isPulsing }, "has an isPulsing value of") val byIsPromoted: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming( { it.promotedContent != null }, "has (or doesn't have) a promoted content model", }, /* description = */ "is icon model of", ) val byIconNotifKey: Correspondence<ActiveNotificationIconModel, String> = Correspondence.transforming({ it.notifKey }, "has a notifKey of") packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt +20 −9 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ 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 @@ -116,7 +117,11 @@ private class ActiveNotificationsStoreBuilder( private fun addBundleEntry(entry: BundleEntry) { val childModels = entry.children.mapNotNull { it.toModel() } builder.addBundle( existingModels.createOrReuseBundle(key = entry.key, children = childModels) existingModels.createOrReuseBundle( key = entry.key, iconResId = entry.bundleRepository.bundleIcon, children = childModels, ) ) } Loading @@ -132,19 +137,21 @@ private class ActiveNotificationsStoreBuilder( builder.setRankingsMap(flatMapToRankingsMap(entries)) } fun flatMapToRankingsMap(entries: List<PipelineEntry>): Map<String, Int> { private fun flatMapToRankingsMap(entries: List<PipelineEntry>): Map<String, Int> { val result = ArrayMap<String, Int>() for (entry in entries) { when (entry) { is BundleEntry -> { // TODO(b/410815667): Handle BundleEntry is BundleEntry -> flatMapToRankingsMap(entry, result) is ListEntry -> flatMapToRankingsMap(entry, result) } is ListEntry -> { flatMapToRankingsMap(entry, result) } return result } private fun flatMapToRankingsMap(entry: BundleEntry, result: ArrayMap<String, Int>) { for (child in entry.children) { flatMapToRankingsMap(child, result) } return result } private fun flatMapToRankingsMap(entry: ListEntry, result: ArrayMap<String, Int>) { Loading Loading @@ -396,17 +403,21 @@ private fun StatusBarNotification.toCallType(): CallType = private fun ActiveNotificationsStore.createOrReuseBundle( key: String, @DrawableRes iconResId: Int, children: List<ActiveNotificationEntryModel>, ): ActiveBundleModel { return bundles[key]?.takeIf { it.isCurrent(key, children) } ?: ActiveBundleModel(key, children) return bundles[key]?.takeIf { it.isCurrent(key, iconResId, children) } ?: ActiveBundleModel(key, iconResId, children) } private fun ActiveBundleModel.isCurrent( key: String, @DrawableRes iconResId: Int, children: List<ActiveNotificationEntryModel>, ): Boolean { return when { key != this.key -> false iconResId != this.iconResId -> false !hasSameInstances(children, this.children) -> false else -> true } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt +91 −22 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/row/BundleHeader.kt +1 −1 Original line number Diff line number Diff line Loading @@ -151,7 +151,7 @@ private fun ContentScope.BundleHeaderContent( ) if (collapsed) { val currentPreviewIcons by val currentPreviewIcons: List<Drawable> by viewModel.previewIcons.collectAsStateWithLifecycle(initialValue = emptyList()) if (currentPreviewIcons.isNotEmpty()) { BundlePreviewIcons( Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt +94 −58 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ package com.android.systemui.statusbar.notification.icon.domain.interactor import android.content.applicationContext import android.platform.test.annotations.DisableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest Loading @@ -29,21 +30,15 @@ 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.data.repository.notificationsKeyguardViewStateRepository import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor 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.byIsAmbient import com.android.systemui.statusbar.notification.shared.byIsLastMessageFromReply import com.android.systemui.statusbar.notification.shared.byIsPromoted import com.android.systemui.statusbar.notification.shared.byIsPulsing import com.android.systemui.statusbar.notification.shared.byIsRowDismissed import com.android.systemui.statusbar.notification.shared.byIsSilent import com.android.systemui.statusbar.notification.shared.byIsSuppressedFromStatusBar import com.android.systemui.statusbar.notification.shared.byKey import com.android.systemui.statusbar.notification.shared.byAssociatedNotifModel import com.android.systemui.statusbar.notification.shared.byIconIsAmbient import com.android.systemui.statusbar.notification.shared.byIconNotifKey import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor import com.android.systemui.testKosmos import com.android.systemui.util.mockito.eq Loading @@ -60,18 +55,23 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class NotificationIconsInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val activeNotificationListRepository = kosmos.activeNotificationListRepository private val notificationsKeyguardInteractor = kosmos.notificationsKeyguardInteractor private val aodPromotedNotificationInteractor = kosmos.aodPromotedNotificationInteractor private val testScope get() = kosmos.testScope private val activeNotificationListRepository get() = kosmos.activeNotificationListRepository private val notificationsKeyguardInteractor get() = kosmos.notificationsKeyguardInteractor private val underTest = NotificationIconsInteractor( kosmos.activeNotificationsInteractor, kosmos.activeNotificationListRepository, kosmos.bubblesOptional, kosmos.headsUpNotificationIconInteractor, kosmos.aodPromotedNotificationInteractor, kosmos.notificationsKeyguardViewStateRepository, kosmos.applicationContext, ) @Before Loading @@ -88,7 +88,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { fun filteredEntrySet() = testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet()) assertThat(filteredSet).containsExactlyElementsIn(testIcons) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsExactlyElementsIn(testIcons) } @Test Loading @@ -96,31 +98,35 @@ class NotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { whenever(kosmos.bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true) val filteredSet by collectLastValue(underTest.filteredNotifSet()) assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1") assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).doesNotContain("notif1") } @Test fun filteredEntrySet_noAmbient() = testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showAmbient = false)) assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true) assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byIsSuppressedFromStatusBar) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) } @Test fun filteredEntrySet_noLowPriority() = testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showLowPriority = false)) assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSilent }) } @Test fun filteredEntrySet_noDismissed() = testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showDismissed = false)) assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) } @Test Loading @@ -129,8 +135,8 @@ class NotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.filteredNotifSet(showRepliedMessages = false)) assertThat(filteredSet) .comparingElementsUsing(byIsLastMessageFromReply) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) } @Test Loading @@ -138,7 +144,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false)) notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isPulsing }) } @Test Loading @@ -146,14 +154,18 @@ class NotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false)) notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) } @Test fun filteredEntrySet_showAodPromoted() { testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = true)) assertThat(filteredSet).comparingElementsUsing(byIsPromoted).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.promotedContent != null }) } } Loading @@ -161,7 +173,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() { fun filteredEntrySet_noAodPromoted() { testScope.runTest { val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = false)) assertThat(filteredSet).comparingElementsUsing(byIsPromoted).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.promotedContent != null }) } } } Loading @@ -170,9 +184,11 @@ class NotificationIconsInteractorTest : SysuiTestCase() { @RunWith(AndroidJUnit4::class) class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val testScope get() = kosmos.testScope private val underTest = kosmos.alwaysOnDisplayNotificationIconsInteractor private val underTest get() = kosmos.alwaysOnDisplayNotificationIconsInteractor @Before fun setup() { Loading @@ -187,24 +203,26 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { whenever(kosmos.bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true) val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1") assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).doesNotContain("notif1") } @Test fun filteredEntrySet_noAmbient() = testScope.runTest { val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true) assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byIsSuppressedFromStatusBar) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) } @Test fun filteredEntrySet_noDismissed() = testScope.runTest { val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) } @Test Loading @@ -212,8 +230,8 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.aodNotifs) assertThat(filteredSet) .comparingElementsUsing(byIsLastMessageFromReply) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) } @Test Loading @@ -222,7 +240,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(false) kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) } @Test Loading @@ -231,7 +251,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(false) kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) } @Test Loading @@ -240,7 +262,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(true) kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(false) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isPulsing }) } @Test Loading @@ -249,7 +273,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() { val filteredSet by collectLastValue(underTest.aodNotifs) kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(true) kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(true) assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isPulsing }) } } Loading Loading @@ -280,17 +306,17 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { whenever(kosmos.bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true) val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1") assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).doesNotContain("notif1") } @Test fun filteredEntrySet_noAmbient() = testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true) assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byIsSuppressedFromStatusBar) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar }) } @Test Loading @@ -298,7 +324,9 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) kosmos.notificationListenerSettingsRepository.showSilentStatusIcons.value = false assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isSilent }) } @Test Loading @@ -306,14 +334,18 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) kosmos.notificationListenerSettingsRepository.showSilentStatusIcons.value = true assertThat(filteredSet).comparingElementsUsing(byIsSilent).contains(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsAnyIn(testIcons.filter { it.isSilent }) } @Test fun filteredEntrySet_noDismissed() = testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true) assertThat(filteredSet) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isRowDismissed }) } @Test Loading @@ -321,8 +353,8 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) assertThat(filteredSet) .comparingElementsUsing(byIsLastMessageFromReply) .doesNotContain(true) .comparingElementsUsing(byAssociatedNotifModel) .containsNoneIn(testIcons.filter { it.isLastMessageFromReply }) } @Test Loading @@ -331,20 +363,24 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() { testScope.runTest { val filteredSet by collectLastValue(underTest.statusBarNotifs) kosmos.headsUpNotificationIconInteractor.setIsolatedIconNotificationKey("notif5") assertThat(filteredSet).comparingElementsUsing(byKey).contains("notif5") assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).contains("notif5") } } private val testIcons = listOf( activeNotificationModel(key = "notif1"), activeNotificationModel(key = "notif2", isAmbient = true), activeNotificationModel(key = "notif3", isRowDismissed = true), activeNotificationModel(key = "notif4", isSilent = true), activeNotificationModel(key = "notif5", isLastMessageFromReply = true), activeNotificationModel(key = "notif6", isSuppressedFromStatusBar = true), activeNotificationModel(key = "notif7", isPulsing = true), activeNotificationModel(key = "notif8", promotedContent = promotedContent("notif8", Base)), 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( Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt +19 −20 Original line number Diff line number Diff line Loading @@ -15,30 +15,29 @@ package com.android.systemui.statusbar.notification.shared import com.android.systemui.statusbar.notification.icon.domain.interactor.ActiveNotificationIconModel import com.google.common.truth.Correspondence val byKey: Correspondence<ActiveNotificationModel, String> = Correspondence.transforming({ it.key }, "has a key of") val byIsAmbient: Correspondence<ActiveNotificationModel, Boolean> = val byIconIsAmbient: Correspondence<ActiveNotificationIconModel, Boolean> = Correspondence.transforming({ it.isAmbient }, "has an isAmbient value of") val byIsSuppressedFromStatusBar: Correspondence<ActiveNotificationModel, Boolean> = val byAssociatedNotifModel: Correspondence<ActiveNotificationIconModel, ActiveNotificationModel> = Correspondence.transforming( { it.isSuppressedFromStatusBar }, "has an isSuppressedFromStatusBar value of", /* actualTransform = */ { it }, /* expectedTransform = */ { expected -> checkNotNull(expected) ActiveNotificationIconModel( expected.key, expected.groupKey!!, expected.shelfIcon, expected.statusBarIcon, expected.aodIcon, expected.isAmbient, ) val byIsSilent: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming({ it.isSilent }, "has an isSilent value of") val byIsRowDismissed: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming({ it.isRowDismissed }, "has an isRowDismissed value of") val byIsLastMessageFromReply: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming( { it.isLastMessageFromReply }, "has an isLastMessageFromReply value of", ) val byIsPulsing: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming({ it.isPulsing }, "has an isPulsing value of") val byIsPromoted: Correspondence<ActiveNotificationModel, Boolean> = Correspondence.transforming( { it.promotedContent != null }, "has (or doesn't have) a promoted content model", }, /* description = */ "is icon model of", ) val byIconNotifKey: Correspondence<ActiveNotificationIconModel, String> = Correspondence.transforming({ it.notifKey }, "has a notifKey of")
packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt +20 −9 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ 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 @@ -116,7 +117,11 @@ private class ActiveNotificationsStoreBuilder( private fun addBundleEntry(entry: BundleEntry) { val childModels = entry.children.mapNotNull { it.toModel() } builder.addBundle( existingModels.createOrReuseBundle(key = entry.key, children = childModels) existingModels.createOrReuseBundle( key = entry.key, iconResId = entry.bundleRepository.bundleIcon, children = childModels, ) ) } Loading @@ -132,19 +137,21 @@ private class ActiveNotificationsStoreBuilder( builder.setRankingsMap(flatMapToRankingsMap(entries)) } fun flatMapToRankingsMap(entries: List<PipelineEntry>): Map<String, Int> { private fun flatMapToRankingsMap(entries: List<PipelineEntry>): Map<String, Int> { val result = ArrayMap<String, Int>() for (entry in entries) { when (entry) { is BundleEntry -> { // TODO(b/410815667): Handle BundleEntry is BundleEntry -> flatMapToRankingsMap(entry, result) is ListEntry -> flatMapToRankingsMap(entry, result) } is ListEntry -> { flatMapToRankingsMap(entry, result) } return result } private fun flatMapToRankingsMap(entry: BundleEntry, result: ArrayMap<String, Int>) { for (child in entry.children) { flatMapToRankingsMap(child, result) } return result } private fun flatMapToRankingsMap(entry: ListEntry, result: ArrayMap<String, Int>) { Loading Loading @@ -396,17 +403,21 @@ private fun StatusBarNotification.toCallType(): CallType = private fun ActiveNotificationsStore.createOrReuseBundle( key: String, @DrawableRes iconResId: Int, children: List<ActiveNotificationEntryModel>, ): ActiveBundleModel { return bundles[key]?.takeIf { it.isCurrent(key, children) } ?: ActiveBundleModel(key, children) return bundles[key]?.takeIf { it.isCurrent(key, iconResId, children) } ?: ActiveBundleModel(key, iconResId, children) } private fun ActiveBundleModel.isCurrent( key: String, @DrawableRes iconResId: Int, children: List<ActiveNotificationEntryModel>, ): Boolean { return when { key != this.key -> false iconResId != this.iconResId -> false !hasSameInstances(children, this.children) -> false else -> true } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt +91 −22 File changed.Preview size limit exceeded, changes collapsed. Show changes