• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.NotificationChannel;
25 import android.content.Intent;
26 import android.content.pm.ShortcutInfo;
27 import android.content.pm.UserInfo;
28 import android.graphics.drawable.Icon;
29 import android.hardware.HardwareBuffer;
30 import android.os.UserHandle;
31 import android.service.notification.NotificationListenerService;
32 import android.service.notification.NotificationListenerService.RankingMap;
33 import android.util.Pair;
34 import android.util.SparseArray;
35 import android.window.ScreenCapture.ScreenshotHardwareBuffer;
36 import android.window.ScreenCapture.SynchronousScreenCaptureListener;
37 
38 import androidx.annotation.IntDef;
39 import androidx.annotation.NonNull;
40 import androidx.annotation.Nullable;
41 
42 import com.android.wm.shell.shared.annotations.ExternalThread;
43 import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
44 import com.android.wm.shell.shared.bubbles.BubbleBarUpdate;
45 
46 import java.lang.annotation.Retention;
47 import java.lang.annotation.Target;
48 import java.util.HashMap;
49 import java.util.List;
50 import java.util.Set;
51 import java.util.concurrent.Executor;
52 import java.util.function.Consumer;
53 import java.util.function.IntConsumer;
54 
55 /**
56  * Interface to engage bubbles feature.
57  */
58 @ExternalThread
59 public interface Bubbles {
60 
61     @Retention(SOURCE)
62     @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
63             DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
64             DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
65             DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
66             DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_ACCOUNT_REMOVED,
67             DISMISS_SWITCH_TO_STACK, DISMISS_USER_GESTURE_FROM_LAUNCHER})
68     @Target({FIELD, LOCAL_VARIABLE, PARAMETER})
69     @interface DismissReason {
70     }
71 
72     int DISMISS_USER_GESTURE = 1;
73     int DISMISS_AGED = 2;
74     int DISMISS_TASK_FINISHED = 3;
75     int DISMISS_BLOCKED = 4;
76     int DISMISS_NOTIF_CANCEL = 5;
77     int DISMISS_ACCESSIBILITY_ACTION = 6;
78     int DISMISS_NO_LONGER_BUBBLE = 7;
79     int DISMISS_USER_CHANGED = 8;
80     int DISMISS_GROUP_CANCELLED = 9;
81     int DISMISS_INVALID_INTENT = 10;
82     int DISMISS_OVERFLOW_MAX_REACHED = 11;
83     int DISMISS_SHORTCUT_REMOVED = 12;
84     int DISMISS_PACKAGE_REMOVED = 13;
85     int DISMISS_NO_BUBBLE_UP = 14;
86     int DISMISS_RELOAD_FROM_DISK = 15;
87     int DISMISS_USER_ACCOUNT_REMOVED = 16;
88     int DISMISS_SWITCH_TO_STACK = 17;
89     int DISMISS_USER_GESTURE_FROM_LAUNCHER = 18;
90 
91     /** Returns a binder that can be passed to an external process to manipulate Bubbles. */
createExternalInterface()92     default IBubbles createExternalInterface() {
93         return null;
94     }
95 
96     /**
97      * @return {@code true} if there is a bubble associated with the provided key and if its
98      * notification is hidden from the shade or there is a group summary associated with the
99      * provided key that is hidden from the shade because it has been dismissed but still has child
100      * bubbles active.
101      */
isBubbleNotificationSuppressedFromShade(String key, String groupKey)102     boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey);
103 
104     /**
105      * @return {@code true} if the current notification entry same as selected bubble
106      * notification entry and the stack is currently expanded.
107      */
isBubbleExpanded(String key)108     boolean isBubbleExpanded(String key);
109 
110     /** Tell the stack of bubbles to collapse. */
collapseStack()111     void collapseStack();
112 
113     /**
114      * Request the stack expand if needed, then select the specified Bubble as current.
115      * If no bubble exists for this entry, one is created.
116      *
117      * @param entry the notification for the bubble to be selected
118      */
expandStackAndSelectBubble(BubbleEntry entry)119     void expandStackAndSelectBubble(BubbleEntry entry);
120 
121     /**
122      * Request the stack expand if needed, then select the specified Bubble as current.
123      * If no bubble exists for this entry, one is created.
124      *
125      * @param info the shortcut info to use to create the bubble.
126      */
expandStackAndSelectBubble(ShortcutInfo info)127     void expandStackAndSelectBubble(ShortcutInfo info);
128 
129     /**
130      * Request the stack expand if needed, then select the specified Bubble as current.
131      *
132      * @param bubble the bubble to be selected
133      */
expandStackAndSelectBubble(Bubble bubble)134     void expandStackAndSelectBubble(Bubble bubble);
135 
136     /**
137      * This method has different behavior depending on:
138      *    - if a notes bubble exists
139      *    - if a notes bubble is expanded
140      *
141      * If no notes bubble exists, this will add and expand a bubble with the provided intent. The
142      * intent must be explicit (i.e. include a package name or fully qualified component class name)
143      * and the activity for it should be resizable.
144      *
145      * If a notes bubble exists, this will toggle the visibility of it, i.e. if the notes bubble is
146      * expanded, calling this method will collapse it. If the notes bubble is not expanded, calling
147      * this method will expand it.
148      *
149      * These bubbles are <b>not</b> backed by a notification and remain until the user dismisses
150      * the bubble or bubble stack.
151      *
152      * Some details:
153      *    - Calling this method with a different intent than the existing bubble will do nothing
154      *
155      * @param intent the intent to display in the bubble expanded view.
156      * @param user the {@link UserHandle} of the user to start this activity for.
157      * @param icon the {@link Icon} to use for the bubble view.
158      */
showOrHideNoteBubble(Intent intent, UserHandle user, @Nullable Icon icon)159     void showOrHideNoteBubble(Intent intent, UserHandle user, @Nullable Icon icon);
160 
161     /** @return true if the specified {@code taskId} corresponds to app bubble's taskId. */
isNoteBubbleTaskId(int taskId)162     boolean isNoteBubbleTaskId(int taskId);
163 
164     /**
165 `    * @return a {@link SynchronousScreenCaptureListener} after performing a screenshot that may
166      * exclude the bubble layer, if one is present. The underlying
167      * {@link ScreenshotHardwareBuffer} can be accessed via
168      * {@link SynchronousScreenCaptureListener#getBuffer()} asynchronously and care should be taken
169      * to {@link HardwareBuffer#close()} the associated
170      * {@link ScreenshotHardwareBuffer#getHardwareBuffer()} when no longer required.`
171      */
getScreenshotExcludingBubble(int displayId)172     SynchronousScreenCaptureListener getScreenshotExcludingBubble(int displayId);
173 
174     /**
175      * @return a bubble that matches the provided shortcutId, if one exists.
176      */
177     @Nullable
getBubbleWithShortcutId(String shortcutId)178     Bubble getBubbleWithShortcutId(String shortcutId);
179 
180     /**
181      * We intercept notification entries (including group summaries) dismissed by the user when
182      * there is an active bubble associated with it. We do this so that developers can still
183      * cancel it (and hence the bubbles associated with it). However, these intercepted
184      * notifications should then be hidden from the shade since the user has cancelled them, so we
185      * {@link Bubble#setSuppressNotification}.  For the case of suppressed summaries, we also add
186      * {@link BubbleData#addSummaryToSuppress}.
187      *
188      * @param entry          the notification of the BubbleEntry should be removed.
189      * @param children       the list of child notification of the BubbleEntry from 1st param entry,
190      *                       this will be null if entry does have no children.
191      * @param removeCallback the remove callback for SystemUI side to remove notification, the int
192      *                       number should be list position of children list and use -1 for
193      *                       removing the parent notification.
194      * @return true if we want to intercept the dismissal of the entry, else false.
195      */
handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children, IntConsumer removeCallback, Executor callbackExecutor)196     boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children,
197             IntConsumer removeCallback, Executor callbackExecutor);
198 
199     /** Set the proxy to commnuicate with SysUi side components. */
setSysuiProxy(SysuiProxy proxy)200     void setSysuiProxy(SysuiProxy proxy);
201 
202     /** Set a listener to be notified of bubble expand events. */
setExpandListener(BubbleExpandListener listener)203     void setExpandListener(BubbleExpandListener listener);
204 
205     /**
206      * Called when new notification entry added.
207      *
208      * @param entry the {@link BubbleEntry} by the notification.
209      */
onEntryAdded(BubbleEntry entry)210     void onEntryAdded(BubbleEntry entry);
211 
212     /**
213      * Called when new notification entry updated.
214      *
215      * @param entry          the {@link BubbleEntry} by the notification.
216      * @param shouldBubbleUp {@code true} if this notification should bubble up.
217      * @param fromSystem     {@code true} if this update is from NotificationManagerService or App,
218      *                                   false means this update is from SystemUi
219      */
onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp, boolean fromSystem)220     void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp, boolean fromSystem);
221 
222     /**
223      * Called when new notification entry removed.
224      *
225      * @param entry the {@link BubbleEntry} by the notification.
226      */
onEntryRemoved(BubbleEntry entry)227     void onEntryRemoved(BubbleEntry entry);
228 
229     /**
230      * Called when NotificationListener has received adjusted notification rank and reapplied
231      * filtering and sorting. This is used to dismiss or create bubbles based on changes in
232      * permissions on the notification channel or the global setting.
233      *
234      * @param rankingMap     the updated ranking map from NotificationListenerService
235      * @param entryDataByKey a map of ranking key to bubble entry and whether the entry should
236      *                       bubble up
237      */
onRankingUpdated( RankingMap rankingMap, HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey)238     void onRankingUpdated(
239             RankingMap rankingMap,
240             HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey);
241 
242     /**
243      * Called when a notification channel is modified, in response to
244      * {@link NotificationListenerService#onNotificationChannelModified}.
245      *
246      * @param pkg              the package the notification channel belongs to.
247      * @param user             the user the notification channel belongs to.
248      * @param channel          the channel being modified.
249      * @param modificationType the type of modification that occurred to the channel.
250      */
onNotificationChannelModified( String pkg, UserHandle user, NotificationChannel channel, int modificationType)251     void onNotificationChannelModified(
252             String pkg,
253             UserHandle user,
254             NotificationChannel channel,
255             int modificationType);
256 
257     /**
258      * Called when notification panel is expanded or collapsed
259      */
onNotificationPanelExpandedChanged(boolean expanded)260     void onNotificationPanelExpandedChanged(boolean expanded);
261 
262     /**
263      * Called when the status bar has become visible or invisible (either permanently or
264      * temporarily).
265      */
onStatusBarVisibilityChanged(boolean visible)266     void onStatusBarVisibilityChanged(boolean visible);
267 
268     /** Called when system zen mode state changed. */
onZenStateChanged()269     void onZenStateChanged();
270 
271     /**
272      * Called when statusBar state changed.
273      *
274      * @param isShade {@code true} is state is SHADE.
275      */
onStatusBarStateChanged(boolean isShade)276     void onStatusBarStateChanged(boolean isShade);
277 
278     /**
279      * Called when the current user changed.
280      *
281      * @param newUserId the new user's id.
282      */
onUserChanged(int newUserId)283     void onUserChanged(int newUserId);
284 
285     /**
286      * Called when the current user profiles change.
287      *
288      * @param currentProfiles the user infos for the current profile.
289      */
onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles)290     void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles);
291 
292     /**
293      * Called when a user is removed.
294      *
295      * @param removedUserId the id of the removed user.
296      */
onUserRemoved(int removedUserId)297     void onUserRemoved(int removedUserId);
298 
299     /**
300      * Called when the Sensitive notification protection state has changed, such as when media
301      * projection starts and stops.
302      *
303      * @param sensitiveNotificationProtectionActive {@code true} if notifications should be
304      *     protected
305      */
onSensitiveNotificationProtectionStateChanged( boolean sensitiveNotificationProtectionActive)306     void onSensitiveNotificationProtectionStateChanged(
307             boolean sensitiveNotificationProtectionActive);
308 
309     /**
310      * Determines whether Bubbles can show notifications.
311      *
312      * <p>Normally bubble notifications are shown by Bubbles, but in some cases the bubble
313      * notification is suppressed and should be shown by the Notifications pipeline as regular
314      * notifications.
315      */
canShowBubbleNotification()316     boolean canShowBubbleNotification();
317 
318     /**
319      * A listener to be notified of bubble state changes, used by launcher to render bubbles in
320      * its process.
321      */
322     interface BubbleStateListener {
323         /**
324          * Called when the bubbles state changes.
325          */
onBubbleStateChange(BubbleBarUpdate update)326         void onBubbleStateChange(BubbleBarUpdate update);
327 
328         /**
329          * Called when bubble bar should temporarily be animated to a new location.
330          * Does not result in a state change.
331          */
animateBubbleBarLocation(BubbleBarLocation location)332         void animateBubbleBarLocation(BubbleBarLocation location);
333 
334         /**
335          * Called when an application icon is being dragged over the Bubble Bar drop zone.
336          * The location of the Bubble Bar is provided as an argument.
337          */
onDragItemOverBubbleBarDragZone(@onNull BubbleBarLocation location)338         void onDragItemOverBubbleBarDragZone(@NonNull BubbleBarLocation location);
339 
340         /**
341          * Called when an application icon is being dragged outside the Bubble Bar drop zone.
342          * Always called after {@link #onDragItemOverBubbleBarDragZone(BubbleBarLocation)}
343          */
onItemDraggedOutsideBubbleBarDropZone()344         void onItemDraggedOutsideBubbleBarDropZone();
345     }
346 
347     /** Listener to find out about stack expansion / collapse events. */
348     interface BubbleExpandListener {
349         /**
350          * Called when the expansion state of the bubble stack changes.
351          *
352          * @param isExpanding whether it's expanding or collapsing
353          * @param key         the notification key associated with bubble being expanded
354          */
onBubbleExpandChanged(boolean isExpanding, String key)355         void onBubbleExpandChanged(boolean isExpanding, String key);
356     }
357 
358     /** Listener to be notified when the flags on BubbleMetadata have changed. */
359     interface BubbleMetadataFlagListener {
360         /** Called when the flags on BubbleMetadata have changed for the provided bubble. */
onBubbleMetadataFlagChanged(Bubble bubble)361         void onBubbleMetadataFlagChanged(Bubble bubble);
362     }
363 
364     /** Listener to be notified when a pending intent has been canceled for a bubble. */
365     interface PendingIntentCanceledListener {
366         /** Called when the pending intent for a bubble has been canceled. */
onPendingIntentCanceled(Bubble bubble)367         void onPendingIntentCanceled(Bubble bubble);
368     }
369 
370     /** Callback to tell SysUi components execute some methods. */
371     interface SysuiProxy {
372 
373         /** Provider interface for {@link SysuiProxy}. */
374         interface Provider {
375             /** Returns {@link SysuiProxy}. */
getSysuiProxy()376             SysuiProxy getSysuiProxy();
377         }
378 
isNotificationPanelExpand(Consumer<Boolean> callback)379         void isNotificationPanelExpand(Consumer<Boolean> callback);
380 
getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback)381         void getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback);
382 
getShouldRestoredEntries(Set<String> savedBubbleKeys, Consumer<List<BubbleEntry>> callback)383         void getShouldRestoredEntries(Set<String> savedBubbleKeys,
384                 Consumer<List<BubbleEntry>> callback);
385 
setNotificationInterruption(String key)386         void setNotificationInterruption(String key);
387 
requestNotificationShadeTopUi(boolean requestTopUi, String componentTag)388         void requestNotificationShadeTopUi(boolean requestTopUi, String componentTag);
389 
notifyRemoveNotification(String key, int reason)390         void notifyRemoveNotification(String key, int reason);
391 
notifyInvalidateNotifications(String reason)392         void notifyInvalidateNotifications(String reason);
393 
updateNotificationBubbleButton(String key)394         void updateNotificationBubbleButton(String key);
395 
onStackExpandChanged(boolean shouldExpand)396         void onStackExpandChanged(boolean shouldExpand);
397 
onManageMenuExpandChanged(boolean menuExpanded)398         void onManageMenuExpandChanged(boolean menuExpanded);
399 
onUnbubbleConversation(String key)400         void onUnbubbleConversation(String key);
401     }
402 }
403