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 com.android.internal.annotations.VisibleForTesting
20 import com.android.systemui.CoreStartable
21 import com.android.systemui.statusbar.notification.collection.NotificationEntry
22 
23 /**
24  * Decides whether a notification should visually interrupt the user in various ways.
25  *
26  * These include displaying the notification as heads-up (peeking while the device is awake or
27  * pulsing while the device is dozing), displaying the notification as a bubble, and launching a
28  * full-screen intent for the notification.
29  */
30 interface VisualInterruptionDecisionProvider : CoreStartable {
31     /**
32      * Represents the decision to visually interrupt or not.
33      *
34      * Used for heads-up and bubble decisions; subclassed by [FullScreenIntentDecision] for
35      * full-screen intent decisions.
36      *
37      * @property[shouldInterrupt] whether a visual interruption should be triggered
38      * @property[logReason] a log-friendly string explaining the reason for the decision; should be
39      *   used *only* for logging, not decision-making
40      */
41     interface Decision {
42         val shouldInterrupt: Boolean
43         val logReason: String
44     }
45 
46     /**
47      * Represents the decision to launch a full-screen intent for a notification or not.
48      *
49      * @property[wouldInterruptWithoutDnd] whether a full-screen intent should not be launched only
50      *   because Do Not Disturb has suppressed it
51      */
52     interface FullScreenIntentDecision : Decision {
53         val wouldInterruptWithoutDnd: Boolean
54     }
55 
56     /** Initializes the provider. */
startnull57     override fun start() {}
58 
59     /**
60      * Adds a [NotificationInterruptSuppressor] that can suppress visual interruptions.
61      *
62      * This method may be called before [start] has been called.
63      *
64      * This class may call suppressors, conditions, and filters in any order.
65      *
66      * @param[suppressor] the suppressor to add
67      */
addLegacySuppressornull68     fun addLegacySuppressor(suppressor: NotificationInterruptSuppressor)
69 
70     /**
71      * Removes a previously-added suppressor.
72      *
73      * This method may be called before [start] has been called.
74      *
75      * @param[suppressor] the suppressor to remove
76      */
77     @VisibleForTesting fun removeLegacySuppressor(suppressor: NotificationInterruptSuppressor)
78 
79     /**
80      * Adds a [VisualInterruptionCondition] that can suppress visual interruptions without examining
81      * individual notifications.
82      *
83      * This method may be called before [start] has been called.
84      *
85      * This class may call suppressors, conditions, and filters in any order.
86      *
87      * @param[condition] the condition to add
88      */
89     fun addCondition(condition: VisualInterruptionCondition)
90 
91     /**
92      * Removes a previously-added condition.
93      *
94      * This method may be called before [start] has been called.
95      *
96      * @param[condition] the condition to remove
97      */
98     @VisibleForTesting fun removeCondition(condition: VisualInterruptionCondition)
99 
100     /**
101      * Adds a [VisualInterruptionFilter] that can suppress visual interruptions based on individual
102      * notifications.
103      *
104      * This method may be called before [start] has been called.
105      *
106      * This class may call suppressors, conditions, and filters in any order.
107      *
108      * @param[filter] the filter to add
109      */
110     fun addFilter(filter: VisualInterruptionFilter)
111 
112     /**
113      * Removes a previously-added filter.
114      *
115      * This method may be called before [start] has been called.
116      *
117      * @param[filter] the filter to remove
118      */
119     @VisibleForTesting fun removeFilter(filter: VisualInterruptionFilter)
120 
121     /**
122      * Decides whether a [notification][entry] should display as heads-up or not, but does not log
123      * that decision.
124      *
125      * [start] must be called before this method can be called.
126      *
127      * @param[entry] the notification that this decision is about
128      * @return the decision to display that notification as heads-up or not
129      */
130     fun makeUnloggedHeadsUpDecision(entry: NotificationEntry): Decision
131 
132     /**
133      * Decides whether a [notification][entry] should display as heads-up or not, and logs that
134      * decision.
135      *
136      * If the device is awake, the decision will consider whether the notification should "peek"
137      * (slide in from the top of the screen over the current activity).
138      *
139      * If the device is dozing, the decision will consider whether the notification should "pulse"
140      * (wake the screen up and display the ambient view of the notification).
141      *
142      * [start] must be called before this method can be called.
143      *
144      * @see[makeUnloggedHeadsUpDecision]
145      *
146      * @param[entry] the notification that this decision is about
147      * @return the decision to display that notification as heads-up or not
148      */
149     fun makeAndLogHeadsUpDecision(entry: NotificationEntry): Decision
150 
151     /**
152      * Decides whether a [notification][entry] should launch a full-screen intent or not, but does
153      * not log that decision.
154      *
155      * The returned decision can be logged by passing it to [logFullScreenIntentDecision].
156      *
157      * [start] must be called before this method can be called.
158      *
159      * @see[makeAndLogHeadsUpDecision]
160      *
161      * @param[entry] the notification that this decision is about
162      * @return the decision to launch a full-screen intent for that notification or not
163      */
164     fun makeUnloggedFullScreenIntentDecision(entry: NotificationEntry): FullScreenIntentDecision
165 
166     /**
167      * Logs a previous [decision] to launch a full-screen intent or not.
168      *
169      * [start] must be called before this method can be called.
170      *
171      * @param[decision] the decision to log
172      */
173     fun logFullScreenIntentDecision(decision: FullScreenIntentDecision)
174 
175     /**
176      * Decides whether a [notification][entry] should display as a bubble or not.
177      *
178      * [start] must be called before this method can be called.
179      *
180      * @param[entry] the notification that this decision is about
181      * @return the decision to display that notification as a bubble or not
182      */
183     fun makeAndLogBubbleDecision(entry: NotificationEntry): Decision
184 }
185