• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  *
14  */
15 
16 package com.android.systemui.statusbar.notification.icon.domain.interactor
17 
18 import com.android.systemui.dagger.qualifiers.Background
19 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
20 import com.android.systemui.statusbar.data.repository.NotificationListenerSettingsRepository
21 import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository
22 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
23 import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor
24 import com.android.systemui.statusbar.notification.promoted.domain.interactor.AODPromotedNotificationInteractor
25 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
26 import com.android.wm.shell.bubbles.Bubbles
27 import java.util.Optional
28 import javax.inject.Inject
29 import kotlin.coroutines.CoroutineContext
30 import kotlin.jvm.optionals.getOrNull
31 import kotlinx.coroutines.flow.Flow
32 import kotlinx.coroutines.flow.combine
33 import kotlinx.coroutines.flow.flatMapLatest
34 import kotlinx.coroutines.flow.flowOf
35 import kotlinx.coroutines.flow.flowOn
36 
37 /** Domain logic related to notification icons. */
38 class NotificationIconsInteractor
39 @Inject
40 constructor(
41     private val activeNotificationsInteractor: ActiveNotificationsInteractor,
42     private val bubbles: Optional<Bubbles>,
43     private val headsUpNotificationIconInteractor: HeadsUpNotificationIconInteractor,
44     private val aodPromotedNotificationInteractor: AODPromotedNotificationInteractor,
45     private val keyguardViewStateRepository: NotificationsKeyguardViewStateRepository,
46 ) {
47     private val aodPromotedKeyToHide: Flow<String?> =
48         combine(
49             aodPromotedNotificationInteractor.content,
50             aodPromotedNotificationInteractor.isPresent,
51         ) { content, isPresent ->
52             when {
53                 !isPresent -> null
54                 content == null -> null
55                 else -> content.identity.key
56             }
57         }
58 
59     /** Returns a subset of all active notifications based on the supplied filtration parameters. */
60     fun filteredNotifSet(
61         forceShowHeadsUp: Boolean = false,
62         showAmbient: Boolean = true,
63         showLowPriority: Boolean = true,
64         showDismissed: Boolean = true,
65         showRepliedMessages: Boolean = true,
66         showPulsing: Boolean = true,
67         showAodPromoted: Boolean = true,
68     ): Flow<Set<ActiveNotificationModel>> {
69         return combine(
70             activeNotificationsInteractor.topLevelRepresentativeNotifications,
71             headsUpNotificationIconInteractor.isolatedNotification,
72             if (showAodPromoted) flowOf(null) else aodPromotedKeyToHide,
73             keyguardViewStateRepository.areNotificationsFullyHidden,
74         ) { notifications, isolatedNotifKey, aodPromotedKeyToHide, notifsFullyHidden ->
75             notifications
76                 .asSequence()
77                 .filter { model: ActiveNotificationModel ->
78                     shouldShowNotificationIcon(
79                         model = model,
80                         forceShowHeadsUp = forceShowHeadsUp,
81                         showAmbient = showAmbient,
82                         showLowPriority = showLowPriority,
83                         showDismissed = showDismissed,
84                         showRepliedMessages = showRepliedMessages,
85                         showPulsing = showPulsing,
86                         isolatedNotifKey = isolatedNotifKey,
87                         aodPromotedKeyToHide = aodPromotedKeyToHide,
88                         notifsFullyHidden = notifsFullyHidden,
89                     )
90                 }
91                 .toSet()
92         }
93     }
94 
95     private fun shouldShowNotificationIcon(
96         model: ActiveNotificationModel,
97         forceShowHeadsUp: Boolean,
98         showAmbient: Boolean,
99         showLowPriority: Boolean,
100         showDismissed: Boolean,
101         showRepliedMessages: Boolean,
102         showPulsing: Boolean,
103         isolatedNotifKey: String?,
104         aodPromotedKeyToHide: String?,
105         notifsFullyHidden: Boolean,
106     ): Boolean {
107         return when {
108             forceShowHeadsUp && model.key == isolatedNotifKey -> true
109             !showAmbient && model.isAmbient -> false
110             !showLowPriority && model.isSilent -> false
111             !showDismissed && model.isRowDismissed -> false
112             !showRepliedMessages && model.isLastMessageFromReply -> false
113             !showAmbient && model.isSuppressedFromStatusBar -> false
114             !showPulsing && model.isPulsing && !notifsFullyHidden -> false
115             model.key == aodPromotedKeyToHide -> false
116             bubbles.getOrNull()?.isBubbleExpanded(model.key) == true -> false
117             else -> true
118         }
119     }
120 }
121 
122 /** Domain logic related to notification icons shown on the always-on display. */
123 class AlwaysOnDisplayNotificationIconsInteractor
124 @Inject
125 constructor(
126     @Background bgContext: CoroutineContext,
127     deviceEntryInteractor: DeviceEntryInteractor,
128     iconsInteractor: NotificationIconsInteractor,
129 ) {
130     val aodNotifs: Flow<Set<ActiveNotificationModel>> =
131         deviceEntryInteractor.isBypassEnabled
isBypassEnablednull132             .flatMapLatest { isBypassEnabled ->
133                 iconsInteractor.filteredNotifSet(
134                     showAmbient = false,
135                     showDismissed = false,
136                     showRepliedMessages = false,
137                     showPulsing = !isBypassEnabled,
138                     showAodPromoted = false,
139                 )
140             }
141             .flowOn(bgContext)
142 }
143 
144 /** Domain logic related to notification icons shown in the status bar. */
145 class StatusBarNotificationIconsInteractor
146 @Inject
147 constructor(
148     @Background bgContext: CoroutineContext,
149     iconsInteractor: NotificationIconsInteractor,
150     settingsRepository: NotificationListenerSettingsRepository,
151 ) {
152     val statusBarNotifs: Flow<Set<ActiveNotificationModel>> =
153         settingsRepository.showSilentStatusIcons
showSilentIconsnull154             .flatMapLatest { showSilentIcons ->
155                 iconsInteractor.filteredNotifSet(
156                     forceShowHeadsUp = true,
157                     showAmbient = false,
158                     showLowPriority = showSilentIcons,
159                     showDismissed = false,
160                     showRepliedMessages = false,
161                 )
162             }
163             .flowOn(bgContext)
164 }
165