1 /*
2  * Copyright (C) 2020 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 androidx.annotation.NonNull;
20 
21 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
22 
23 /**
24  * Provides bubble-up and heads-up state for notification entries.
25  *
26  * When a notification is heads-up when dozing, this is also called "pulsing."
27  */
28 public interface NotificationInterruptStateProvider {
29     /**
30      * Enum representing a decision of whether to show a full screen intent. While many of the
31      * relevant properties could overlap, the decision represents the deciding factor for whether
32      * the full screen intent should or shouldn't launch.
33      */
34     enum FullScreenIntentDecision {
35         /**
36          * Full screen intents are disabled.
37          */
38         NO_FSI_SHOW_STICKY_HUN(false),
39         /**
40          * No full screen intent included, so there is nothing to show.
41          */
42         NO_FULL_SCREEN_INTENT(false),
43         /**
44          * Suppressed by DND settings.
45          */
46         NO_FSI_SUPPRESSED_BY_DND(false),
47         /**
48          * Full screen intent was suppressed *only* by DND, and if not for DND would have shown. We
49          * track this separately in order to allow the intent to be shown if the DND decision
50          * changes.
51          */
52         NO_FSI_SUPPRESSED_ONLY_BY_DND(false),
53         /**
54          * Notification importance not high enough to show FSI.
55          */
56         NO_FSI_NOT_IMPORTANT_ENOUGH(false),
57         /**
58          * Notification should not FSI due to having suppressive GroupAlertBehavior. This blocks a
59          * potentially malicious use of flags that previously allowed apps to escalate a HUN to an
60          * FSI even while the device was unlocked.
61          */
62         NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(false),
63         /**
64          * Notification should not FSI due to having suppressive BubbleMetadata. This blocks a
65          * potentially malicious use of flags that previously allowed apps to escalate a HUN to an
66          * FSI even while the device was unlocked.
67          */
68         NO_FSI_SUPPRESSIVE_BUBBLE_METADATA(false),
69         /**
70          * Device screen is off, so the FSI should launch.
71          */
72         FSI_DEVICE_NOT_INTERACTIVE(true),
73         /**
74          * Device is currently dreaming, so FSI should launch.
75          */
76         FSI_DEVICE_IS_DREAMING(true),
77         /**
78          * Keyguard is showing, so FSI should launch.
79          */
80         FSI_KEYGUARD_SHOWING(true),
81         /**
82          * The notification is expected to show heads-up, so FSI is not needed.
83          */
84         NO_FSI_EXPECTED_TO_HUN(false),
85         /**
86          * The notification is not expected to HUN while the keyguard is occluded, so show FSI.
87          */
88         FSI_KEYGUARD_OCCLUDED(true),
89         /**
90          * The notification is not expected to HUN when the keyguard is showing but not occluded,
91          * which likely means that the shade is showing over the lockscreen; show FSI in this case.
92          */
93         FSI_LOCKED_SHADE(true),
94         /**
95          * FSI requires keyguard to be showing, but there is no keyguard. This is a (potentially
96          * malicious) warning state where we suppress the FSI because the device is in use knowing
97          * that the HUN will probably not display.
98          */
99         NO_FSI_NO_HUN_OR_KEYGUARD(false),
100         /**
101          * The notification is coming from a suspended packages, so FSI is suppressed.
102          */
103         NO_FSI_SUSPENDED(false),
104         /**
105          * The device is not provisioned, launch FSI.
106          */
107         FSI_NOT_PROVISIONED(true),
108         /**
109          * The current user has not completed setup, launch FSI.
110          */
111         FSI_USER_SETUP_INCOMPLETE(true);
112 
113         public final boolean shouldLaunch;
114 
FullScreenIntentDecision(boolean shouldLaunch)115         FullScreenIntentDecision(boolean shouldLaunch) {
116             this.shouldLaunch = shouldLaunch;
117         }
118     }
119 
120     /**
121      * If the device is awake (not dozing):
122      *  Whether the notification should peek in from the top and alert the user.
123      *
124      * If the device is dozing:
125      *  Whether the notification should show the ambient view of the notification ("pulse").
126      *
127      * @param entry the entry to check
128      * @return true if the entry should heads up, false otherwise
129      */
shouldHeadsUp(NotificationEntry entry)130     boolean shouldHeadsUp(NotificationEntry entry);
131 
132     /**
133      * Returns the value of whether this entry should peek (from shouldHeadsUp(entry)), but only
134      * optionally logs the status.
135      *
136      * This method should be used in cases where the caller needs to check whether a notification
137      * qualifies for a heads up, but is not necessarily guaranteed to make the heads-up happen.
138      *
139      * @param entry the entry to check
140      * @param log whether or not to log the results of this check
141      * @return true if the entry should heads up, false otherwise
142      */
checkHeadsUp(NotificationEntry entry, boolean log)143     boolean checkHeadsUp(NotificationEntry entry, boolean log);
144 
145     /**
146      * Whether the notification should appear as a bubble with a fly-out on top of the screen.
147      *
148      * @param entry the entry to check
149      * @return true if the entry should bubble up, false otherwise
150      */
shouldBubbleUp(NotificationEntry entry)151     boolean shouldBubbleUp(NotificationEntry entry);
152 
153     /**
154      * Whether to launch the entry's full screen intent when the entry is added.
155      *
156      * @param entry the entry that was added
157      * @return {@code true} if we should launch the full screen intent
158      */
shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry)159     boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry);
160 
161     /**
162      * Whether an entry's full screen intent would be launched.
163      *
164      * This method differs from shouldLaunchFullScreenIntentWhenAdded by returning more information
165      * on the decision, and only optionally logging the outcome. It should be used in cases where
166      * the caller needs to know what the decision would be, but may not actually launch the full
167      * screen intent.
168      *
169      * @param entry the entry to evaluate
170      * @return FullScreenIntentDecision representing the decision for whether to show the intent
171      */
172     @NonNull
getFullScreenIntentDecision(@onNull NotificationEntry entry)173     FullScreenIntentDecision getFullScreenIntentDecision(@NonNull NotificationEntry entry);
174 
175     /**
176      * Write the full screen launch decision for the given entry to logs.
177      *
178      * @param entry the NotificationEntry for which the decision applies
179      * @param decision reason for launch or no-launch of FSI for entry
180      */
logFullScreenIntentDecision(NotificationEntry entry, FullScreenIntentDecision decision)181     void logFullScreenIntentDecision(NotificationEntry entry, FullScreenIntentDecision decision);
182 
183     /**
184      * Add a component that can suppress visual interruptions.
185      */
addSuppressor(NotificationInterruptSuppressor suppressor)186     void addSuppressor(NotificationInterruptSuppressor suppressor);
187 
188     /**
189      * Remove a component that can suppress visual interruptions.
190      */
removeSuppressor(NotificationInterruptSuppressor suppressor)191     void removeSuppressor(NotificationInterruptSuppressor suppressor);
192 }
193