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