1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.systemui.statusbar.notification.data.repository 17 18 import com.android.systemui.dagger.SysUISingleton 19 import com.android.systemui.statusbar.notification.collection.render.NotifStats 20 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore.Key 21 import com.android.systemui.statusbar.notification.shared.ActiveNotificationEntryModel 22 import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel 23 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel 24 import javax.inject.Inject 25 import kotlinx.coroutines.flow.MutableStateFlow 26 27 /** 28 * Repository of "active" notifications in the notification list. 29 * 30 * This repository serves as the boundary between the 31 * [com.android.systemui.statusbar.notification.collection.NotifPipeline] and the modern 32 * notifications presentation codebase. 33 */ 34 @SysUISingleton 35 class ActiveNotificationListRepository @Inject constructor() { 36 /** Notifications actively presented to the user in the notification list. */ 37 val activeNotifications = MutableStateFlow(ActiveNotificationsStore()) 38 39 /** Are any already-seen notifications currently filtered out of the active list? */ 40 val hasFilteredOutSeenNotifications = MutableStateFlow(false) 41 42 /** Stats about the list of notifications attached to the shade */ 43 val notifStats = MutableStateFlow(NotifStats.empty) 44 45 /** The key of the top ongoing notification */ 46 val topOngoingNotificationKey = MutableStateFlow<String?>(null) 47 48 /** The key of the top unseen notification */ 49 val topUnseenNotificationKey = MutableStateFlow<String?>(null) 50 } 51 52 /** Represents the notification list, comprised of groups and individual notifications. */ 53 data class ActiveNotificationsStore( 54 /** Notification groups, stored by key. */ 55 val groups: Map<String, ActiveNotificationGroupModel> = emptyMap(), 56 /** All individual notifications, including top-level and group children, stored by key. */ 57 val individuals: Map<String, ActiveNotificationModel> = emptyMap(), 58 /** 59 * Ordered top-level list of entries in the notification list (either groups or individual), 60 * represented as [Key]s. The associated [ActiveNotificationEntryModel] can be retrieved by 61 * invoking [get]. 62 */ 63 val renderList: List<Key> = emptyList(), 64 65 /** 66 * Map of notification key to rank, where rank is the 0-based index of the notification on the 67 * system server, meaning that in the unfiltered flattened list of notification entries. 68 */ 69 val rankingsMap: Map<String, Int> = emptyMap() 70 ) { getnull71 operator fun get(key: Key): ActiveNotificationEntryModel? { 72 return when (key) { 73 is Key.Group -> groups[key.key] 74 is Key.Individual -> individuals[key.key] 75 } 76 } 77 78 /** Unique key identifying an [ActiveNotificationEntryModel] in the store. */ 79 sealed class Key { 80 data class Individual(val key: String) : Key() 81 82 data class Group(val key: String) : Key() 83 } 84 85 /** Mutable builder for an [ActiveNotificationsStore]. */ 86 class Builder { 87 private val groups = mutableMapOf<String, ActiveNotificationGroupModel>() 88 private val individuals = mutableMapOf<String, ActiveNotificationModel>() 89 private val renderList = mutableListOf<Key>() 90 private var rankingsMap: Map<String, Int> = emptyMap() 91 buildnull92 fun build() = ActiveNotificationsStore(groups, individuals, renderList, rankingsMap) 93 94 fun addEntry(entry: ActiveNotificationEntryModel) { 95 when (entry) { 96 is ActiveNotificationModel -> addIndividualNotif(entry) 97 is ActiveNotificationGroupModel -> addNotifGroup(entry) 98 } 99 } 100 addIndividualNotifnull101 fun addIndividualNotif(notif: ActiveNotificationModel) { 102 renderList.add(Key.Individual(notif.key)) 103 individuals[notif.key] = notif 104 } 105 addNotifGroupnull106 fun addNotifGroup(group: ActiveNotificationGroupModel) { 107 renderList.add(Key.Group(group.key)) 108 groups[group.key] = group 109 individuals[group.summary.key] = group.summary 110 group.children.forEach { individuals[it.key] = it } 111 } 112 setRankingsMapnull113 fun setRankingsMap(map: Map<String, Int>) { 114 rankingsMap = map.toMap() 115 } 116 } 117 } 118