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