1 /* 2 * Copyright (C) 2007 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 android.app; 18 19 import android.Manifest; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SystemApi; 25 import android.annotation.SystemService; 26 import android.annotation.TestApi; 27 import android.annotation.UserIdInt; 28 import android.app.compat.CompatChanges; 29 import android.compat.annotation.ChangeId; 30 import android.compat.annotation.EnabledSince; 31 import android.compat.annotation.LoggingOnly; 32 import android.compat.annotation.UnsupportedAppUsage; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.graphics.drawable.Icon; 37 import android.media.INearbyMediaDevicesProvider; 38 import android.media.INearbyMediaDevicesUpdateCallback; 39 import android.media.MediaRoute2Info; 40 import android.media.NearbyDevice; 41 import android.media.NearbyMediaDevicesProvider; 42 import android.os.Binder; 43 import android.os.Build; 44 import android.os.Bundle; 45 import android.os.IBinder; 46 import android.os.RemoteException; 47 import android.os.ServiceManager; 48 import android.os.UserHandle; 49 import android.util.Pair; 50 import android.util.Slog; 51 import android.view.KeyEvent; 52 import android.view.View; 53 54 import com.android.internal.compat.IPlatformCompat; 55 import com.android.internal.statusbar.AppClipsServiceConnector; 56 import com.android.internal.statusbar.IAddTileResultCallback; 57 import com.android.internal.statusbar.IStatusBarService; 58 import com.android.internal.statusbar.IUndoMediaTransferCallback; 59 import com.android.internal.statusbar.NotificationVisibility; 60 61 import java.lang.annotation.Retention; 62 import java.lang.annotation.RetentionPolicy; 63 import java.util.HashMap; 64 import java.util.List; 65 import java.util.Map; 66 import java.util.Objects; 67 import java.util.Set; 68 import java.util.concurrent.Executor; 69 import java.util.function.Consumer; 70 71 /** 72 * Allows an app to control the status bar. 73 */ 74 @SystemService(Context.STATUS_BAR_SERVICE) 75 public class StatusBarManager { 76 // LINT.IfChange 77 /** @hide */ 78 public static final int DISABLE_EXPAND = View.STATUS_BAR_DISABLE_EXPAND; 79 /** @hide */ 80 public static final int DISABLE_NOTIFICATION_ICONS = View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS; 81 /** @hide */ 82 public static final int DISABLE_NOTIFICATION_ALERTS 83 = View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS; 84 85 /** @hide */ 86 @Deprecated 87 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 88 public static final int DISABLE_NOTIFICATION_TICKER 89 = View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER; 90 /** @hide */ 91 public static final int DISABLE_SYSTEM_INFO = View.STATUS_BAR_DISABLE_SYSTEM_INFO; 92 /** @hide */ 93 public static final int DISABLE_HOME = View.STATUS_BAR_DISABLE_HOME; 94 /** @hide */ 95 public static final int DISABLE_RECENT = View.STATUS_BAR_DISABLE_RECENT; 96 /** @hide */ 97 public static final int DISABLE_BACK = View.STATUS_BAR_DISABLE_BACK; 98 /** @hide */ 99 public static final int DISABLE_CLOCK = View.STATUS_BAR_DISABLE_CLOCK; 100 /** @hide */ 101 public static final int DISABLE_SEARCH = View.STATUS_BAR_DISABLE_SEARCH; 102 103 /** @hide */ 104 public static final int DISABLE_ONGOING_CALL_CHIP = View.STATUS_BAR_DISABLE_ONGOING_CALL_CHIP; 105 106 /** @hide */ 107 @Deprecated 108 public static final int DISABLE_NAVIGATION = 109 View.STATUS_BAR_DISABLE_HOME | View.STATUS_BAR_DISABLE_RECENT; 110 111 /** @hide */ 112 public static final int DISABLE_NONE = 0x00000000; 113 114 /** @hide */ 115 public static final int DISABLE_MASK = DISABLE_EXPAND | DISABLE_NOTIFICATION_ICONS 116 | DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER 117 | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK 118 | DISABLE_SEARCH | DISABLE_ONGOING_CALL_CHIP; 119 120 /** @hide */ 121 @IntDef(flag = true, prefix = {"DISABLE_"}, value = { 122 DISABLE_NONE, 123 DISABLE_EXPAND, 124 DISABLE_NOTIFICATION_ICONS, 125 DISABLE_NOTIFICATION_ALERTS, 126 DISABLE_NOTIFICATION_TICKER, 127 DISABLE_SYSTEM_INFO, 128 DISABLE_HOME, 129 DISABLE_RECENT, 130 DISABLE_BACK, 131 DISABLE_CLOCK, 132 DISABLE_SEARCH, 133 DISABLE_ONGOING_CALL_CHIP 134 }) 135 @Retention(RetentionPolicy.SOURCE) 136 public @interface DisableFlags {} 137 138 /** 139 * Flag to disable quick settings. 140 * 141 * Setting this flag disables quick settings completely, but does not disable expanding the 142 * notification shade. 143 */ 144 /** @hide */ 145 public static final int DISABLE2_QUICK_SETTINGS = 1; 146 /** @hide */ 147 public static final int DISABLE2_SYSTEM_ICONS = 1 << 1; 148 /** @hide */ 149 public static final int DISABLE2_NOTIFICATION_SHADE = 1 << 2; 150 /** @hide */ 151 public static final int DISABLE2_GLOBAL_ACTIONS = 1 << 3; 152 /** @hide */ 153 public static final int DISABLE2_ROTATE_SUGGESTIONS = 1 << 4; 154 155 /** @hide */ 156 public static final int DISABLE2_NONE = 0x00000000; 157 158 /** @hide */ 159 public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS 160 | DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS | DISABLE2_ROTATE_SUGGESTIONS; 161 162 /** @hide */ 163 @IntDef(flag = true, prefix = { "DISABLE2_" }, value = { 164 DISABLE2_NONE, 165 DISABLE2_MASK, 166 DISABLE2_QUICK_SETTINGS, 167 DISABLE2_SYSTEM_ICONS, 168 DISABLE2_NOTIFICATION_SHADE, 169 DISABLE2_GLOBAL_ACTIONS, 170 DISABLE2_ROTATE_SUGGESTIONS 171 }) 172 @Retention(RetentionPolicy.SOURCE) 173 public @interface Disable2Flags {} 174 // LINT.ThenChange(frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt) 175 176 private static final String TAG = "StatusBarManager"; 177 178 /** 179 * Default disable flags for setup 180 * 181 * @hide 182 */ 183 public static final int DEFAULT_SETUP_DISABLE_FLAGS = DISABLE_NOTIFICATION_ALERTS 184 | DISABLE_HOME | DISABLE_EXPAND | DISABLE_RECENT | DISABLE_CLOCK | DISABLE_SEARCH; 185 186 /** 187 * Default disable2 flags for setup 188 * 189 * @hide 190 */ 191 public static final int DEFAULT_SETUP_DISABLE2_FLAGS = DISABLE2_NONE; 192 193 /** 194 * disable flags to be applied when the device is sim-locked. 195 */ 196 private static final int DEFAULT_SIM_LOCKED_DISABLED_FLAGS = DISABLE_EXPAND; 197 198 /** @hide */ 199 public static final int NAVIGATION_HINT_BACK_ALT = 1 << 0; 200 /** @hide */ 201 public static final int NAVIGATION_HINT_IME_SHOWN = 1 << 1; 202 /** @hide */ 203 public static final int NAVIGATION_HINT_IME_SWITCHER_SHOWN = 1 << 2; 204 205 /** @hide */ 206 public static final int WINDOW_STATUS_BAR = 1; 207 /** @hide */ 208 public static final int WINDOW_NAVIGATION_BAR = 2; 209 210 /** @hide */ 211 @IntDef(flag = true, prefix = { "WINDOW_" }, value = { 212 WINDOW_STATUS_BAR, 213 WINDOW_NAVIGATION_BAR 214 }) 215 @Retention(RetentionPolicy.SOURCE) 216 public @interface WindowType {} 217 218 /** @hide */ 219 public static final int WINDOW_STATE_SHOWING = 0; 220 /** @hide */ 221 public static final int WINDOW_STATE_HIDING = 1; 222 /** @hide */ 223 public static final int WINDOW_STATE_HIDDEN = 2; 224 225 /** @hide */ 226 @IntDef(flag = true, prefix = { "WINDOW_STATE_" }, value = { 227 WINDOW_STATE_SHOWING, 228 WINDOW_STATE_HIDING, 229 WINDOW_STATE_HIDDEN 230 }) 231 @Retention(RetentionPolicy.SOURCE) 232 public @interface WindowVisibleState {} 233 234 /** @hide */ 235 public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0; 236 /** @hide */ 237 public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1; 238 /** @hide */ 239 public static final int CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = 2; 240 /** @hide */ 241 public static final int CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE = 3; 242 243 /** 244 * Session flag for {@link #registerSessionListener} indicating the listener 245 * is interested in sessions on the keygaurd. 246 * Keyguard Session Boundaries: 247 * START_SESSION: device starts going to sleep OR the keyguard is newly shown 248 * END_SESSION: device starts going to sleep OR keyguard is no longer showing 249 * @hide 250 */ 251 public static final int SESSION_KEYGUARD = 1 << 0; 252 253 /** 254 * Session flag for {@link #registerSessionListener} indicating the current session 255 * is interested in session on the biometric prompt. 256 * @hide 257 */ 258 public static final int SESSION_BIOMETRIC_PROMPT = 1 << 1; 259 260 /** @hide */ 261 public static final Set<Integer> ALL_SESSIONS = Set.of( 262 SESSION_KEYGUARD, 263 SESSION_BIOMETRIC_PROMPT 264 ); 265 266 /** @hide */ 267 @Retention(RetentionPolicy.SOURCE) 268 @IntDef(flag = true, prefix = { "SESSION_KEYGUARD" }, value = { 269 SESSION_KEYGUARD, 270 SESSION_BIOMETRIC_PROMPT, 271 }) 272 public @interface SessionFlags {} 273 274 /** 275 * Response indicating that the tile was not added. 276 */ 277 public static final int TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED = 0; 278 /** 279 * Response indicating that the tile was already added and the user was not prompted. 280 */ 281 public static final int TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED = 1; 282 /** 283 * Response indicating that the tile was added. 284 */ 285 public static final int TILE_ADD_REQUEST_RESULT_TILE_ADDED = 2; 286 /** @hide */ 287 public static final int TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED = 3; 288 289 /** 290 * Values greater or equal to this value indicate an error in the request. 291 */ 292 private static final int TILE_ADD_REQUEST_FIRST_ERROR_CODE = 1000; 293 294 /** 295 * Indicates that this package does not match that of the 296 * {@link android.service.quicksettings.TileService}. 297 */ 298 public static final int TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE = 299 TILE_ADD_REQUEST_FIRST_ERROR_CODE; 300 /** 301 * Indicates that there's a request in progress for this package. 302 */ 303 public static final int TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS = 304 TILE_ADD_REQUEST_FIRST_ERROR_CODE + 1; 305 /** 306 * Indicates that the component does not match an enabled exported 307 * {@link android.service.quicksettings.TileService} for the current user. 308 */ 309 public static final int TILE_ADD_REQUEST_ERROR_BAD_COMPONENT = 310 TILE_ADD_REQUEST_FIRST_ERROR_CODE + 2; 311 /** 312 * Indicates that the user is not the current user. 313 */ 314 public static final int TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER = 315 TILE_ADD_REQUEST_FIRST_ERROR_CODE + 3; 316 /** 317 * Indicates that the requesting application is not in the foreground. 318 */ 319 public static final int TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND = 320 TILE_ADD_REQUEST_FIRST_ERROR_CODE + 4; 321 /** 322 * The request could not be processed because no fulfilling service was found. This could be 323 * a temporary issue (for example, SystemUI has crashed). 324 */ 325 public static final int TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE = 326 TILE_ADD_REQUEST_FIRST_ERROR_CODE + 5; 327 328 /** @hide */ 329 @IntDef(prefix = {"TILE_ADD_REQUEST"}, value = { 330 TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED, 331 TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED, 332 TILE_ADD_REQUEST_RESULT_TILE_ADDED, 333 TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE, 334 TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS, 335 TILE_ADD_REQUEST_ERROR_BAD_COMPONENT, 336 TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER, 337 TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND, 338 TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE 339 }) 340 @Retention(RetentionPolicy.SOURCE) 341 public @interface RequestResult {} 342 343 /** 344 * Constant for {@link #setNavBarMode(int)} indicating the default navbar mode. 345 * 346 * @hide 347 */ 348 @SystemApi 349 public static final int NAV_BAR_MODE_DEFAULT = 0; 350 351 /** 352 * Constant for {@link #setNavBarMode(int)} indicating kids navbar mode. 353 * 354 * <p>When used, back and home icons will change drawables and layout, recents will be hidden, 355 * and enables the setting to force navbar visible, even when apps are in immersive mode. 356 * 357 * @hide 358 */ 359 @SystemApi 360 public static final int NAV_BAR_MODE_KIDS = 1; 361 362 /** @hide */ 363 @IntDef(prefix = {"NAV_BAR_MODE_"}, value = { 364 NAV_BAR_MODE_DEFAULT, 365 NAV_BAR_MODE_KIDS 366 }) 367 @Retention(RetentionPolicy.SOURCE) 368 public @interface NavBarMode {} 369 370 /** 371 * State indicating that this sender device is close to a receiver device, so the user can 372 * potentially *start* a cast to the receiver device if the user moves their device a bit 373 * closer. 374 * <p> 375 * Important notes: 376 * <ul> 377 * <li>This state represents that the device is close enough to inform the user that 378 * transferring is an option, but the device is *not* close enough to actually initiate a 379 * transfer yet.</li> 380 * <li>This state is for *starting* a cast. It should be used when this device is currently 381 * playing media locally and the media should be transferred to be played on the receiver 382 * device instead.</li> 383 * </ul> 384 * 385 * @hide 386 */ 387 @SystemApi 388 public static final int MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST = 0; 389 390 /** 391 * State indicating that this sender device is close to a receiver device, so the user can 392 * potentially *end* a cast on the receiver device if the user moves this device a bit closer. 393 * <p> 394 * Important notes: 395 * <ul> 396 * <li>This state represents that the device is close enough to inform the user that 397 * transferring is an option, but the device is *not* close enough to actually initiate a 398 * transfer yet.</li> 399 * <li>This state is for *ending* a cast. It should be used when media is currently being 400 * played on the receiver device and the media should be transferred to play locally 401 * instead.</li> 402 * </ul> 403 * 404 * @hide 405 */ 406 @SystemApi 407 public static final int MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST = 1; 408 409 /** 410 * State indicating that a media transfer from this sender device to a receiver device has been 411 * started. 412 * <p> 413 * Important note: This state is for *starting* a cast. It should be used when this device is 414 * currently playing media locally and the media has started being transferred to the receiver 415 * device instead. 416 * 417 * @hide 418 */ 419 @SystemApi 420 public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED = 2; 421 422 /** 423 * State indicating that a media transfer from the receiver and back to this sender device 424 * has been started. 425 * <p> 426 * Important note: This state is for *ending* a cast. It should be used when media is currently 427 * being played on the receiver device and the media has started being transferred to play 428 * locally instead. 429 * 430 * @hide 431 */ 432 @SystemApi 433 public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED = 3; 434 435 /** 436 * State indicating that a media transfer from this sender device to a receiver device has 437 * finished successfully. 438 * <p> 439 * Important note: This state is for *starting* a cast. It should be used when this device had 440 * previously been playing media locally and the media has successfully been transferred to the 441 * receiver device instead. 442 * 443 * @hide 444 */ 445 @SystemApi 446 public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED = 4; 447 448 /** 449 * State indicating that a media transfer from the receiver and back to this sender device has 450 * finished successfully. 451 * <p> 452 * Important note: This state is for *ending* a cast. It should be used when media was 453 * previously being played on the receiver device and has been successfully transferred to play 454 * locally on this device instead. 455 * 456 * @hide 457 */ 458 @SystemApi 459 public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED = 5; 460 461 /** 462 * State indicating that the attempted transfer to the receiver device has failed. 463 * 464 * @hide 465 */ 466 @SystemApi 467 public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED = 6; 468 469 /** 470 * State indicating that the attempted transfer back to this device has failed. 471 * 472 * @hide 473 */ 474 @SystemApi 475 public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED = 7; 476 477 /** 478 * State indicating that this sender device is no longer close to the receiver device. 479 * 480 * @hide 481 */ 482 @SystemApi 483 public static final int MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER = 8; 484 485 /** @hide */ 486 @IntDef(prefix = {"MEDIA_TRANSFER_SENDER_STATE_"}, value = { 487 MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 488 MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 489 MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, 490 MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, 491 MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 492 MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 493 MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED, 494 MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED, 495 MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 496 }) 497 @Retention(RetentionPolicy.SOURCE) 498 public @interface MediaTransferSenderState {} 499 500 /** 501 * State indicating that this receiver device is close to a sender device, so the user can 502 * potentially start or end a cast to the receiver device if the user moves the sender device a 503 * bit closer. 504 * <p> 505 * Important note: This state represents that the device is close enough to inform the user that 506 * transferring is an option, but the device is *not* close enough to actually initiate a 507 * transfer yet. 508 * 509 * @hide 510 */ 511 @SystemApi 512 public static final int MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER = 0; 513 514 /** 515 * State indicating that this receiver device is no longer close to the sender device. 516 * 517 * @hide 518 */ 519 @SystemApi 520 public static final int MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER = 1; 521 522 /** 523 * State indicating that media transfer to this receiver device is succeeded. 524 * 525 * @hide 526 */ 527 @SystemApi 528 public static final int MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED = 2; 529 530 /** 531 * State indicating that media transfer to this receiver device is failed. 532 * 533 * @hide 534 */ 535 @SystemApi 536 public static final int MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_FAILED = 3; 537 538 /** @hide */ 539 @IntDef(prefix = {"MEDIA_TRANSFER_RECEIVER_STATE_"}, value = { 540 MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, 541 MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER, 542 MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 543 MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_FAILED, 544 }) 545 @Retention(RetentionPolicy.SOURCE) 546 public @interface MediaTransferReceiverState {} 547 548 /** 549 * A map from a provider registered in 550 * {@link #registerNearbyMediaDevicesProvider(NearbyMediaDevicesProvider)} to the wrapper 551 * around the provider that was created internally. We need the wrapper to make the provider 552 * binder-compatible, and we need to store a reference to the wrapper so that when the provider 553 * is un-registered, we un-register the saved wrapper instance. 554 */ 555 private final Map<NearbyMediaDevicesProvider, NearbyMediaDevicesProviderWrapper> 556 nearbyMediaDevicesProviderMap = new HashMap<>(); 557 558 /** 559 * Media controls based on {@link android.app.Notification.MediaStyle} notifications will have 560 * actions based on the media session's {@link android.media.session.PlaybackState}, rather than 561 * the notification's actions. 562 * 563 * These actions will be: 564 * - Play/Pause (depending on whether the current state is a playing state) 565 * - Previous (if declared), or a custom action if the slot is not reserved with 566 * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV} 567 * - Next (if declared), or a custom action if the slot is not reserved with 568 * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT} 569 * - Custom action 570 * - Custom action 571 * 572 * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV 573 * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT 574 */ 575 @ChangeId 576 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) 577 private static final long MEDIA_CONTROL_SESSION_ACTIONS = 203800354L; 578 579 /** 580 * Media controls based on {@link android.app.Notification.MediaStyle} notifications should 581 * include a non-empty title, either in the {@link android.media.MediaMetadata} or 582 * notification title. 583 */ 584 @ChangeId 585 @LoggingOnly 586 private static final long MEDIA_CONTROL_BLANK_TITLE = 274775190L; 587 588 @UnsupportedAppUsage 589 private Context mContext; 590 private IStatusBarService mService; 591 @UnsupportedAppUsage 592 private IBinder mToken = new Binder(); 593 594 private final IPlatformCompat mPlatformCompat = IPlatformCompat.Stub.asInterface( 595 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); 596 597 @UnsupportedAppUsage StatusBarManager(Context context)598 StatusBarManager(Context context) { 599 mContext = context; 600 } 601 602 @UnsupportedAppUsage getService()603 private synchronized IStatusBarService getService() { 604 if (mService == null) { 605 mService = IStatusBarService.Stub.asInterface( 606 ServiceManager.getService(Context.STATUS_BAR_SERVICE)); 607 if (mService == null) { 608 Slog.w(TAG, "warning: no STATUS_BAR_SERVICE"); 609 } 610 } 611 return mService; 612 } 613 614 /** 615 * Disable some features in the status bar. Pass the bitwise-or of the DISABLE_* flags. 616 * To re-enable everything, pass {@link #DISABLE_NONE}. 617 * 618 * @hide 619 */ 620 @UnsupportedAppUsage disable(int what)621 public void disable(int what) { 622 try { 623 final int userId = Binder.getCallingUserHandle().getIdentifier(); 624 final IStatusBarService svc = getService(); 625 if (svc != null) { 626 svc.disableForUser(what, mToken, mContext.getPackageName(), userId); 627 } 628 } catch (RemoteException ex) { 629 throw ex.rethrowFromSystemServer(); 630 } 631 } 632 633 /** 634 * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags. 635 * To re-enable everything, pass {@link #DISABLE_NONE}. 636 * 637 * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. 638 * 639 * @hide 640 */ disable2(@isable2Flags int what)641 public void disable2(@Disable2Flags int what) { 642 try { 643 final int userId = Binder.getCallingUserHandle().getIdentifier(); 644 final IStatusBarService svc = getService(); 645 if (svc != null) { 646 svc.disable2ForUser(what, mToken, mContext.getPackageName(), userId); 647 } 648 } catch (RemoteException ex) { 649 throw ex.rethrowFromSystemServer(); 650 } 651 } 652 653 /** 654 * Simulate notification click for testing 655 * 656 * @hide 657 */ 658 @TestApi clickNotification(@ullable String key, int rank, int count, boolean visible)659 public void clickNotification(@Nullable String key, int rank, int count, boolean visible) { 660 clickNotificationInternal(key, rank, count, visible); 661 } 662 clickNotificationInternal(String key, int rank, int count, boolean visible)663 private void clickNotificationInternal(String key, int rank, int count, boolean visible) { 664 try { 665 final IStatusBarService svc = getService(); 666 if (svc != null) { 667 svc.onNotificationClick(key, 668 NotificationVisibility.obtain(key, rank, count, visible)); 669 } 670 } catch (RemoteException ex) { 671 throw ex.rethrowFromSystemServer(); 672 } 673 } 674 675 /** 676 * Simulate notification feedback for testing 677 * 678 * @hide 679 */ 680 @TestApi sendNotificationFeedback(@ullable String key, @Nullable Bundle feedback)681 public void sendNotificationFeedback(@Nullable String key, @Nullable Bundle feedback) { 682 try { 683 final IStatusBarService svc = getService(); 684 if (svc != null) { 685 svc.onNotificationFeedbackReceived(key, feedback); 686 } 687 } catch (RemoteException ex) { 688 throw ex.rethrowFromSystemServer(); 689 } 690 } 691 692 /** 693 * Expand the notifications panel. 694 * 695 * @hide 696 */ 697 @UnsupportedAppUsage 698 @TestApi expandNotificationsPanel()699 public void expandNotificationsPanel() { 700 try { 701 final IStatusBarService svc = getService(); 702 if (svc != null) { 703 svc.expandNotificationsPanel(); 704 } 705 } catch (RemoteException ex) { 706 throw ex.rethrowFromSystemServer(); 707 } 708 } 709 710 /** 711 * Collapse the notifications and settings panels. 712 * 713 * Starting in Android {@link Build.VERSION_CODES.S}, apps targeting SDK level {@link 714 * Build.VERSION_CODES.S} or higher will need {@link android.Manifest.permission.STATUS_BAR} 715 * permission to call this API. 716 * 717 * @hide 718 */ 719 @RequiresPermission(android.Manifest.permission.STATUS_BAR) 720 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "This operation" 721 + " is not allowed anymore, please see {@link android.content" 722 + ".Intent#ACTION_CLOSE_SYSTEM_DIALOGS} for more details.") 723 @TestApi collapsePanels()724 public void collapsePanels() { 725 726 try { 727 final IStatusBarService svc = getService(); 728 if (svc != null) { 729 svc.collapsePanels(); 730 } 731 } catch (RemoteException ex) { 732 throw ex.rethrowFromSystemServer(); 733 } 734 } 735 736 /** 737 * Toggles the notification panel. 738 * 739 * @hide 740 */ 741 @RequiresPermission(android.Manifest.permission.STATUS_BAR) 742 @TestApi togglePanel()743 public void togglePanel() { 744 try { 745 final IStatusBarService svc = getService(); 746 if (svc != null) { 747 svc.togglePanel(); 748 } 749 } catch (RemoteException ex) { 750 throw ex.rethrowFromSystemServer(); 751 } 752 } 753 754 /** 755 * Sends system keys to the status bar. 756 * 757 * @hide 758 */ 759 @RequiresPermission(android.Manifest.permission.STATUS_BAR) 760 @TestApi handleSystemKey(@onNull KeyEvent key)761 public void handleSystemKey(@NonNull KeyEvent key) { 762 try { 763 final IStatusBarService svc = getService(); 764 if (svc != null) { 765 svc.handleSystemKey(key); 766 } 767 } catch (RemoteException ex) { 768 throw ex.rethrowFromSystemServer(); 769 } 770 } 771 772 /** 773 * Gets the last handled system key. A system key is a KeyEvent that the 774 * {@link com.android.server.policy.PhoneWindowManager} sends directly to the 775 * status bar, rather than forwarding to apps. If a key has never been sent to the 776 * status bar, will return -1. 777 * 778 * @return the keycode of the last KeyEvent that has been sent to the system. 779 * @hide 780 */ 781 @RequiresPermission(android.Manifest.permission.STATUS_BAR) 782 @TestApi getLastSystemKey()783 public int getLastSystemKey() { 784 try { 785 final IStatusBarService svc = getService(); 786 if (svc != null) { 787 return svc.getLastSystemKey(); 788 } 789 } catch (RemoteException ex) { 790 throw ex.rethrowFromSystemServer(); 791 } 792 return -1; 793 } 794 795 /** 796 * Expand the settings panel. 797 * 798 * @hide 799 */ 800 @UnsupportedAppUsage expandSettingsPanel()801 public void expandSettingsPanel() { 802 expandSettingsPanel(null); 803 } 804 805 /** 806 * Expand the settings panel and open a subPanel. If the subpanel is null or does not have a 807 * corresponding tile, the QS panel is simply expanded 808 * 809 * @hide 810 */ 811 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) expandSettingsPanel(@ullable String subPanel)812 public void expandSettingsPanel(@Nullable String subPanel) { 813 try { 814 final IStatusBarService svc = getService(); 815 if (svc != null) { 816 svc.expandSettingsPanel(subPanel); 817 } 818 } catch (RemoteException ex) { 819 throw ex.rethrowFromSystemServer(); 820 } 821 } 822 823 /** @hide */ 824 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setIcon(String slot, int iconId, int iconLevel, String contentDescription)825 public void setIcon(String slot, int iconId, int iconLevel, String contentDescription) { 826 try { 827 final IStatusBarService svc = getService(); 828 if (svc != null) { 829 svc.setIcon(slot, mContext.getPackageName(), iconId, iconLevel, 830 contentDescription); 831 } 832 } catch (RemoteException ex) { 833 throw ex.rethrowFromSystemServer(); 834 } 835 } 836 837 /** @hide */ 838 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) removeIcon(String slot)839 public void removeIcon(String slot) { 840 try { 841 final IStatusBarService svc = getService(); 842 if (svc != null) { 843 svc.removeIcon(slot); 844 } 845 } catch (RemoteException ex) { 846 throw ex.rethrowFromSystemServer(); 847 } 848 } 849 850 /** @hide */ 851 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setIconVisibility(String slot, boolean visible)852 public void setIconVisibility(String slot, boolean visible) { 853 try { 854 final IStatusBarService svc = getService(); 855 if (svc != null) { 856 svc.setIconVisibility(slot, visible); 857 } 858 } catch (RemoteException ex) { 859 throw ex.rethrowFromSystemServer(); 860 } 861 } 862 863 /** 864 * Enable or disable status bar elements (notifications, clock) which are inappropriate during 865 * device setup. 866 * 867 * @param disabled whether to apply or remove the disabled flags 868 * 869 * @hide 870 */ 871 @SystemApi 872 @RequiresPermission(android.Manifest.permission.STATUS_BAR) setDisabledForSetup(boolean disabled)873 public void setDisabledForSetup(boolean disabled) { 874 try { 875 final int userId = Binder.getCallingUserHandle().getIdentifier(); 876 final IStatusBarService svc = getService(); 877 if (svc != null) { 878 svc.disableForUser(disabled ? DEFAULT_SETUP_DISABLE_FLAGS : DISABLE_NONE, 879 mToken, mContext.getPackageName(), userId); 880 svc.disable2ForUser(disabled ? DEFAULT_SETUP_DISABLE2_FLAGS : DISABLE2_NONE, 881 mToken, mContext.getPackageName(), userId); 882 } 883 } catch (RemoteException ex) { 884 throw ex.rethrowFromSystemServer(); 885 } 886 } 887 888 /** 889 * Enable or disable expansion of the status bar. When the device is SIM-locked, the status 890 * bar should not be expandable. 891 * 892 * @param disabled If {@code true}, the status bar will be set to non-expandable. If 893 * {@code false}, re-enables expansion of the status bar. 894 * @hide 895 */ 896 @TestApi 897 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 898 @RequiresPermission(android.Manifest.permission.STATUS_BAR) setExpansionDisabledForSimNetworkLock(boolean disabled)899 public void setExpansionDisabledForSimNetworkLock(boolean disabled) { 900 try { 901 final int userId = Binder.getCallingUserHandle().getIdentifier(); 902 final IStatusBarService svc = getService(); 903 if (svc != null) { 904 svc.disableForUser(disabled ? DEFAULT_SIM_LOCKED_DISABLED_FLAGS : DISABLE_NONE, 905 mToken, mContext.getPackageName(), userId); 906 } 907 } catch (RemoteException ex) { 908 throw ex.rethrowFromSystemServer(); 909 } 910 } 911 912 /** 913 * Get this app's currently requested disabled components 914 * 915 * @return a new DisableInfo 916 * 917 * @hide 918 */ 919 @SystemApi 920 @RequiresPermission(android.Manifest.permission.STATUS_BAR) 921 @NonNull getDisableInfo()922 public DisableInfo getDisableInfo() { 923 try { 924 final int userId = Binder.getCallingUserHandle().getIdentifier(); 925 final IStatusBarService svc = getService(); 926 int[] flags = new int[] {0, 0}; 927 if (svc != null) { 928 flags = svc.getDisableFlags(mToken, userId); 929 } 930 931 return new DisableInfo(flags[0], flags[1]); 932 } catch (RemoteException ex) { 933 throw ex.rethrowFromSystemServer(); 934 } 935 } 936 937 /** 938 * Sets an active {@link android.service.quicksettings.TileService} to listening state 939 * 940 * The {@code componentName}'s package must match the calling package. 941 * 942 * @param componentName the tile to set into listening state 943 * @see android.service.quicksettings.TileService#requestListeningState 944 * @hide 945 */ requestTileServiceListeningState(@onNull ComponentName componentName)946 public void requestTileServiceListeningState(@NonNull ComponentName componentName) { 947 Objects.requireNonNull(componentName); 948 try { 949 getService().requestTileServiceListeningState(componentName, mContext.getUserId()); 950 } catch (RemoteException ex) { 951 throw ex.rethrowFromSystemServer(); 952 } 953 } 954 955 /** 956 * Request to the user to add a {@link android.service.quicksettings.TileService} 957 * to the set of current QS tiles. 958 * <p> 959 * Calling this will prompt the user to decide whether they want to add the shown 960 * {@link android.service.quicksettings.TileService} to their current tiles. The user can 961 * deny the request and the system can stop processing requests for a given 962 * {@link ComponentName} after a number of requests. 963 * <p> 964 * The request will show to the user information about the tile: 965 * <ul> 966 * <li>Application name</li> 967 * <li>Label for the tile</li> 968 * <li>Icon for the tile</li> 969 * </ul> 970 * <p> 971 * The user for which this will be added is determined from the {@link Context} used to retrieve 972 * this service, and must match the current user. The requesting application must be in the 973 * foreground ({@link ActivityManager.RunningAppProcessInfo#IMPORTANCE_FOREGROUND} 974 * and the {@link android.service.quicksettings.TileService} must be exported. 975 * 976 * Note: the system can choose to auto-deny a request if the user has denied that specific 977 * request (user, ComponentName) enough times before. 978 * 979 * @param tileServiceComponentName {@link ComponentName} of the 980 * {@link android.service.quicksettings.TileService} for the request. 981 * @param tileLabel label of the tile to show to the user. 982 * @param icon icon to use in the tile shown to the user. 983 * @param resultExecutor an executor to run the callback on 984 * @param resultCallback callback to indicate the result of the request. 985 * 986 * @see android.service.quicksettings.TileService 987 */ requestAddTileService( @onNull ComponentName tileServiceComponentName, @NonNull CharSequence tileLabel, @NonNull Icon icon, @NonNull Executor resultExecutor, @NonNull Consumer<Integer> resultCallback )988 public void requestAddTileService( 989 @NonNull ComponentName tileServiceComponentName, 990 @NonNull CharSequence tileLabel, 991 @NonNull Icon icon, 992 @NonNull Executor resultExecutor, 993 @NonNull Consumer<Integer> resultCallback 994 ) { 995 Objects.requireNonNull(tileServiceComponentName); 996 Objects.requireNonNull(tileLabel); 997 Objects.requireNonNull(icon); 998 Objects.requireNonNull(resultExecutor); 999 Objects.requireNonNull(resultCallback); 1000 if (!tileServiceComponentName.getPackageName().equals(mContext.getPackageName())) { 1001 resultExecutor.execute( 1002 () -> resultCallback.accept(TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE)); 1003 return; 1004 } 1005 int userId = mContext.getUserId(); 1006 RequestResultCallback callbackProxy = new RequestResultCallback(resultExecutor, 1007 resultCallback); 1008 IStatusBarService svc = getService(); 1009 try { 1010 svc.requestAddTile( 1011 tileServiceComponentName, 1012 tileLabel, 1013 icon, 1014 userId, 1015 callbackProxy 1016 ); 1017 } catch (RemoteException ex) { 1018 ex.rethrowFromSystemServer(); 1019 } 1020 } 1021 1022 /** 1023 * @hide 1024 * @param packageName 1025 */ 1026 @TestApi cancelRequestAddTile(@onNull String packageName)1027 public void cancelRequestAddTile(@NonNull String packageName) { 1028 Objects.requireNonNull(packageName); 1029 IStatusBarService svc = getService(); 1030 try { 1031 svc.cancelRequestAddTile(packageName); 1032 } catch (RemoteException e) { 1033 e.rethrowFromSystemServer(); 1034 } 1035 } 1036 1037 /** 1038 * Sets or removes the navigation bar mode. 1039 * 1040 * @param navBarMode the mode of the navigation bar to be set. 1041 * 1042 * @hide 1043 */ 1044 @SystemApi 1045 @RequiresPermission(android.Manifest.permission.STATUS_BAR) setNavBarMode(@avBarMode int navBarMode)1046 public void setNavBarMode(@NavBarMode int navBarMode) { 1047 if (navBarMode != NAV_BAR_MODE_DEFAULT && navBarMode != NAV_BAR_MODE_KIDS) { 1048 throw new IllegalArgumentException("Supplied navBarMode not supported: " + navBarMode); 1049 } 1050 1051 try { 1052 final IStatusBarService svc = getService(); 1053 if (svc != null) { 1054 svc.setNavBarMode(navBarMode); 1055 } 1056 } catch (RemoteException e) { 1057 throw e.rethrowFromSystemServer(); 1058 } 1059 } 1060 1061 /** 1062 * Gets the navigation bar mode. Returns default value if no mode is set. 1063 * 1064 * @hide 1065 */ 1066 @SystemApi 1067 @RequiresPermission(android.Manifest.permission.STATUS_BAR) getNavBarMode()1068 public @NavBarMode int getNavBarMode() { 1069 int navBarMode = NAV_BAR_MODE_DEFAULT; 1070 try { 1071 final IStatusBarService svc = getService(); 1072 if (svc != null) { 1073 navBarMode = svc.getNavBarMode(); 1074 } 1075 } catch (RemoteException e) { 1076 throw e.rethrowFromSystemServer(); 1077 } 1078 return navBarMode; 1079 } 1080 1081 /** 1082 * Notifies the system of a new media tap-to-transfer state for the <b>sender</b> device. 1083 * 1084 * <p>The callback should only be provided for the {@link 1085 * MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED} or {@link 1086 * MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED} states, since those are the 1087 * only states where an action can be un-done. 1088 * 1089 * @param displayState the new state for media tap-to-transfer. 1090 * @param routeInfo the media route information for the media being transferred. 1091 * @param undoExecutor an executor to run the callback on and must be provided if the 1092 * callback is non-null. 1093 * @param undoCallback a callback that will be triggered if the user elects to undo a media 1094 * transfer. 1095 * 1096 * @throws IllegalArgumentException if an undo callback is provided for states that are not a 1097 * succeeded state. 1098 * @throws IllegalArgumentException if an executor is not provided when a callback is. 1099 * 1100 * @hide 1101 */ 1102 @SystemApi 1103 @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) updateMediaTapToTransferSenderDisplay( @ediaTransferSenderState int displayState, @NonNull MediaRoute2Info routeInfo, @Nullable Executor undoExecutor, @Nullable Runnable undoCallback )1104 public void updateMediaTapToTransferSenderDisplay( 1105 @MediaTransferSenderState int displayState, 1106 @NonNull MediaRoute2Info routeInfo, 1107 @Nullable Executor undoExecutor, 1108 @Nullable Runnable undoCallback 1109 ) { 1110 Objects.requireNonNull(routeInfo); 1111 if (displayState != MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED 1112 && displayState != MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED 1113 && undoCallback != null) { 1114 throw new IllegalArgumentException( 1115 "The undoCallback should only be provided when the state is a " 1116 + "transfer succeeded state"); 1117 } 1118 if (undoCallback != null && undoExecutor == null) { 1119 throw new IllegalArgumentException( 1120 "You must pass an executor when you pass an undo callback"); 1121 } 1122 IStatusBarService svc = getService(); 1123 try { 1124 UndoCallback callbackProxy = null; 1125 if (undoExecutor != null) { 1126 callbackProxy = new UndoCallback(undoExecutor, undoCallback); 1127 } 1128 svc.updateMediaTapToTransferSenderDisplay(displayState, routeInfo, callbackProxy); 1129 } catch (RemoteException e) { 1130 e.rethrowFromSystemServer(); 1131 } 1132 } 1133 1134 /** 1135 * Notifies the system of a new media tap-to-transfer state for the <b>receiver</b> device. 1136 * 1137 * @param displayState the new state for media tap-to-transfer. 1138 * @param routeInfo the media route information for the media being transferred. 1139 * @param appIcon the icon of the app playing the media. 1140 * @param appName the name of the app playing the media. 1141 * 1142 * @hide 1143 */ 1144 @SystemApi 1145 @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) updateMediaTapToTransferReceiverDisplay( @ediaTransferReceiverState int displayState, @NonNull MediaRoute2Info routeInfo, @Nullable Icon appIcon, @Nullable CharSequence appName)1146 public void updateMediaTapToTransferReceiverDisplay( 1147 @MediaTransferReceiverState int displayState, 1148 @NonNull MediaRoute2Info routeInfo, 1149 @Nullable Icon appIcon, 1150 @Nullable CharSequence appName) { 1151 Objects.requireNonNull(routeInfo); 1152 IStatusBarService svc = getService(); 1153 try { 1154 svc.updateMediaTapToTransferReceiverDisplay(displayState, routeInfo, appIcon, appName); 1155 } catch (RemoteException e) { 1156 e.rethrowFromSystemServer(); 1157 } 1158 } 1159 1160 /** 1161 * Registers a provider that notifies callbacks about the status of nearby devices that are able 1162 * to play media. 1163 * <p> 1164 * If multiple providers are registered, all the providers will be used for nearby device 1165 * information. 1166 * <p> 1167 * @param provider the nearby device information provider to register 1168 * <p> 1169 * @hide 1170 */ 1171 @SystemApi 1172 @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) registerNearbyMediaDevicesProvider( @onNull NearbyMediaDevicesProvider provider )1173 public void registerNearbyMediaDevicesProvider( 1174 @NonNull NearbyMediaDevicesProvider provider 1175 ) { 1176 Objects.requireNonNull(provider); 1177 if (nearbyMediaDevicesProviderMap.containsKey(provider)) { 1178 return; 1179 } 1180 try { 1181 final IStatusBarService svc = getService(); 1182 NearbyMediaDevicesProviderWrapper providerWrapper = 1183 new NearbyMediaDevicesProviderWrapper(provider); 1184 nearbyMediaDevicesProviderMap.put(provider, providerWrapper); 1185 svc.registerNearbyMediaDevicesProvider(providerWrapper); 1186 } catch (RemoteException e) { 1187 throw e.rethrowFromSystemServer(); 1188 } 1189 } 1190 1191 /** 1192 * Unregisters a provider that gives information about nearby devices that are able to play 1193 * media. 1194 * <p> 1195 * See {@link registerNearbyMediaDevicesProvider}. 1196 * <p> 1197 * @param provider the nearby device information provider to unregister 1198 * <p> 1199 * @hide 1200 */ 1201 @SystemApi 1202 @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) unregisterNearbyMediaDevicesProvider( @onNull NearbyMediaDevicesProvider provider )1203 public void unregisterNearbyMediaDevicesProvider( 1204 @NonNull NearbyMediaDevicesProvider provider 1205 ) { 1206 Objects.requireNonNull(provider); 1207 if (!nearbyMediaDevicesProviderMap.containsKey(provider)) { 1208 return; 1209 } 1210 try { 1211 final IStatusBarService svc = getService(); 1212 NearbyMediaDevicesProviderWrapper providerWrapper = 1213 nearbyMediaDevicesProviderMap.get(provider); 1214 nearbyMediaDevicesProviderMap.remove(provider); 1215 svc.unregisterNearbyMediaDevicesProvider(providerWrapper); 1216 } catch (RemoteException e) { 1217 throw e.rethrowFromSystemServer(); 1218 } 1219 } 1220 1221 /** 1222 * Checks whether the given package should use session-based actions for its media controls. 1223 * 1224 * @param packageName App posting media controls 1225 * @param user Current user handle 1226 * @return true if the app supports session actions 1227 * 1228 * @hide 1229 */ 1230 @RequiresPermission(allOf = {android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG, 1231 android.Manifest.permission.LOG_COMPAT_CHANGE}) useMediaSessionActionsForApp(String packageName, UserHandle user)1232 public static boolean useMediaSessionActionsForApp(String packageName, UserHandle user) { 1233 return CompatChanges.isChangeEnabled(MEDIA_CONTROL_SESSION_ACTIONS, packageName, user); 1234 } 1235 1236 /** 1237 * Log that the given package has posted media controls with a blank title 1238 * 1239 * @param packageName App posting media controls 1240 * @param userId Current user ID 1241 * @throws RuntimeException if there is an error reporting the change 1242 * 1243 * @hide 1244 */ logBlankMediaTitle(String packageName, @UserIdInt int userId)1245 public void logBlankMediaTitle(String packageName, @UserIdInt int userId) 1246 throws RuntimeException { 1247 try { 1248 mPlatformCompat.reportChangeByPackageName(MEDIA_CONTROL_BLANK_TITLE, packageName, 1249 userId); 1250 } catch (RemoteException e) { 1251 throw e.rethrowFromSystemServer(); 1252 } 1253 } 1254 1255 /** 1256 * Checks whether the supplied activity can {@link Activity#startActivityForResult(Intent, int)} 1257 * a system activity that captures content on the screen to take a screenshot. 1258 * 1259 * <p>Note: The result should not be cached. 1260 * 1261 * <p>The system activity displays an editing tool that allows user to edit the screenshot, save 1262 * it on device, and return the edited screenshot as {@link android.net.Uri} to the calling 1263 * activity. User interaction is required to return the edited screenshot to the calling 1264 * activity. 1265 * 1266 * <p>When {@code true}, callers can use {@link Activity#startActivityForResult(Intent, int)} 1267 * to start start the content capture activity using 1268 * {@link Intent#ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE}. 1269 * 1270 * @param activity Calling activity 1271 * @return true if the activity supports launching the capture content activity for note. 1272 * 1273 * @see Intent#ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE 1274 * @see Manifest.permission#LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE 1275 * @see android.app.role.RoleManager#ROLE_NOTES 1276 */ 1277 @RequiresPermission(Manifest.permission.LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE) canLaunchCaptureContentActivityForNote(@onNull Activity activity)1278 public boolean canLaunchCaptureContentActivityForNote(@NonNull Activity activity) { 1279 Objects.requireNonNull(activity); 1280 IBinder activityToken = activity.getActivityToken(); 1281 int taskId = ActivityClient.getInstance().getTaskForActivity(activityToken, false); 1282 return new AppClipsServiceConnector(mContext) 1283 .canLaunchCaptureContentActivityForNote(taskId); 1284 } 1285 1286 /** @hide */ windowStateToString(int state)1287 public static String windowStateToString(int state) { 1288 if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING"; 1289 if (state == WINDOW_STATE_HIDDEN) return "WINDOW_STATE_HIDDEN"; 1290 if (state == WINDOW_STATE_SHOWING) return "WINDOW_STATE_SHOWING"; 1291 return "WINDOW_STATE_UNKNOWN"; 1292 } 1293 1294 /** 1295 * DisableInfo describes this app's requested state of the StatusBar with regards to which 1296 * components are enabled/disabled 1297 * 1298 * @hide 1299 */ 1300 @SystemApi 1301 public static final class DisableInfo { 1302 1303 private boolean mStatusBarExpansion; 1304 private boolean mNavigateHome; 1305 private boolean mNotificationPeeking; 1306 private boolean mRecents; 1307 private boolean mSearch; 1308 private boolean mSystemIcons; 1309 private boolean mClock; 1310 private boolean mNotificationIcons; 1311 private boolean mRotationSuggestion; 1312 1313 /** @hide */ DisableInfo(int flags1, int flags2)1314 public DisableInfo(int flags1, int flags2) { 1315 mStatusBarExpansion = (flags1 & DISABLE_EXPAND) != 0; 1316 mNavigateHome = (flags1 & DISABLE_HOME) != 0; 1317 mNotificationPeeking = (flags1 & DISABLE_NOTIFICATION_ALERTS) != 0; 1318 mRecents = (flags1 & DISABLE_RECENT) != 0; 1319 mSearch = (flags1 & DISABLE_SEARCH) != 0; 1320 mSystemIcons = (flags1 & DISABLE_SYSTEM_INFO) != 0; 1321 mClock = (flags1 & DISABLE_CLOCK) != 0; 1322 mNotificationIcons = (flags1 & DISABLE_NOTIFICATION_ICONS) != 0; 1323 mRotationSuggestion = (flags2 & DISABLE2_ROTATE_SUGGESTIONS) != 0; 1324 } 1325 1326 /** @hide */ DisableInfo()1327 public DisableInfo() {} 1328 1329 /** 1330 * @return {@code true} if expanding the notification shade is disabled 1331 * 1332 * @hide 1333 */ 1334 @SystemApi isStatusBarExpansionDisabled()1335 public boolean isStatusBarExpansionDisabled() { 1336 return mStatusBarExpansion; 1337 } 1338 1339 /** * @hide */ setStatusBarExpansionDisabled(boolean disabled)1340 public void setStatusBarExpansionDisabled(boolean disabled) { 1341 mStatusBarExpansion = disabled; 1342 } 1343 1344 /** 1345 * @return {@code true} if navigation home is disabled 1346 * 1347 * @hide 1348 */ 1349 @SystemApi isNavigateToHomeDisabled()1350 public boolean isNavigateToHomeDisabled() { 1351 return mNavigateHome; 1352 } 1353 1354 /** * @hide */ setNagivationHomeDisabled(boolean disabled)1355 public void setNagivationHomeDisabled(boolean disabled) { 1356 mNavigateHome = disabled; 1357 } 1358 1359 /** 1360 * @return {@code true} if notification peeking (heads-up notification) is disabled 1361 * 1362 * @hide 1363 */ 1364 @SystemApi isNotificationPeekingDisabled()1365 public boolean isNotificationPeekingDisabled() { 1366 return mNotificationPeeking; 1367 } 1368 1369 /** @hide */ setNotificationPeekingDisabled(boolean disabled)1370 public void setNotificationPeekingDisabled(boolean disabled) { 1371 mNotificationPeeking = disabled; 1372 } 1373 1374 /** 1375 * @return {@code true} if mRecents/overview is disabled 1376 * 1377 * @hide 1378 */ 1379 @SystemApi isRecentsDisabled()1380 public boolean isRecentsDisabled() { 1381 return mRecents; 1382 } 1383 1384 /** @hide */ setRecentsDisabled(boolean disabled)1385 public void setRecentsDisabled(boolean disabled) { 1386 mRecents = disabled; 1387 } 1388 1389 /** 1390 * @return {@code true} if mSearch is disabled 1391 * 1392 * @hide 1393 */ 1394 @SystemApi isSearchDisabled()1395 public boolean isSearchDisabled() { 1396 return mSearch; 1397 } 1398 1399 /** @hide */ setSearchDisabled(boolean disabled)1400 public void setSearchDisabled(boolean disabled) { 1401 mSearch = disabled; 1402 } 1403 1404 /** 1405 * @return {@code true} if system icons are disabled 1406 * 1407 * @hide 1408 */ areSystemIconsDisabled()1409 public boolean areSystemIconsDisabled() { 1410 return mSystemIcons; 1411 } 1412 1413 /** * @hide */ setSystemIconsDisabled(boolean disabled)1414 public void setSystemIconsDisabled(boolean disabled) { 1415 mSystemIcons = disabled; 1416 } 1417 1418 /** 1419 * @return {@code true} if the clock icon is disabled 1420 * 1421 * @hide 1422 */ isClockDisabled()1423 public boolean isClockDisabled() { 1424 return mClock; 1425 } 1426 1427 /** * @hide */ setClockDisabled(boolean disabled)1428 public void setClockDisabled(boolean disabled) { 1429 mClock = disabled; 1430 } 1431 1432 /** 1433 * @return {@code true} if notification icons are disabled 1434 * 1435 * @hide 1436 */ areNotificationIconsDisabled()1437 public boolean areNotificationIconsDisabled() { 1438 return mNotificationIcons; 1439 } 1440 1441 /** * @hide */ setNotificationIconsDisabled(boolean disabled)1442 public void setNotificationIconsDisabled(boolean disabled) { 1443 mNotificationIcons = disabled; 1444 } 1445 1446 /** 1447 * Returns whether the rotation suggestion is disabled. 1448 * 1449 * @hide 1450 */ 1451 @TestApi isRotationSuggestionDisabled()1452 public boolean isRotationSuggestionDisabled() { 1453 return mRotationSuggestion; 1454 } 1455 1456 /** 1457 * @return {@code true} if no components are disabled (default state) 1458 * @hide 1459 */ 1460 @SystemApi areAllComponentsEnabled()1461 public boolean areAllComponentsEnabled() { 1462 return !mStatusBarExpansion && !mNavigateHome && !mNotificationPeeking && !mRecents 1463 && !mSearch && !mSystemIcons && !mClock && !mNotificationIcons 1464 && !mRotationSuggestion; 1465 } 1466 1467 /** @hide */ setEnableAll()1468 public void setEnableAll() { 1469 mStatusBarExpansion = false; 1470 mNavigateHome = false; 1471 mNotificationPeeking = false; 1472 mRecents = false; 1473 mSearch = false; 1474 mSystemIcons = false; 1475 mClock = false; 1476 mNotificationIcons = false; 1477 mRotationSuggestion = false; 1478 } 1479 1480 /** 1481 * @return {@code true} if all status bar components are disabled 1482 * 1483 * @hide 1484 */ areAllComponentsDisabled()1485 public boolean areAllComponentsDisabled() { 1486 return mStatusBarExpansion && mNavigateHome && mNotificationPeeking 1487 && mRecents && mSearch && mSystemIcons && mClock && mNotificationIcons 1488 && mRotationSuggestion; 1489 } 1490 1491 /** @hide */ setDisableAll()1492 public void setDisableAll() { 1493 mStatusBarExpansion = true; 1494 mNavigateHome = true; 1495 mNotificationPeeking = true; 1496 mRecents = true; 1497 mSearch = true; 1498 mSystemIcons = true; 1499 mClock = true; 1500 mNotificationIcons = true; 1501 mRotationSuggestion = true; 1502 } 1503 1504 @NonNull 1505 @Override toString()1506 public String toString() { 1507 StringBuilder sb = new StringBuilder(); 1508 sb.append("DisableInfo: "); 1509 sb.append(" mStatusBarExpansion=").append(mStatusBarExpansion ? "disabled" : "enabled"); 1510 sb.append(" mNavigateHome=").append(mNavigateHome ? "disabled" : "enabled"); 1511 sb.append(" mNotificationPeeking=") 1512 .append(mNotificationPeeking ? "disabled" : "enabled"); 1513 sb.append(" mRecents=").append(mRecents ? "disabled" : "enabled"); 1514 sb.append(" mSearch=").append(mSearch ? "disabled" : "enabled"); 1515 sb.append(" mSystemIcons=").append(mSystemIcons ? "disabled" : "enabled"); 1516 sb.append(" mClock=").append(mClock ? "disabled" : "enabled"); 1517 sb.append(" mNotificationIcons=").append(mNotificationIcons ? "disabled" : "enabled"); 1518 sb.append(" mRotationSuggestion=").append(mRotationSuggestion ? "disabled" : "enabled"); 1519 1520 return sb.toString(); 1521 1522 } 1523 1524 /** 1525 * Convert a DisableInfo to equivalent flags 1526 * @return a pair of equivalent disable flags 1527 * 1528 * @hide 1529 */ toFlags()1530 public Pair<Integer, Integer> toFlags() { 1531 int disable1 = DISABLE_NONE; 1532 int disable2 = DISABLE2_NONE; 1533 1534 if (mStatusBarExpansion) disable1 |= DISABLE_EXPAND; 1535 if (mNavigateHome) disable1 |= DISABLE_HOME; 1536 if (mNotificationPeeking) disable1 |= DISABLE_NOTIFICATION_ALERTS; 1537 if (mRecents) disable1 |= DISABLE_RECENT; 1538 if (mSearch) disable1 |= DISABLE_SEARCH; 1539 if (mSystemIcons) disable1 |= DISABLE_SYSTEM_INFO; 1540 if (mClock) disable1 |= DISABLE_CLOCK; 1541 if (mNotificationIcons) disable1 |= DISABLE_NOTIFICATION_ICONS; 1542 if (mRotationSuggestion) disable2 |= DISABLE2_ROTATE_SUGGESTIONS; 1543 1544 return new Pair<Integer, Integer>(disable1, disable2); 1545 } 1546 } 1547 1548 /** 1549 * @hide 1550 */ 1551 static final class RequestResultCallback extends IAddTileResultCallback.Stub { 1552 1553 @NonNull 1554 private final Executor mExecutor; 1555 @NonNull 1556 private final Consumer<Integer> mCallback; 1557 RequestResultCallback(@onNull Executor executor, @NonNull Consumer<Integer> callback)1558 RequestResultCallback(@NonNull Executor executor, @NonNull Consumer<Integer> callback) { 1559 mExecutor = executor; 1560 mCallback = callback; 1561 } 1562 1563 @Override onTileRequest(int userResponse)1564 public void onTileRequest(int userResponse) { 1565 mExecutor.execute(() -> mCallback.accept(userResponse)); 1566 } 1567 } 1568 1569 /** 1570 * @hide 1571 */ 1572 static final class UndoCallback extends IUndoMediaTransferCallback.Stub { 1573 @NonNull 1574 private final Executor mExecutor; 1575 @NonNull 1576 private final Runnable mCallback; 1577 UndoCallback(@onNull Executor executor, @NonNull Runnable callback)1578 UndoCallback(@NonNull Executor executor, @NonNull Runnable callback) { 1579 mExecutor = executor; 1580 mCallback = callback; 1581 } 1582 1583 @Override onUndoTriggered()1584 public void onUndoTriggered() { 1585 final long callingIdentity = Binder.clearCallingIdentity(); 1586 try { 1587 mExecutor.execute(mCallback); 1588 } finally { 1589 restoreCallingIdentity(callingIdentity); 1590 } 1591 } 1592 } 1593 1594 /** 1595 * @hide 1596 */ 1597 static final class NearbyMediaDevicesProviderWrapper extends INearbyMediaDevicesProvider.Stub { 1598 @NonNull 1599 private final NearbyMediaDevicesProvider mProvider; 1600 // Because we're wrapping a {@link NearbyMediaDevicesProvider} in a binder-compatible 1601 // interface, we also need to wrap the callbacks that the provider receives. We use 1602 // this map to keep track of the original callback and the wrapper callback so that 1603 // unregistering the callback works correctly. 1604 @NonNull 1605 private final Map<INearbyMediaDevicesUpdateCallback, Consumer<List<NearbyDevice>>> 1606 mRegisteredCallbacks = new HashMap<>(); 1607 NearbyMediaDevicesProviderWrapper(@onNull NearbyMediaDevicesProvider provider)1608 NearbyMediaDevicesProviderWrapper(@NonNull NearbyMediaDevicesProvider provider) { 1609 mProvider = provider; 1610 } 1611 1612 @Override registerNearbyDevicesCallback( @onNull INearbyMediaDevicesUpdateCallback callback)1613 public void registerNearbyDevicesCallback( 1614 @NonNull INearbyMediaDevicesUpdateCallback callback) { 1615 Consumer<List<NearbyDevice>> callbackAsConsumer = nearbyDevices -> { 1616 try { 1617 callback.onDevicesUpdated(nearbyDevices); 1618 } catch (RemoteException ex) { 1619 throw ex.rethrowFromSystemServer(); 1620 } 1621 }; 1622 1623 mRegisteredCallbacks.put(callback, callbackAsConsumer); 1624 mProvider.registerNearbyDevicesCallback(callbackAsConsumer); 1625 } 1626 1627 @Override unregisterNearbyDevicesCallback( @onNull INearbyMediaDevicesUpdateCallback callback)1628 public void unregisterNearbyDevicesCallback( 1629 @NonNull INearbyMediaDevicesUpdateCallback callback) { 1630 if (!mRegisteredCallbacks.containsKey(callback)) { 1631 return; 1632 } 1633 mProvider.unregisterNearbyDevicesCallback(mRegisteredCallbacks.get(callback)); 1634 mRegisteredCallbacks.remove(callback); 1635 } 1636 } 1637 } 1638