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.wm.shell.bubbles;
18 
19 import static java.lang.annotation.ElementType.FIELD;
20 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
21 import static java.lang.annotation.ElementType.PARAMETER;
22 import static java.lang.annotation.RetentionPolicy.SOURCE;
23 
24 import android.content.pm.UserInfo;
25 import android.content.res.Configuration;
26 import android.os.Bundle;
27 import android.service.notification.NotificationListenerService.RankingMap;
28 import android.util.ArraySet;
29 import android.util.Pair;
30 import android.util.SparseArray;
31 
32 import androidx.annotation.IntDef;
33 import androidx.annotation.Nullable;
34 
35 import com.android.wm.shell.common.annotations.ExternalThread;
36 
37 import java.io.FileDescriptor;
38 import java.io.PrintWriter;
39 import java.lang.annotation.Retention;
40 import java.lang.annotation.Target;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.concurrent.Executor;
44 import java.util.function.Consumer;
45 import java.util.function.IntConsumer;
46 
47 /**
48  * Interface to engage bubbles feature.
49  */
50 @ExternalThread
51 public interface Bubbles {
52 
53     @Retention(SOURCE)
54     @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
55             DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
56             DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
57             DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
58             DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK})
59     @Target({FIELD, LOCAL_VARIABLE, PARAMETER})
60     @interface DismissReason {}
61 
62     int DISMISS_USER_GESTURE = 1;
63     int DISMISS_AGED = 2;
64     int DISMISS_TASK_FINISHED = 3;
65     int DISMISS_BLOCKED = 4;
66     int DISMISS_NOTIF_CANCEL = 5;
67     int DISMISS_ACCESSIBILITY_ACTION = 6;
68     int DISMISS_NO_LONGER_BUBBLE = 7;
69     int DISMISS_USER_CHANGED = 8;
70     int DISMISS_GROUP_CANCELLED = 9;
71     int DISMISS_INVALID_INTENT = 10;
72     int DISMISS_OVERFLOW_MAX_REACHED = 11;
73     int DISMISS_SHORTCUT_REMOVED = 12;
74     int DISMISS_PACKAGE_REMOVED = 13;
75     int DISMISS_NO_BUBBLE_UP = 14;
76     int DISMISS_RELOAD_FROM_DISK = 15;
77 
78     /**
79      * @return {@code true} if there is a bubble associated with the provided key and if its
80      * notification is hidden from the shade or there is a group summary associated with the
81      * provided key that is hidden from the shade because it has been dismissed but still has child
82      * bubbles active.
83      */
isBubbleNotificationSuppressedFromShade(String key, String groupKey)84     boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey);
85 
86     /**
87      * @return {@code true} if the current notification entry same as selected bubble
88      * notification entry and the stack is currently expanded.
89      */
isBubbleExpanded(String key)90     boolean isBubbleExpanded(String key);
91 
92     /** @return {@code true} if stack of bubbles is expanded or not. */
isStackExpanded()93     boolean isStackExpanded();
94 
95     /**
96      * Removes a group key indicating that the summary for this group should no longer be
97      * suppressed.
98      *
99      * @param callback If removed, this callback will be called with the summary key of the group
100      */
removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback, Executor callbackExecutor)101     void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback,
102             Executor callbackExecutor);
103 
104     /** Tell the stack of bubbles to collapse. */
collapseStack()105     void collapseStack();
106 
107     /** Tell the controller need update its UI to fit theme. */
updateForThemeChanges()108     void updateForThemeChanges();
109 
110     /**
111      * Request the stack expand if needed, then select the specified Bubble as current.
112      * If no bubble exists for this entry, one is created.
113      *
114      * @param entry the notification for the bubble to be selected
115      */
expandStackAndSelectBubble(BubbleEntry entry)116     void expandStackAndSelectBubble(BubbleEntry entry);
117 
118     /**
119      * Request the stack expand if needed, then select the specified Bubble as current.
120      *
121      * @param bubble the bubble to be selected
122      */
expandStackAndSelectBubble(Bubble bubble)123     void expandStackAndSelectBubble(Bubble bubble);
124 
125     /**
126      * @return a bubble that matches the provided shortcutId, if one exists.
127      */
128     @Nullable
getBubbleWithShortcutId(String shortcutId)129     Bubble getBubbleWithShortcutId(String shortcutId);
130 
131     /** Called for any taskbar changes. */
onTaskbarChanged(Bundle b)132     void onTaskbarChanged(Bundle b);
133 
134     /** Open the overflow view. */
openBubbleOverflow()135     void openBubbleOverflow();
136 
137     /**
138      * We intercept notification entries (including group summaries) dismissed by the user when
139      * there is an active bubble associated with it. We do this so that developers can still
140      * cancel it (and hence the bubbles associated with it). However, these intercepted
141      * notifications should then be hidden from the shade since the user has cancelled them, so we
142      * {@link Bubble#setSuppressNotification}.  For the case of suppressed summaries, we also add
143      * {@link BubbleData#addSummaryToSuppress}.
144      *
145      * @param entry the notification of the BubbleEntry should be removed.
146      * @param children the list of child notification of the BubbleEntry from 1st param entry,
147      *                 this will be null if entry does have no children.
148      * @param removeCallback the remove callback for SystemUI side to remove notification, the int
149      *                       number should be list position of children list and use -1 for
150      *                       removing the parent notification.
151      *
152      * @return true if we want to intercept the dismissal of the entry, else false.
153      */
handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children, IntConsumer removeCallback, Executor callbackExecutor)154     boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children,
155             IntConsumer removeCallback, Executor callbackExecutor);
156 
157     /** Set the proxy to commnuicate with SysUi side components. */
setSysuiProxy(SysuiProxy proxy)158     void setSysuiProxy(SysuiProxy proxy);
159 
160     /** Set a listener to be notified of bubble expand events. */
setExpandListener(BubbleExpandListener listener)161     void setExpandListener(BubbleExpandListener listener);
162 
163     /**
164      * Called when new notification entry added.
165      *
166      * @param entry the {@link BubbleEntry} by the notification.
167      */
onEntryAdded(BubbleEntry entry)168     void onEntryAdded(BubbleEntry entry);
169 
170     /**
171      * Called when new notification entry updated.
172      *
173      * @param entry the {@link BubbleEntry} by the notification.
174      * @param shouldBubbleUp {@code true} if this notification should bubble up.
175      */
onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp)176     void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp);
177 
178     /**
179      * Called when new notification entry removed.
180      *
181      * @param entry the {@link BubbleEntry} by the notification.
182      */
onEntryRemoved(BubbleEntry entry)183     void onEntryRemoved(BubbleEntry entry);
184 
185     /**
186      * Called when NotificationListener has received adjusted notification rank and reapplied
187      * filtering and sorting. This is used to dismiss or create bubbles based on changes in
188      * permissions on the notification channel or the global setting.
189      *
190      * @param rankingMap the updated ranking map from NotificationListenerService
191      * @param entryDataByKey a map of ranking key to bubble entry and whether the entry should
192      *                       bubble up
193      */
onRankingUpdated(RankingMap rankingMap, HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey)194     void onRankingUpdated(RankingMap rankingMap,
195             HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey);
196 
197     /**
198      * Called when the status bar has become visible or invisible (either permanently or
199      * temporarily).
200      */
onStatusBarVisibilityChanged(boolean visible)201     void onStatusBarVisibilityChanged(boolean visible);
202 
203     /** Called when system zen mode state changed. */
onZenStateChanged()204     void onZenStateChanged();
205 
206     /**
207      * Called when statusBar state changed.
208      *
209      * @param isShade {@code true} is state is SHADE.
210      */
onStatusBarStateChanged(boolean isShade)211     void onStatusBarStateChanged(boolean isShade);
212 
213     /**
214      * Called when the current user changed.
215      *
216      * @param newUserId the new user's id.
217      */
onUserChanged(int newUserId)218     void onUserChanged(int newUserId);
219 
220     /**
221      * Called when the current user profiles change.
222      *
223      * @param currentProfiles the user infos for the current profile.
224      */
onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles)225     void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles);
226 
227     /**
228      * Called when config changed.
229      *
230      * @param newConfig the new config.
231      */
onConfigChanged(Configuration newConfig)232     void onConfigChanged(Configuration newConfig);
233 
234     /** Description of current bubble state. */
dump(FileDescriptor fd, PrintWriter pw, String[] args)235     void dump(FileDescriptor fd, PrintWriter pw, String[] args);
236 
237     /** Listener to find out about stack expansion / collapse events. */
238     interface BubbleExpandListener {
239         /**
240          * Called when the expansion state of the bubble stack changes.
241          *
242          * @param isExpanding whether it's expanding or collapsing
243          * @param key the notification key associated with bubble being expanded
244          */
onBubbleExpandChanged(boolean isExpanding, String key)245         void onBubbleExpandChanged(boolean isExpanding, String key);
246     }
247 
248     /** Listener to be notified when the flags for notification or bubble suppression changes.*/
249     interface SuppressionChangedListener {
250         /** Called when the notification suppression state of a bubble changes. */
onBubbleNotificationSuppressionChange(Bubble bubble)251         void onBubbleNotificationSuppressionChange(Bubble bubble);
252     }
253 
254     /** Listener to be notified when a pending intent has been canceled for a bubble. */
255     interface PendingIntentCanceledListener {
256         /** Called when the pending intent for a bubble has been canceled. */
onPendingIntentCanceled(Bubble bubble)257         void onPendingIntentCanceled(Bubble bubble);
258     }
259 
260     /** Callback to tell SysUi components execute some methods. */
261     interface SysuiProxy {
isNotificationShadeExpand(Consumer<Boolean> callback)262         void isNotificationShadeExpand(Consumer<Boolean> callback);
263 
getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback)264         void getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback);
265 
getShouldRestoredEntries(ArraySet<String> savedBubbleKeys, Consumer<List<BubbleEntry>> callback)266         void getShouldRestoredEntries(ArraySet<String> savedBubbleKeys,
267                 Consumer<List<BubbleEntry>> callback);
268 
setNotificationInterruption(String key)269         void setNotificationInterruption(String key);
270 
requestNotificationShadeTopUi(boolean requestTopUi, String componentTag)271         void requestNotificationShadeTopUi(boolean requestTopUi, String componentTag);
272 
notifyRemoveNotification(String key, int reason)273         void notifyRemoveNotification(String key, int reason);
274 
notifyInvalidateNotifications(String reason)275         void notifyInvalidateNotifications(String reason);
276 
notifyMaybeCancelSummary(String key)277         void notifyMaybeCancelSummary(String key);
278 
removeNotificationEntry(String key)279         void removeNotificationEntry(String key);
280 
updateNotificationBubbleButton(String key)281         void updateNotificationBubbleButton(String key);
282 
updateNotificationSuppression(String key)283         void updateNotificationSuppression(String key);
284 
onStackExpandChanged(boolean shouldExpand)285         void onStackExpandChanged(boolean shouldExpand);
286 
onManageMenuExpandChanged(boolean menuExpanded)287         void onManageMenuExpandChanged(boolean menuExpanded);
288 
onUnbubbleConversation(String key)289         void onUnbubbleConversation(String key);
290     }
291 }
292