Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt +49 −8 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ package com.android.systemui.statusbar.notification.data.repository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.notification.data.model.NotifStats import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore.Key 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.systemui.statusbar.notification.shared.ActivePipelineEntryModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow Loading Loading @@ -51,14 +53,16 @@ class ActiveNotificationListRepository @Inject constructor() { /** Represents the notification list, comprised of groups and individual notifications. */ data class ActiveNotificationsStore( /** Notification bundles, stored by key. */ val bundles: Map<String, ActiveBundleModel> = emptyMap(), /** Notification groups, stored by key. */ val groups: Map<String, ActiveNotificationGroupModel> = emptyMap(), /** All individual notifications, including top-level and group children, stored by key. */ val individuals: Map<String, ActiveNotificationModel> = emptyMap(), /** * Ordered top-level list of entries in the notification list (either groups or individual), * represented as [Key]s. The associated [ActiveNotificationEntryModel] can be retrieved by * invoking [get]. * represented as [Key]s. The associated [ActivePipelineEntryModel] can be retrieved by invoking * [get]. */ val renderList: List<Key> = emptyList(), Loading @@ -68,30 +72,42 @@ data class ActiveNotificationsStore( */ val rankingsMap: Map<String, Int> = emptyMap(), ) { operator fun get(key: Key): ActiveNotificationEntryModel? { operator fun get(key: Key): ActivePipelineEntryModel? { return when (key) { is Key.Bundle -> bundles[key.key] is Key.Group -> groups[key.key] is Key.Individual -> individuals[key.key] } } /** Unique key identifying an [ActiveNotificationEntryModel] in the store. */ /** Unique key identifying an [ActivePipelineEntryModel] in the store. */ sealed class Key { data class Individual(val key: String) : Key() data class Group(val key: String) : Key() data class Bundle(val key: String) : Key() } /** Mutable builder for an [ActiveNotificationsStore]. */ class Builder { private val bundles = mutableMapOf<String, ActiveBundleModel>() private val groups = mutableMapOf<String, ActiveNotificationGroupModel>() private val individuals = mutableMapOf<String, ActiveNotificationModel>() private val renderList = mutableListOf<Key>() private var rankingsMap: Map<String, Int> = emptyMap() fun build() = ActiveNotificationsStore(groups, individuals, renderList, rankingsMap) fun build() = ActiveNotificationsStore(bundles, groups, individuals, renderList, rankingsMap) fun addNotifEntry(entry: ActivePipelineEntryModel) { when (entry) { is ActiveBundleModel -> addBundle(entry) is ActiveNotificationEntryModel -> addNotifEntry(entry) } } fun addEntry(entry: ActiveNotificationEntryModel) { fun addNotifEntry(entry: ActiveNotificationEntryModel) { when (entry) { is ActiveNotificationModel -> addIndividualNotif(entry) is ActiveNotificationGroupModel -> addNotifGroup(entry) Loading @@ -100,14 +116,39 @@ data class ActiveNotificationsStore( fun addIndividualNotif(notif: ActiveNotificationModel) { renderList.add(Key.Individual(notif.key)) individuals[notif.key] = notif trackIndividualNotif(notif) } fun addNotifGroup(group: ActiveNotificationGroupModel) { renderList.add(Key.Group(group.key)) trackNotifGroup(group) } fun addBundle(bundle: ActiveBundleModel) { renderList.add(Key.Bundle(bundle.key)) trackBundle(bundle) } private fun trackNotifEntry(entry: ActiveNotificationEntryModel) { when (entry) { is ActiveNotificationGroupModel -> trackNotifGroup(entry) is ActiveNotificationModel -> trackIndividualNotif(entry) } } private fun trackIndividualNotif(notif: ActiveNotificationModel) { individuals[notif.key] = notif } private fun trackNotifGroup(group: ActiveNotificationGroupModel) { groups[group.key] = group individuals[group.summary.key] = group.summary group.children.forEach { individuals[it.key] = it } group.children.forEach { trackIndividualNotif(it) } } private fun trackBundle(bundle: ActiveBundleModel) { bundles[bundle.key] = bundle bundle.children.forEach { child -> trackNotifEntry(child) } } fun setRankingsMap(map: Map<String, Int>) { Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt +30 −15 Original line number Diff line number Diff line Loading @@ -19,9 +19,12 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.statusbar.notification.data.model.NotifStats import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi import com.android.systemui.statusbar.notification.shared.ActiveBundleModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.notification.shared.ActivePipelineEntryModel import com.android.systemui.statusbar.notification.shared.CallType import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher Loading @@ -39,24 +42,14 @@ constructor( @Background private val backgroundDispatcher: CoroutineDispatcher, ) { /** * Top level list of Notifications actively presented to the user in the notification stack, in * order. * List of top-level entries in the notification stack that are backed by a notification. * * This omits bundles and bundled notifications; the bundle is top-level, and it is not backed * by a notification. */ val topLevelRepresentativeNotifications: Flow<List<ActiveNotificationModel>> = repository.activeNotifications .map { store -> store.renderList.map { key -> val entry = store[key] ?: error( "Could not find notification with key $key in active notif store." ) when (entry) { is ActiveNotificationGroupModel -> entry.summary is ActiveNotificationModel -> entry } } } .map { store -> topLevelRepresentativeModels(store) } .flowOn(backgroundDispatcher) /** Loading Loading @@ -172,6 +165,28 @@ constructor( repository.notifStats.value = notifStats } /** * Returns the representative model for each top-level entry in the [store]. By definition, this * will omit bundles, which are always top-level and do not have a representative entry. */ private fun topLevelRepresentativeModels( store: ActiveNotificationsStore ): List<ActiveNotificationModel> = store.renderList.mapNotNull { key -> representativeModelForKey(store, key) } private fun representativeModelForKey( store: ActiveNotificationsStore, key: ActiveNotificationsStore.Key, ): ActiveNotificationModel? { val entry: ActivePipelineEntryModel = store[key] ?: error("Could not find entry with key=$key in active notif store.") return when (entry) { is ActiveNotificationGroupModel -> entry.summary is ActiveNotificationModel -> entry is ActiveBundleModel -> null } } companion object { fun ActiveNotificationModel.isOngoingCallNotification() = this.callType == CallType.Ongoing } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt +71 −26 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import com.android.systemui.statusbar.notification.data.repository.ActiveNotific import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel 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.ActiveNotificationEntryModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel Loading Loading @@ -100,35 +101,31 @@ private class ActiveNotificationsStoreBuilder( */ fun addPipelineEntry(entry: PipelineEntry) { when (entry) { is BundleEntry -> { // TODO(b/410815667): Handle BundleEntry } is ListEntry -> { addListEntry(entry) } is BundleEntry -> addBundleEntry(entry) is ListEntry -> addListEntry(entry) } } private fun addListEntry(entry: ListEntry) { when (entry) { is GroupEntry -> { entry.summary?.let { summary -> val summaryModel = summary.toModel() val childModels = entry.children.map { it.toModel() } builder.addNotifGroup( existingModels.createOrReuse( key = entry.key, summary = summaryModel, children = childModels, ) ) is GroupEntry -> addGroupEntry(entry) is NotificationEntry -> addNotificationEntry(entry) } } is NotificationEntry -> { builder.addIndividualNotif(entry.toModel()) private fun addBundleEntry(entry: BundleEntry) { val childModels = entry.children.mapNotNull { it.toModel() } builder.addBundle( existingModels.createOrReuseBundle(key = entry.key, children = childModels) ) } private fun addGroupEntry(entry: GroupEntry) { entry.toModel()?.let { builder.addNotifGroup(it) } } private fun addNotificationEntry(entry: NotificationEntry) { builder.addIndividualNotif(entry.toModel()) } fun setRankingsMap(entries: List<PipelineEntry>) { Loading Loading @@ -165,6 +162,24 @@ private class ActiveNotificationsStoreBuilder( } } private fun ListEntry.toModel(): ActiveNotificationEntryModel? = when (this) { is GroupEntry -> toModel() is NotificationEntry -> toModel() else -> null } private fun GroupEntry.toModel(): ActiveNotificationGroupModel? = summary?.let { summary -> val summaryModel = summary.toModel() val childModels = children.map { it.toModel() } existingModels.createOrReuseGroup( key = key, summary = summaryModel, children = childModels, ) } private fun NotificationEntry.toModel(): ActiveNotificationModel { val promotedContent = if (PromotedNotificationContentModel.featureFlagEnabled()) { Loading @@ -173,7 +188,7 @@ private class ActiveNotificationsStoreBuilder( null } return existingModels.createOrReuse( return existingModels.createOrReuseNotif( key = key, groupKey = sbn.groupKey, whenTime = sbn.notification.`when`, Loading Loading @@ -202,7 +217,7 @@ private class ActiveNotificationsStoreBuilder( } } private fun ActiveNotificationsStore.createOrReuse( private fun ActiveNotificationsStore.createOrReuseNotif( key: String, groupKey: String?, whenTime: Long, Loading Loading @@ -341,7 +356,7 @@ private fun ActiveNotificationModel.isCurrent( } } private fun ActiveNotificationsStore.createOrReuse( private fun ActiveNotificationsStore.createOrReuseGroup( key: String, summary: ActiveNotificationModel, children: List<ActiveNotificationModel>, Loading Loading @@ -372,3 +387,33 @@ private fun StatusBarNotification.toCallType(): CallType = CALL_TYPE_UNKNOWN -> CallType.Unknown else -> CallType.Unknown } private fun ActiveNotificationsStore.createOrReuseBundle( key: String, children: List<ActiveNotificationEntryModel>, ): ActiveBundleModel { return bundles[key]?.takeIf { it.isCurrent(key, children) } ?: ActiveBundleModel(key, children) } private fun ActiveBundleModel.isCurrent( key: String, children: List<ActiveNotificationEntryModel>, ): Boolean { return when { key != this.key -> false !hasSameInstances(children, this.children) -> false else -> true } } private fun hasSameInstances(list1: List<*>, list2: List<*>): Boolean { if (list1.size != list2.size) { return false } for (i in list1.indices) { if (list1[i] !== list2[i]) { return false } } return true } packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt +12 −1 Original line number Diff line number Diff line Loading @@ -26,9 +26,20 @@ import com.android.systemui.statusbar.notification.stack.PriorityBucket /** * Model for a top-level "entry" in the notification list, either an * [individual notification][ActiveNotificationModel], a [group][ActiveNotificationGroupModel], or a * [bundle][ActiveBundleModel]. */ sealed class ActivePipelineEntryModel /** Model for a bundle of notifications. */ data class ActiveBundleModel(val key: String, val children: List<ActiveNotificationEntryModel>) : ActivePipelineEntryModel() /** * Model for a notification-backed "entry" in the notification list, either an * [individual notification][ActiveNotificationModel], or a [group][ActiveNotificationGroupModel]. */ sealed class ActiveNotificationEntryModel sealed class ActiveNotificationEntryModel : ActivePipelineEntryModel() /** * Model for an individual notification in the notification list. These can appear as either an Loading packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepositoryExt.kt +1 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ fun ActiveNotificationListRepository.setActiveNotifs(count: Int) { val rankingsMap = mutableMapOf<String, Int>() repeat(count) { i -> val key = "$i" addEntry(activeNotificationModel(key = key)) addNotifEntry(activeNotificationModel(key = key)) rankingsMap[key] = i } Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt +49 −8 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ package com.android.systemui.statusbar.notification.data.repository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.notification.data.model.NotifStats import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore.Key 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.systemui.statusbar.notification.shared.ActivePipelineEntryModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow Loading Loading @@ -51,14 +53,16 @@ class ActiveNotificationListRepository @Inject constructor() { /** Represents the notification list, comprised of groups and individual notifications. */ data class ActiveNotificationsStore( /** Notification bundles, stored by key. */ val bundles: Map<String, ActiveBundleModel> = emptyMap(), /** Notification groups, stored by key. */ val groups: Map<String, ActiveNotificationGroupModel> = emptyMap(), /** All individual notifications, including top-level and group children, stored by key. */ val individuals: Map<String, ActiveNotificationModel> = emptyMap(), /** * Ordered top-level list of entries in the notification list (either groups or individual), * represented as [Key]s. The associated [ActiveNotificationEntryModel] can be retrieved by * invoking [get]. * represented as [Key]s. The associated [ActivePipelineEntryModel] can be retrieved by invoking * [get]. */ val renderList: List<Key> = emptyList(), Loading @@ -68,30 +72,42 @@ data class ActiveNotificationsStore( */ val rankingsMap: Map<String, Int> = emptyMap(), ) { operator fun get(key: Key): ActiveNotificationEntryModel? { operator fun get(key: Key): ActivePipelineEntryModel? { return when (key) { is Key.Bundle -> bundles[key.key] is Key.Group -> groups[key.key] is Key.Individual -> individuals[key.key] } } /** Unique key identifying an [ActiveNotificationEntryModel] in the store. */ /** Unique key identifying an [ActivePipelineEntryModel] in the store. */ sealed class Key { data class Individual(val key: String) : Key() data class Group(val key: String) : Key() data class Bundle(val key: String) : Key() } /** Mutable builder for an [ActiveNotificationsStore]. */ class Builder { private val bundles = mutableMapOf<String, ActiveBundleModel>() private val groups = mutableMapOf<String, ActiveNotificationGroupModel>() private val individuals = mutableMapOf<String, ActiveNotificationModel>() private val renderList = mutableListOf<Key>() private var rankingsMap: Map<String, Int> = emptyMap() fun build() = ActiveNotificationsStore(groups, individuals, renderList, rankingsMap) fun build() = ActiveNotificationsStore(bundles, groups, individuals, renderList, rankingsMap) fun addNotifEntry(entry: ActivePipelineEntryModel) { when (entry) { is ActiveBundleModel -> addBundle(entry) is ActiveNotificationEntryModel -> addNotifEntry(entry) } } fun addEntry(entry: ActiveNotificationEntryModel) { fun addNotifEntry(entry: ActiveNotificationEntryModel) { when (entry) { is ActiveNotificationModel -> addIndividualNotif(entry) is ActiveNotificationGroupModel -> addNotifGroup(entry) Loading @@ -100,14 +116,39 @@ data class ActiveNotificationsStore( fun addIndividualNotif(notif: ActiveNotificationModel) { renderList.add(Key.Individual(notif.key)) individuals[notif.key] = notif trackIndividualNotif(notif) } fun addNotifGroup(group: ActiveNotificationGroupModel) { renderList.add(Key.Group(group.key)) trackNotifGroup(group) } fun addBundle(bundle: ActiveBundleModel) { renderList.add(Key.Bundle(bundle.key)) trackBundle(bundle) } private fun trackNotifEntry(entry: ActiveNotificationEntryModel) { when (entry) { is ActiveNotificationGroupModel -> trackNotifGroup(entry) is ActiveNotificationModel -> trackIndividualNotif(entry) } } private fun trackIndividualNotif(notif: ActiveNotificationModel) { individuals[notif.key] = notif } private fun trackNotifGroup(group: ActiveNotificationGroupModel) { groups[group.key] = group individuals[group.summary.key] = group.summary group.children.forEach { individuals[it.key] = it } group.children.forEach { trackIndividualNotif(it) } } private fun trackBundle(bundle: ActiveBundleModel) { bundles[bundle.key] = bundle bundle.children.forEach { child -> trackNotifEntry(child) } } fun setRankingsMap(map: Map<String, Int>) { Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt +30 −15 Original line number Diff line number Diff line Loading @@ -19,9 +19,12 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.statusbar.notification.data.model.NotifStats import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi import com.android.systemui.statusbar.notification.shared.ActiveBundleModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.notification.shared.ActivePipelineEntryModel import com.android.systemui.statusbar.notification.shared.CallType import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher Loading @@ -39,24 +42,14 @@ constructor( @Background private val backgroundDispatcher: CoroutineDispatcher, ) { /** * Top level list of Notifications actively presented to the user in the notification stack, in * order. * List of top-level entries in the notification stack that are backed by a notification. * * This omits bundles and bundled notifications; the bundle is top-level, and it is not backed * by a notification. */ val topLevelRepresentativeNotifications: Flow<List<ActiveNotificationModel>> = repository.activeNotifications .map { store -> store.renderList.map { key -> val entry = store[key] ?: error( "Could not find notification with key $key in active notif store." ) when (entry) { is ActiveNotificationGroupModel -> entry.summary is ActiveNotificationModel -> entry } } } .map { store -> topLevelRepresentativeModels(store) } .flowOn(backgroundDispatcher) /** Loading Loading @@ -172,6 +165,28 @@ constructor( repository.notifStats.value = notifStats } /** * Returns the representative model for each top-level entry in the [store]. By definition, this * will omit bundles, which are always top-level and do not have a representative entry. */ private fun topLevelRepresentativeModels( store: ActiveNotificationsStore ): List<ActiveNotificationModel> = store.renderList.mapNotNull { key -> representativeModelForKey(store, key) } private fun representativeModelForKey( store: ActiveNotificationsStore, key: ActiveNotificationsStore.Key, ): ActiveNotificationModel? { val entry: ActivePipelineEntryModel = store[key] ?: error("Could not find entry with key=$key in active notif store.") return when (entry) { is ActiveNotificationGroupModel -> entry.summary is ActiveNotificationModel -> entry is ActiveBundleModel -> null } } companion object { fun ActiveNotificationModel.isOngoingCallNotification() = this.callType == CallType.Ongoing } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt +71 −26 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import com.android.systemui.statusbar.notification.data.repository.ActiveNotific import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel 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.ActiveNotificationEntryModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel Loading Loading @@ -100,35 +101,31 @@ private class ActiveNotificationsStoreBuilder( */ fun addPipelineEntry(entry: PipelineEntry) { when (entry) { is BundleEntry -> { // TODO(b/410815667): Handle BundleEntry } is ListEntry -> { addListEntry(entry) } is BundleEntry -> addBundleEntry(entry) is ListEntry -> addListEntry(entry) } } private fun addListEntry(entry: ListEntry) { when (entry) { is GroupEntry -> { entry.summary?.let { summary -> val summaryModel = summary.toModel() val childModels = entry.children.map { it.toModel() } builder.addNotifGroup( existingModels.createOrReuse( key = entry.key, summary = summaryModel, children = childModels, ) ) is GroupEntry -> addGroupEntry(entry) is NotificationEntry -> addNotificationEntry(entry) } } is NotificationEntry -> { builder.addIndividualNotif(entry.toModel()) private fun addBundleEntry(entry: BundleEntry) { val childModels = entry.children.mapNotNull { it.toModel() } builder.addBundle( existingModels.createOrReuseBundle(key = entry.key, children = childModels) ) } private fun addGroupEntry(entry: GroupEntry) { entry.toModel()?.let { builder.addNotifGroup(it) } } private fun addNotificationEntry(entry: NotificationEntry) { builder.addIndividualNotif(entry.toModel()) } fun setRankingsMap(entries: List<PipelineEntry>) { Loading Loading @@ -165,6 +162,24 @@ private class ActiveNotificationsStoreBuilder( } } private fun ListEntry.toModel(): ActiveNotificationEntryModel? = when (this) { is GroupEntry -> toModel() is NotificationEntry -> toModel() else -> null } private fun GroupEntry.toModel(): ActiveNotificationGroupModel? = summary?.let { summary -> val summaryModel = summary.toModel() val childModels = children.map { it.toModel() } existingModels.createOrReuseGroup( key = key, summary = summaryModel, children = childModels, ) } private fun NotificationEntry.toModel(): ActiveNotificationModel { val promotedContent = if (PromotedNotificationContentModel.featureFlagEnabled()) { Loading @@ -173,7 +188,7 @@ private class ActiveNotificationsStoreBuilder( null } return existingModels.createOrReuse( return existingModels.createOrReuseNotif( key = key, groupKey = sbn.groupKey, whenTime = sbn.notification.`when`, Loading Loading @@ -202,7 +217,7 @@ private class ActiveNotificationsStoreBuilder( } } private fun ActiveNotificationsStore.createOrReuse( private fun ActiveNotificationsStore.createOrReuseNotif( key: String, groupKey: String?, whenTime: Long, Loading Loading @@ -341,7 +356,7 @@ private fun ActiveNotificationModel.isCurrent( } } private fun ActiveNotificationsStore.createOrReuse( private fun ActiveNotificationsStore.createOrReuseGroup( key: String, summary: ActiveNotificationModel, children: List<ActiveNotificationModel>, Loading Loading @@ -372,3 +387,33 @@ private fun StatusBarNotification.toCallType(): CallType = CALL_TYPE_UNKNOWN -> CallType.Unknown else -> CallType.Unknown } private fun ActiveNotificationsStore.createOrReuseBundle( key: String, children: List<ActiveNotificationEntryModel>, ): ActiveBundleModel { return bundles[key]?.takeIf { it.isCurrent(key, children) } ?: ActiveBundleModel(key, children) } private fun ActiveBundleModel.isCurrent( key: String, children: List<ActiveNotificationEntryModel>, ): Boolean { return when { key != this.key -> false !hasSameInstances(children, this.children) -> false else -> true } } private fun hasSameInstances(list1: List<*>, list2: List<*>): Boolean { if (list1.size != list2.size) { return false } for (i in list1.indices) { if (list1[i] !== list2[i]) { return false } } return true }
packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt +12 −1 Original line number Diff line number Diff line Loading @@ -26,9 +26,20 @@ import com.android.systemui.statusbar.notification.stack.PriorityBucket /** * Model for a top-level "entry" in the notification list, either an * [individual notification][ActiveNotificationModel], a [group][ActiveNotificationGroupModel], or a * [bundle][ActiveBundleModel]. */ sealed class ActivePipelineEntryModel /** Model for a bundle of notifications. */ data class ActiveBundleModel(val key: String, val children: List<ActiveNotificationEntryModel>) : ActivePipelineEntryModel() /** * Model for a notification-backed "entry" in the notification list, either an * [individual notification][ActiveNotificationModel], or a [group][ActiveNotificationGroupModel]. */ sealed class ActiveNotificationEntryModel sealed class ActiveNotificationEntryModel : ActivePipelineEntryModel() /** * Model for an individual notification in the notification list. These can appear as either an Loading
packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepositoryExt.kt +1 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ fun ActiveNotificationListRepository.setActiveNotifs(count: Int) { val rankingsMap = mutableMapOf<String, Int>() repeat(count) { i -> val key = "$i" addEntry(activeNotificationModel(key = key)) addNotifEntry(activeNotificationModel(key = key)) rankingsMap[key] = i } Loading