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