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         public final boolean shouldLaunch;
106 
FullScreenIntentDecision(boolean shouldLaunch)107         FullScreenIntentDecision(boolean shouldLaunch) {
108             this.shouldLaunch = shouldLaunch;
109         }
110     }
111 
112     /**
113      * If the device is awake (not dozing):
114      *  Whether the notification should peek in from the top and alert the user.
115      *
116      * If the device is dozing:
117      *  Whether the notification should show the ambient view of the notification ("pulse").
118      *
119      * @param entry the entry to check
120      * @return true if the entry should heads up, false otherwise
121      */
shouldHeadsUp(NotificationEntry entry)122     boolean shouldHeadsUp(NotificationEntry entry);
123 
124     /**
125      * Returns the value of whether this entry should peek (from shouldHeadsUp(entry)), but only
126      * optionally logs the status.
127      *
128      * This method should be used in cases where the caller needs to check whether a notification
129      * qualifies for a heads up, but is not necessarily guaranteed to make the heads-up happen.
130      *
131      * @param entry the entry to check
132      * @param log whether or not to log the results of this check
133      * @return true if the entry should heads up, false otherwise
134      */
checkHeadsUp(NotificationEntry entry, boolean log)135     boolean checkHeadsUp(NotificationEntry entry, boolean log);
136 
137     /**
138      * Whether the notification should appear as a bubble with a fly-out on top of the screen.
139      *
140      * @param entry the entry to check
141      * @return true if the entry should bubble up, false otherwise
142      */
shouldBubbleUp(NotificationEntry entry)143     boolean shouldBubbleUp(NotificationEntry entry);
144 
145     /**
146      * Whether to launch the entry's full screen intent when the entry is added.
147      *
148      * @param entry the entry that was added
149      * @return {@code true} if we should launch the full screen intent
150      */
shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry)151     boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry);
152 
153     /**
154      * Whether an entry's full screen intent would be launched.
155      *
156      * This method differs from shouldLaunchFullScreenIntentWhenAdded by returning more information
157      * on the decision, and only optionally logging the outcome. It should be used in cases where
158      * the caller needs to know what the decision would be, but may not actually launch the full
159      * screen intent.
160      *
161      * @param entry the entry to evaluate
162      * @return FullScreenIntentDecision representing the decision for whether to show the intent
163      */
164     @NonNull
getFullScreenIntentDecision(@onNull NotificationEntry entry)165     FullScreenIntentDecision getFullScreenIntentDecision(@NonNull NotificationEntry entry);
166 
167     /**
168      * Write the full screen launch decision for the given entry to logs.
169      *
170      * @param entry the NotificationEntry for which the decision applies
171      * @param decision reason for launch or no-launch of FSI for entry
172      */
logFullScreenIntentDecision(NotificationEntry entry, FullScreenIntentDecision decision)173     void logFullScreenIntentDecision(NotificationEntry entry, FullScreenIntentDecision decision);
174 
175     /**
176      * Add a component that can suppress visual interruptions.
177      */
addSuppressor(NotificationInterruptSuppressor suppressor)178     void addSuppressor(NotificationInterruptSuppressor suppressor);
179 }
180