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.UserInfo; 27 import android.os.UserHandle; 28 import android.service.notification.NotificationListenerService; 29 import android.service.notification.NotificationListenerService.RankingMap; 30 import android.util.Pair; 31 import android.util.SparseArray; 32 33 import androidx.annotation.IntDef; 34 import androidx.annotation.Nullable; 35 36 import com.android.wm.shell.common.annotations.ExternalThread; 37 38 import java.lang.annotation.Retention; 39 import java.lang.annotation.Target; 40 import java.util.HashMap; 41 import java.util.List; 42 import java.util.Set; 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, DISMISS_USER_REMOVED}) 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 int DISMISS_USER_REMOVED = 16; 78 79 /** 80 * @return {@code true} if there is a bubble associated with the provided key and if its 81 * notification is hidden from the shade or there is a group summary associated with the 82 * provided key that is hidden from the shade because it has been dismissed but still has child 83 * bubbles active. 84 */ isBubbleNotificationSuppressedFromShade(String key, String groupKey)85 boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey); 86 87 /** 88 * @return {@code true} if the current notification entry same as selected bubble 89 * notification entry and the stack is currently expanded. 90 */ isBubbleExpanded(String key)91 boolean isBubbleExpanded(String key); 92 93 /** Tell the stack of bubbles to collapse. */ collapseStack()94 void collapseStack(); 95 96 /** 97 * Request the stack expand if needed, then select the specified Bubble as current. 98 * If no bubble exists for this entry, one is created. 99 * 100 * @param entry the notification for the bubble to be selected 101 */ expandStackAndSelectBubble(BubbleEntry entry)102 void expandStackAndSelectBubble(BubbleEntry entry); 103 104 /** 105 * Request the stack expand if needed, then select the specified Bubble as current. 106 * 107 * @param bubble the bubble to be selected 108 */ expandStackAndSelectBubble(Bubble bubble)109 void expandStackAndSelectBubble(Bubble bubble); 110 111 /** 112 * This method has different behavior depending on: 113 * - if an app bubble exists 114 * - if an app bubble is expanded 115 * 116 * If no app bubble exists, this will add and expand a bubble with the provided intent. The 117 * intent must be explicit (i.e. include a package name or fully qualified component class name) 118 * and the activity for it should be resizable. 119 * 120 * If an app bubble exists, this will toggle the visibility of it, i.e. if the app bubble is 121 * expanded, calling this method will collapse it. If the app bubble is not expanded, calling 122 * this method will expand it. 123 * 124 * These bubbles are <b>not</b> backed by a notification and remain until the user dismisses 125 * the bubble or bubble stack. 126 * 127 * Some notes: 128 * - Only one app bubble is supported at a time 129 * - Calling this method with a different intent than the existing app bubble will do nothing 130 * 131 * @param intent the intent to display in the bubble expanded view. 132 */ showOrHideAppBubble(Intent intent)133 void showOrHideAppBubble(Intent intent); 134 135 /** 136 * @return a bubble that matches the provided shortcutId, if one exists. 137 */ 138 @Nullable getBubbleWithShortcutId(String shortcutId)139 Bubble getBubbleWithShortcutId(String shortcutId); 140 141 /** 142 * We intercept notification entries (including group summaries) dismissed by the user when 143 * there is an active bubble associated with it. We do this so that developers can still 144 * cancel it (and hence the bubbles associated with it). However, these intercepted 145 * notifications should then be hidden from the shade since the user has cancelled them, so we 146 * {@link Bubble#setSuppressNotification}. For the case of suppressed summaries, we also add 147 * {@link BubbleData#addSummaryToSuppress}. 148 * 149 * @param entry the notification of the BubbleEntry should be removed. 150 * @param children the list of child notification of the BubbleEntry from 1st param entry, 151 * this will be null if entry does have no children. 152 * @param removeCallback the remove callback for SystemUI side to remove notification, the int 153 * number should be list position of children list and use -1 for 154 * removing the parent notification. 155 * 156 * @return true if we want to intercept the dismissal of the entry, else false. 157 */ handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children, IntConsumer removeCallback, Executor callbackExecutor)158 boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children, 159 IntConsumer removeCallback, Executor callbackExecutor); 160 161 /** Set the proxy to commnuicate with SysUi side components. */ setSysuiProxy(SysuiProxy proxy)162 void setSysuiProxy(SysuiProxy proxy); 163 164 /** Set a listener to be notified of bubble expand events. */ setExpandListener(BubbleExpandListener listener)165 void setExpandListener(BubbleExpandListener listener); 166 167 /** 168 * Called when new notification entry added. 169 * 170 * @param entry the {@link BubbleEntry} by the notification. 171 */ onEntryAdded(BubbleEntry entry)172 void onEntryAdded(BubbleEntry entry); 173 174 /** 175 * Called when new notification entry updated. 176 * 177 * @param entry the {@link BubbleEntry} by the notification. 178 * @param shouldBubbleUp {@code true} if this notification should bubble up. 179 * @param fromSystem {@code true} if this update is from NotificationManagerService. 180 */ onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp, boolean fromSystem)181 void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp, boolean fromSystem); 182 183 /** 184 * Called when new notification entry removed. 185 * 186 * @param entry the {@link BubbleEntry} by the notification. 187 */ onEntryRemoved(BubbleEntry entry)188 void onEntryRemoved(BubbleEntry entry); 189 190 /** 191 * Called when NotificationListener has received adjusted notification rank and reapplied 192 * filtering and sorting. This is used to dismiss or create bubbles based on changes in 193 * permissions on the notification channel or the global setting. 194 * 195 * @param rankingMap the updated ranking map from NotificationListenerService 196 * @param entryDataByKey a map of ranking key to bubble entry and whether the entry should 197 * bubble up 198 */ onRankingUpdated( RankingMap rankingMap, HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey)199 void onRankingUpdated( 200 RankingMap rankingMap, 201 HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey); 202 203 /** 204 * Called when a notification channel is modified, in response to 205 * {@link NotificationListenerService#onNotificationChannelModified}. 206 * 207 * @param pkg the package the notification channel belongs to. 208 * @param user the user the notification channel belongs to. 209 * @param channel the channel being modified. 210 * @param modificationType the type of modification that occurred to the channel. 211 */ onNotificationChannelModified( String pkg, UserHandle user, NotificationChannel channel, int modificationType)212 void onNotificationChannelModified( 213 String pkg, 214 UserHandle user, 215 NotificationChannel channel, 216 int modificationType); 217 218 /** 219 * Called when notification panel is expanded or collapsed 220 */ onNotificationPanelExpandedChanged(boolean expanded)221 void onNotificationPanelExpandedChanged(boolean expanded); 222 223 /** 224 * Called when the status bar has become visible or invisible (either permanently or 225 * temporarily). 226 */ onStatusBarVisibilityChanged(boolean visible)227 void onStatusBarVisibilityChanged(boolean visible); 228 229 /** Called when system zen mode state changed. */ onZenStateChanged()230 void onZenStateChanged(); 231 232 /** 233 * Called when statusBar state changed. 234 * 235 * @param isShade {@code true} is state is SHADE. 236 */ onStatusBarStateChanged(boolean isShade)237 void onStatusBarStateChanged(boolean isShade); 238 239 /** 240 * Called when the current user changed. 241 * 242 * @param newUserId the new user's id. 243 */ onUserChanged(int newUserId)244 void onUserChanged(int newUserId); 245 246 /** 247 * Called when the current user profiles change. 248 * 249 * @param currentProfiles the user infos for the current profile. 250 */ onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles)251 void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles); 252 253 /** 254 * Called when a user is removed. 255 * 256 * @param removedUserId the id of the removed user. 257 */ onUserRemoved(int removedUserId)258 void onUserRemoved(int removedUserId); 259 260 /** Listener to find out about stack expansion / collapse events. */ 261 interface BubbleExpandListener { 262 /** 263 * Called when the expansion state of the bubble stack changes. 264 * 265 * @param isExpanding whether it's expanding or collapsing 266 * @param key the notification key associated with bubble being expanded 267 */ onBubbleExpandChanged(boolean isExpanding, String key)268 void onBubbleExpandChanged(boolean isExpanding, String key); 269 } 270 271 /** Listener to be notified when the flags on BubbleMetadata have changed. */ 272 interface BubbleMetadataFlagListener { 273 /** Called when the flags on BubbleMetadata have changed for the provided bubble. */ onBubbleMetadataFlagChanged(Bubble bubble)274 void onBubbleMetadataFlagChanged(Bubble bubble); 275 } 276 277 /** Listener to be notified when a pending intent has been canceled for a bubble. */ 278 interface PendingIntentCanceledListener { 279 /** Called when the pending intent for a bubble has been canceled. */ onPendingIntentCanceled(Bubble bubble)280 void onPendingIntentCanceled(Bubble bubble); 281 } 282 283 /** Callback to tell SysUi components execute some methods. */ 284 interface SysuiProxy { isNotificationPanelExpand(Consumer<Boolean> callback)285 void isNotificationPanelExpand(Consumer<Boolean> callback); 286 getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback)287 void getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback); 288 getShouldRestoredEntries(Set<String> savedBubbleKeys, Consumer<List<BubbleEntry>> callback)289 void getShouldRestoredEntries(Set<String> savedBubbleKeys, 290 Consumer<List<BubbleEntry>> callback); 291 setNotificationInterruption(String key)292 void setNotificationInterruption(String key); 293 requestNotificationShadeTopUi(boolean requestTopUi, String componentTag)294 void requestNotificationShadeTopUi(boolean requestTopUi, String componentTag); 295 notifyRemoveNotification(String key, int reason)296 void notifyRemoveNotification(String key, int reason); 297 notifyInvalidateNotifications(String reason)298 void notifyInvalidateNotifications(String reason); 299 updateNotificationBubbleButton(String key)300 void updateNotificationBubbleButton(String key); 301 onStackExpandChanged(boolean shouldExpand)302 void onStackExpandChanged(boolean shouldExpand); 303 onManageMenuExpandChanged(boolean menuExpanded)304 void onManageMenuExpandChanged(boolean menuExpanded); 305 onUnbubbleConversation(String key)306 void onUnbubbleConversation(String key); 307 } 308 } 309