• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.systemui.statusbar.notification.interruption
18 
19 import android.app.NotificationManager.IMPORTANCE_HIGH
20 import android.os.PowerManager
21 import com.android.internal.logging.UiEventLogger.UiEventEnum
22 import com.android.systemui.plugins.statusbar.StatusBarStateController
23 import com.android.systemui.statusbar.StatusBarState.KEYGUARD
24 import com.android.systemui.statusbar.notification.collection.NotificationEntry
25 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_DEVICE_DREAMING
26 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_DEVICE_NOT_INTERACTIVE
27 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_DEVICE_NOT_PROVISIONED
28 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_KEYGUARD_OCCLUDED
29 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_KEYGUARD_SHOWING
30 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_LOCKED_SHADE
31 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_USER_SETUP_INCOMPLETE
32 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_EXPECTED_TO_HUN
33 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_NOT_IMPORTANT_ENOUGH
34 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_NO_FULL_SCREEN_INTENT
35 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_NO_HUN_OR_KEYGUARD
36 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_PACKAGE_SUSPENDED
37 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SHOW_STICKY_HUN
38 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SUPPRESSED_BY_DND
39 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SUPPRESSED_ONLY_BY_DND
40 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA
41 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR
42 import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SUPPRESSIVE_SILENT_NOTIFICATION
43 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD
44 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA
45 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR
46 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionSuppressor.EventLogData
47 import com.android.systemui.statusbar.policy.DeviceProvisionedController
48 import com.android.systemui.statusbar.policy.KeyguardStateController
49 
50 class FullScreenIntentDecisionProvider(
51     private val deviceProvisionedController: DeviceProvisionedController,
52     private val keyguardStateController: KeyguardStateController,
53     private val powerManager: PowerManager,
54     private val statusBarStateController: StatusBarStateController
55 ) {
56     interface Decision {
57         val shouldFsi: Boolean
58         val wouldFsiWithoutDnd: Boolean
59         val logReason: String
60         val shouldLog: Boolean
61         val isWarning: Boolean
62         val uiEventId: UiEventEnum?
63         val eventLogData: EventLogData?
64     }
65 
66     private enum class DecisionImpl(
67         override val shouldFsi: Boolean,
68         override val logReason: String,
69         override val wouldFsiWithoutDnd: Boolean = shouldFsi,
70         val supersedesDnd: Boolean = false,
71         override val shouldLog: Boolean = true,
72         override val isWarning: Boolean = false,
73         override val uiEventId: UiEventEnum? = null,
74         override val eventLogData: EventLogData? = null
75     ) : Decision {
76         NO_FSI_NO_FULL_SCREEN_INTENT(
77             false,
78             "no full-screen intent",
79             supersedesDnd = true,
80             shouldLog = false
81         ),
82         NO_FSI_SHOW_STICKY_HUN(false, "full-screen intents are disabled", supersedesDnd = true),
83         NO_FSI_NOT_IMPORTANT_ENOUGH(false, "not important enough"),
84         NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(
85             false,
86             "suppressive group alert behavior",
87             isWarning = true,
88             uiEventId = FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR,
89             eventLogData = EventLogData("231322873", "groupAlertBehavior")
90         ),
91         NO_FSI_SUPPRESSIVE_BUBBLE_METADATA(
92             false,
93             "suppressive bubble metadata",
94             isWarning = true,
95             uiEventId = FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA,
96             eventLogData = EventLogData("274759612", "bubbleMetadata")
97         ),
98         NO_FSI_SUPPRESSIVE_SILENT_NOTIFICATION(false, "suppressive setSilent notification"),
99         NO_FSI_PACKAGE_SUSPENDED(false, "package suspended"),
100         FSI_DEVICE_NOT_INTERACTIVE(true, "device is not interactive"),
101         FSI_DEVICE_DREAMING(true, "device is dreaming"),
102         FSI_KEYGUARD_SHOWING(true, "keyguard is showing"),
103         NO_FSI_EXPECTED_TO_HUN(false, "expected to heads-up instead"),
104         FSI_KEYGUARD_OCCLUDED(true, "keyguard is occluded"),
105         FSI_LOCKED_SHADE(true, "locked shade"),
106         FSI_DEVICE_NOT_PROVISIONED(true, "device not provisioned"),
107         FSI_USER_SETUP_INCOMPLETE(true, "user setup incomplete"),
108         NO_FSI_NO_HUN_OR_KEYGUARD(
109             false,
110             "no HUN or keyguard",
111             isWarning = true,
112             uiEventId = FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD,
113             eventLogData = EventLogData("231322873", "no hun or keyguard")
114         ),
115         NO_FSI_SUPPRESSED_BY_DND(false, "suppressed by DND", wouldFsiWithoutDnd = false),
116         NO_FSI_SUPPRESSED_ONLY_BY_DND(false, "suppressed only by DND", wouldFsiWithoutDnd = true)
117     }
118 
makeFullScreenIntentDecisionnull119     fun makeFullScreenIntentDecision(entry: NotificationEntry, couldHeadsUp: Boolean): Decision {
120         val reasonWithoutDnd = makeDecisionWithoutDnd(entry, couldHeadsUp)
121 
122         val suppressedWithoutDnd = !reasonWithoutDnd.shouldFsi
123         val suppressedByDnd = entry.shouldSuppressFullScreenIntent()
124 
125         val reasonWithDnd =
126             when {
127                 reasonWithoutDnd.supersedesDnd -> reasonWithoutDnd
128                 suppressedByDnd && !suppressedWithoutDnd -> NO_FSI_SUPPRESSED_ONLY_BY_DND
129                 suppressedByDnd -> NO_FSI_SUPPRESSED_BY_DND
130                 else -> reasonWithoutDnd
131             }
132 
133         return reasonWithDnd
134     }
135 
makeDecisionWithoutDndnull136     private fun makeDecisionWithoutDnd(
137         entry: NotificationEntry,
138         couldHeadsUp: Boolean
139     ): DecisionImpl {
140         val sbn = entry.sbn
141         val notification = sbn.notification!!
142 
143         if (notification.fullScreenIntent == null) {
144             return if (entry.isStickyAndNotDemoted) {
145                 NO_FSI_SHOW_STICKY_HUN
146             } else {
147                 NO_FSI_NO_FULL_SCREEN_INTENT
148             }
149         }
150 
151         if (entry.importance < IMPORTANCE_HIGH) {
152             return NO_FSI_NOT_IMPORTANT_ENOUGH
153         }
154 
155         if (sbn.isGroup && notification.suppressAlertingDueToGrouping()) {
156             return NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR
157         }
158 
159         if (android.service.notification.Flags.notificationSilentFlag()) {
160             if (sbn.notification.isSilent) {
161                 return NO_FSI_SUPPRESSIVE_SILENT_NOTIFICATION
162             }
163         }
164 
165         val bubbleMetadata = notification.bubbleMetadata
166         if (bubbleMetadata != null && bubbleMetadata.isNotificationSuppressed) {
167             return NO_FSI_SUPPRESSIVE_BUBBLE_METADATA
168         }
169 
170         if (entry.ranking.isSuspended) {
171             return NO_FSI_PACKAGE_SUSPENDED
172         }
173 
174         if (!powerManager.isInteractive) {
175             return FSI_DEVICE_NOT_INTERACTIVE
176         }
177 
178         if (statusBarStateController.isDreaming) {
179             return FSI_DEVICE_DREAMING
180         }
181 
182         if (statusBarStateController.state == KEYGUARD) {
183             return FSI_KEYGUARD_SHOWING
184         }
185 
186         if (couldHeadsUp) {
187             return NO_FSI_EXPECTED_TO_HUN
188         }
189 
190         if (keyguardStateController.isShowing) {
191             return if (keyguardStateController.isOccluded) {
192                 FSI_KEYGUARD_OCCLUDED
193             } else {
194                 FSI_LOCKED_SHADE
195             }
196         }
197 
198         if (!deviceProvisionedController.isDeviceProvisioned) {
199             return FSI_DEVICE_NOT_PROVISIONED
200         }
201 
202         if (!deviceProvisionedController.isCurrentUserSetup) {
203             return FSI_USER_SETUP_INCOMPLETE
204         }
205 
206         return NO_FSI_NO_HUN_OR_KEYGUARD
207     }
208 }
209