1 /*
<lambda>null2  * 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 
17 package com.android.systemui.statusbar.notification.collection.coordinator
18 
19 import com.android.systemui.statusbar.notification.collection.GroupEntry
20 import com.android.systemui.statusbar.notification.collection.ListEntry
21 import com.android.systemui.statusbar.notification.collection.NotifPipeline
22 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
23 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProviderImpl
24 import com.android.systemui.statusbar.policy.KeyguardStateController
25 import javax.inject.Inject
26 
27 /** Decides if a Notification can be dismissed by the user. */
28 @CoordinatorScope
29 class DismissibilityCoordinator
30 @Inject
31 constructor(
32     private val keyguardStateController: KeyguardStateController,
33     private val provider: NotificationDismissibilityProviderImpl
34 ) : Coordinator {
35 
36     override fun attach(pipeline: NotifPipeline) {
37         pipeline.addOnBeforeRenderListListener(::onBeforeRenderListListener)
38     }
39 
40     private fun onBeforeRenderListListener(entries: List<ListEntry>) {
41         val isLocked = !keyguardStateController.isUnlocked
42         val nonDismissableEntryKeys = mutableSetOf<String>()
43         markNonDismissibleEntries(nonDismissableEntryKeys, entries, isLocked)
44         provider.update(nonDismissableEntryKeys)
45     }
46 
47     /**
48      * Visits every entry and its children to mark the dismissible entries.
49      *
50      * @param markedKeys set to store the marked entry keys
51      * @param entries to visit
52      * @param isLocked the locked state of the device
53      * @return true if any of the entries were marked as non-dismissible.
54      */
55     private fun markNonDismissibleEntries(
56         markedKeys: MutableSet<String>,
57         entries: List<ListEntry>,
58         isLocked: Boolean
59     ): Boolean {
60         var anyNonDismissableEntries = false
61 
62         for (entry in entries) {
63             entry.representativeEntry?.let { notifEntry ->
64                 // mark the entry if it is non-dismissible
65                 if (!notifEntry.isDismissableForState(isLocked)) {
66                     markedKeys.add(notifEntry.key)
67                     anyNonDismissableEntries = true
68                 }
69             }
70 
71             if (entry is GroupEntry) {
72                 if (markNonDismissibleEntries(markedKeys, entry.children, isLocked)) {
73                     // if any child is non-dismissible, mark the parent as well
74                     entry.representativeEntry?.let { markedKeys.add(it.key) }
75                     anyNonDismissableEntries = true
76                 }
77             }
78         }
79 
80         return anyNonDismissableEntries
81     }
82 }
83