1 /*
2  * Copyright (C) 2021 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 
17 package com.android.systemui.statusbar.notification.collection.coordinator
18 
19 import com.android.systemui.statusbar.notification.collection.ListEntry
20 import com.android.systemui.statusbar.notification.collection.NotifPipeline
21 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
22 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl
23 import com.android.systemui.statusbar.notification.collection.render.NotifStackController
24 import com.android.systemui.statusbar.notification.collection.render.NotifStats
25 import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
26 import com.android.systemui.statusbar.phone.NotificationIconAreaController
27 import com.android.systemui.util.traceSection
28 import javax.inject.Inject
29 
30 /**
31  * A small coordinator which updates the notif stack (the view layer which holds notifications)
32  * with high-level data after the stack is populated with the final entries.
33  */
34 @CoordinatorScope
35 class StackCoordinator @Inject internal constructor(
36     private val groupExpansionManagerImpl: GroupExpansionManagerImpl,
37     private val notificationIconAreaController: NotificationIconAreaController
38 ) : Coordinator {
39 
40     override fun attach(pipeline: NotifPipeline) {
41         pipeline.addOnAfterRenderListListener(::onAfterRenderList)
42         // TODO(b/282865576): This has an issue where it makes changes to some groups without
43         // notifying listeners. To be fixed in QPR, but for now let's comment it out to avoid the
44         // group expansion bug.
45         // groupExpansionManagerImpl.attach(pipeline)
46     }
47 
48     fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
49         traceSection("StackCoordinator.onAfterRenderList") {
50             controller.setNotifStats(calculateNotifStats(entries))
51             notificationIconAreaController.updateNotificationIcons(entries)
52         }
53 
54     private fun calculateNotifStats(entries: List<ListEntry>): NotifStats {
55         var hasNonClearableAlertingNotifs = false
56         var hasClearableAlertingNotifs = false
57         var hasNonClearableSilentNotifs = false
58         var hasClearableSilentNotifs = false
59         entries.forEach {
60             val section = checkNotNull(it.section) { "Null section for ${it.key}" }
61             val entry = checkNotNull(it.representativeEntry) { "Null notif entry for ${it.key}" }
62             val isSilent = section.bucket == BUCKET_SILENT
63             // NOTE: NotificationEntry.isClearable will internally check group children to ensure
64             //  the group itself definitively clearable.
65             val isClearable = entry.isClearable
66             when {
67                 isSilent && isClearable -> hasClearableSilentNotifs = true
68                 isSilent && !isClearable -> hasNonClearableSilentNotifs = true
69                 !isSilent && isClearable -> hasClearableAlertingNotifs = true
70                 !isSilent && !isClearable -> hasNonClearableAlertingNotifs = true
71             }
72         }
73         return NotifStats(
74             numActiveNotifs = entries.size,
75             hasNonClearableAlertingNotifs = hasNonClearableAlertingNotifs,
76             hasClearableAlertingNotifs = hasClearableAlertingNotifs,
77             hasNonClearableSilentNotifs = hasNonClearableSilentNotifs,
78             hasClearableSilentNotifs = hasClearableSilentNotifs
79         )
80     }
81 }