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