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