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 com.android.server.statusbar; 18 19 import static android.Manifest.permission.CONTROL_DEVICE_STATE; 20 import static android.Manifest.permission.INTERACT_ACROSS_USERS; 21 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; 22 import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS; 23 import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE; 24 import static android.app.StatusBarManager.NAV_BAR_MODE_DEFAULT; 25 import static android.app.StatusBarManager.NAV_BAR_MODE_KIDS; 26 import static android.app.StatusBarManager.NavBarMode; 27 import static android.app.StatusBarManager.SessionFlags; 28 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 29 import static android.view.Display.DEFAULT_DISPLAY; 30 import static android.view.ViewRootImpl.CLIENT_TRANSIENT; 31 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; 32 33 import android.Manifest; 34 import android.annotation.NonNull; 35 import android.annotation.Nullable; 36 import android.annotation.RequiresPermission; 37 import android.annotation.TestApi; 38 import android.app.ActivityManager; 39 import android.app.ActivityManagerInternal; 40 import android.app.ActivityThread; 41 import android.app.ITransientNotificationCallback; 42 import android.app.Notification; 43 import android.app.StatusBarManager; 44 import android.app.compat.CompatChanges; 45 import android.compat.annotation.ChangeId; 46 import android.compat.annotation.EnabledAfter; 47 import android.compat.annotation.EnabledSince; 48 import android.content.ComponentName; 49 import android.content.Context; 50 import android.content.Intent; 51 import android.content.om.IOverlayManager; 52 import android.content.pm.PackageManager; 53 import android.content.pm.PackageManagerInternal; 54 import android.content.pm.ResolveInfo; 55 import android.graphics.drawable.Icon; 56 import android.hardware.biometrics.BiometricAuthenticator.Modality; 57 import android.hardware.biometrics.IBiometricContextListener; 58 import android.hardware.biometrics.IBiometricSysuiReceiver; 59 import android.hardware.biometrics.PromptInfo; 60 import android.hardware.display.DisplayManager; 61 import android.hardware.display.DisplayManager.DisplayListener; 62 import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback; 63 import android.media.INearbyMediaDevicesProvider; 64 import android.media.MediaRoute2Info; 65 import android.net.Uri; 66 import android.os.Binder; 67 import android.os.Build; 68 import android.os.Bundle; 69 import android.os.Handler; 70 import android.os.IBinder; 71 import android.os.PowerManager; 72 import android.os.Process; 73 import android.os.RemoteException; 74 import android.os.ResultReceiver; 75 import android.os.ServiceManager; 76 import android.os.ShellCallback; 77 import android.os.UserHandle; 78 import android.provider.Settings; 79 import android.service.notification.NotificationStats; 80 import android.service.quicksettings.TileService; 81 import android.text.TextUtils; 82 import android.util.ArrayMap; 83 import android.util.IndentingPrintWriter; 84 import android.util.Pair; 85 import android.util.Slog; 86 import android.util.SparseArray; 87 import android.view.KeyEvent; 88 import android.view.WindowInsets; 89 import android.view.WindowInsets.Type.InsetsType; 90 import android.view.WindowInsetsController.Appearance; 91 import android.view.WindowInsetsController.Behavior; 92 93 import com.android.internal.R; 94 import com.android.internal.annotations.GuardedBy; 95 import com.android.internal.annotations.VisibleForTesting; 96 import com.android.internal.inputmethod.SoftInputShowHideReason; 97 import com.android.internal.logging.InstanceId; 98 import com.android.internal.os.TransferPipe; 99 import com.android.internal.statusbar.IAddTileResultCallback; 100 import com.android.internal.statusbar.ISessionListener; 101 import com.android.internal.statusbar.IStatusBar; 102 import com.android.internal.statusbar.IStatusBarService; 103 import com.android.internal.statusbar.IUndoMediaTransferCallback; 104 import com.android.internal.statusbar.LetterboxDetails; 105 import com.android.internal.statusbar.NotificationVisibility; 106 import com.android.internal.statusbar.RegisterStatusBarResult; 107 import com.android.internal.statusbar.StatusBarIcon; 108 import com.android.internal.util.DumpUtils; 109 import com.android.internal.util.GcUtils; 110 import com.android.internal.view.AppearanceRegion; 111 import com.android.server.LocalServices; 112 import com.android.server.UiThread; 113 import com.android.server.inputmethod.InputMethodManagerInternal; 114 import com.android.server.notification.NotificationDelegate; 115 import com.android.server.policy.GlobalActionsProvider; 116 import com.android.server.power.ShutdownCheckPoints; 117 import com.android.server.power.ShutdownThread; 118 import com.android.server.wm.ActivityTaskManagerInternal; 119 120 import java.io.FileDescriptor; 121 import java.io.PrintWriter; 122 import java.util.ArrayList; 123 import java.util.concurrent.TimeUnit; 124 125 /** 126 * A note on locking: We rely on the fact that calls onto mBar are oneway or 127 * if they are local, that they just enqueue messages to not deadlock. 128 */ 129 public class StatusBarManagerService extends IStatusBarService.Stub implements DisplayListener { 130 private static final String TAG = "StatusBarManagerService"; 131 private static final boolean SPEW = false; 132 133 /** 134 * Apps targeting {@code Build.VERSION_CODES.S} or higher need {@link 135 * android.Manifest.permission#STATUS_BAR} permission to collapse the status bar panels due to 136 * security reasons. 137 * 138 * This was being exploited by malware to prevent the user from accessing critical 139 * notifications. 140 */ 141 @ChangeId 142 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S) 143 private static final long LOCK_DOWN_COLLAPSE_STATUS_BAR = 173031413L; 144 145 /** 146 * In apps targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher, calling 147 * {@link android.service.quicksettings.TileService#requestListeningState} will check that the 148 * calling package (uid) and the package of the target {@link android.content.ComponentName} 149 * match. It'll also make sure that the context used can take actions on behalf of the current 150 * user. 151 */ 152 @ChangeId 153 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) 154 static final long REQUEST_LISTENING_MUST_MATCH_PACKAGE = 172251878L; 155 156 /** 157 * @hide 158 */ 159 @ChangeId 160 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) 161 static final long REQUEST_LISTENING_OTHER_USER_NOOP = 242194868L; 162 163 private final Context mContext; 164 165 private final Handler mHandler = new Handler(); 166 private NotificationDelegate mNotificationDelegate; 167 private volatile IStatusBar mBar; 168 private final ArrayMap<String, StatusBarIcon> mIcons = new ArrayMap<>(); 169 170 // for disabling the status bar 171 private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>(); 172 private GlobalActionsProvider.GlobalActionsListener mGlobalActionListener; 173 private final IBinder mSysUiVisToken = new Binder(); 174 175 private final Object mLock = new Object(); 176 private final DeathRecipient mDeathRecipient = new DeathRecipient(); 177 private final ActivityManagerInternal mActivityManagerInternal; 178 private final ActivityTaskManagerInternal mActivityTaskManager; 179 private final PackageManagerInternal mPackageManagerInternal; 180 private final SessionMonitor mSessionMonitor; 181 private int mCurrentUserId; 182 private boolean mTracingEnabled; 183 private int mLastSystemKey = -1; 184 185 private final TileRequestTracker mTileRequestTracker; 186 187 private final SparseArray<UiState> mDisplayUiState = new SparseArray<>(); 188 @GuardedBy("mLock") 189 private IUdfpsRefreshRateRequestCallback mUdfpsRefreshRateRequestCallback; 190 @GuardedBy("mLock") 191 private IBiometricContextListener mBiometricContextListener; 192 193 @GuardedBy("mCurrentRequestAddTilePackages") 194 private final ArrayMap<String, Long> mCurrentRequestAddTilePackages = new ArrayMap<>(); 195 private static final long REQUEST_TIME_OUT = TimeUnit.MINUTES.toNanos(5); 196 197 private IOverlayManager mOverlayManager; 198 199 private class DeathRecipient implements IBinder.DeathRecipient { binderDied()200 public void binderDied() { 201 mBar.asBinder().unlinkToDeath(this,0); 202 mBar = null; 203 notifyBarAttachChanged(); 204 } 205 linkToDeath()206 public void linkToDeath() { 207 try { 208 mBar.asBinder().linkToDeath(mDeathRecipient,0); 209 } catch (RemoteException e) { 210 Slog.e(TAG,"Unable to register Death Recipient for status bar", e); 211 } 212 } 213 214 } 215 216 private class DisableRecord implements IBinder.DeathRecipient { 217 int userId; 218 String pkg; 219 int what1; 220 int what2; 221 IBinder token; 222 DisableRecord(int userId, IBinder token)223 public DisableRecord(int userId, IBinder token) { 224 this.userId = userId; 225 this.token = token; 226 try { 227 token.linkToDeath(this, 0); 228 } catch (RemoteException re) { 229 // Give up 230 } 231 } 232 233 @Override binderDied()234 public void binderDied() { 235 Slog.i(TAG, "binder died for pkg=" + pkg); 236 disableForUser(0, token, pkg, userId); 237 disable2ForUser(0, token, pkg, userId); 238 token.unlinkToDeath(this, 0); 239 } 240 setFlags(int what, int which, String pkg)241 public void setFlags(int what, int which, String pkg) { 242 switch (which) { 243 case 1: 244 what1 = what; 245 break; 246 case 2: 247 what2 = what; 248 break; 249 default: 250 Slog.w(TAG, "Can't set unsupported disable flag " + which 251 + ": 0x" + Integer.toHexString(what)); 252 break; 253 } 254 this.pkg = pkg; 255 } 256 getFlags(int which)257 public int getFlags(int which) { 258 switch (which) { 259 case 1: return what1; 260 case 2: return what2; 261 default: 262 Slog.w(TAG, "Can't get unsupported disable flag " + which); 263 return 0; 264 } 265 } 266 isEmpty()267 public boolean isEmpty() { 268 return what1 == 0 && what2 == 0; 269 } 270 271 @Override toString()272 public String toString() { 273 return String.format("userId=%d what1=0x%08X what2=0x%08X pkg=%s token=%s", 274 userId, what1, what2, pkg, token); 275 } 276 } 277 278 /** 279 * Construct the service 280 */ StatusBarManagerService(Context context)281 public StatusBarManagerService(Context context) { 282 mContext = context; 283 284 LocalServices.addService(StatusBarManagerInternal.class, mInternalService); 285 286 // We always have a default display. 287 final UiState state = new UiState(); 288 mDisplayUiState.put(DEFAULT_DISPLAY, state); 289 290 final DisplayManager displayManager = 291 (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 292 displayManager.registerDisplayListener(this, mHandler); 293 mActivityTaskManager = LocalServices.getService(ActivityTaskManagerInternal.class); 294 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); 295 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); 296 297 mTileRequestTracker = new TileRequestTracker(mContext); 298 mSessionMonitor = new SessionMonitor(mContext); 299 } 300 301 /** 302 * Publish the {@link GlobalActionsProvider}. 303 */ 304 // TODO(b/259420401): investigate if we can extract GlobalActionsProvider to its own system 305 // service. publishGlobalActionsProvider()306 public void publishGlobalActionsProvider() { 307 if (LocalServices.getService(GlobalActionsProvider.class) == null) { 308 LocalServices.addService(GlobalActionsProvider.class, mGlobalActionsProvider); 309 } 310 } 311 getOverlayManager()312 private IOverlayManager getOverlayManager() { 313 // No need to synchronize; worst-case scenario it will be fetched twice. 314 if (mOverlayManager == null) { 315 mOverlayManager = IOverlayManager.Stub.asInterface( 316 ServiceManager.getService(Context.OVERLAY_SERVICE)); 317 if (mOverlayManager == null) { 318 Slog.w("StatusBarManager", "warning: no OVERLAY_SERVICE"); 319 } 320 } 321 return mOverlayManager; 322 } 323 324 @Override onDisplayAdded(int displayId)325 public void onDisplayAdded(int displayId) {} 326 327 @Override onDisplayRemoved(int displayId)328 public void onDisplayRemoved(int displayId) { 329 synchronized (mLock) { 330 mDisplayUiState.remove(displayId); 331 } 332 } 333 334 @Override onDisplayChanged(int displayId)335 public void onDisplayChanged(int displayId) {} 336 337 /** 338 * Private API used by NotificationManagerService. 339 */ 340 private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() { 341 private boolean mNotificationLightOn; 342 343 @Override 344 public void setNotificationDelegate(NotificationDelegate delegate) { 345 mNotificationDelegate = delegate; 346 } 347 348 @Override 349 public void showScreenPinningRequest(int taskId) { 350 IStatusBar bar = mBar; 351 if (bar != null) { 352 try { 353 bar.showScreenPinningRequest(taskId); 354 } catch (RemoteException e) { 355 } 356 } 357 } 358 359 @Override 360 public void showAssistDisclosure() { 361 IStatusBar bar = mBar; 362 if (bar != null) { 363 try { 364 bar.showAssistDisclosure(); 365 } catch (RemoteException e) { 366 } 367 } 368 } 369 370 @Override 371 public void startAssist(Bundle args) { 372 IStatusBar bar = mBar; 373 if (bar != null) { 374 try { 375 bar.startAssist(args); 376 } catch (RemoteException e) { 377 } 378 } 379 } 380 381 @Override 382 public void onCameraLaunchGestureDetected(int source) { 383 IStatusBar bar = mBar; 384 if (bar != null) { 385 try { 386 bar.onCameraLaunchGestureDetected(source); 387 } catch (RemoteException e) { 388 } 389 } 390 } 391 392 /** 393 * Notifies the status bar that a Emergency Action launch gesture has been detected. 394 * 395 * TODO (b/169175022) Update method name and docs when feature name is locked. 396 */ 397 @Override 398 public void onEmergencyActionLaunchGestureDetected() { 399 if (SPEW) Slog.d(TAG, "Launching emergency action"); 400 IStatusBar bar = mBar; 401 if (bar != null) { 402 try { 403 bar.onEmergencyActionLaunchGestureDetected(); 404 } catch (RemoteException e) { 405 if (SPEW) Slog.d(TAG, "Failed to launch emergency action"); 406 } 407 } 408 } 409 410 @Override 411 public void setDisableFlags(int displayId, int flags, String cause) { 412 StatusBarManagerService.this.setDisableFlags(displayId, flags, cause); 413 } 414 415 @Override 416 public void toggleSplitScreen() { 417 enforceStatusBarService(); 418 IStatusBar bar = mBar; 419 if (bar != null) { 420 try { 421 bar.toggleSplitScreen(); 422 } catch (RemoteException ex) {} 423 } 424 } 425 426 @Override 427 public void appTransitionFinished(int displayId) { 428 enforceStatusBarService(); 429 IStatusBar bar = mBar; 430 if (bar != null) { 431 try { 432 bar.appTransitionFinished(displayId); 433 } catch (RemoteException ex) {} 434 } 435 } 436 437 @Override 438 public void toggleTaskbar() { 439 IStatusBar bar = mBar; 440 if (bar != null) { 441 try { 442 bar.toggleTaskbar(); 443 } catch (RemoteException ex) {} 444 } 445 } 446 447 @Override 448 public void toggleRecentApps() { 449 IStatusBar bar = mBar; 450 if (bar != null) { 451 try { 452 bar.toggleRecentApps(); 453 } catch (RemoteException ex) {} 454 } 455 } 456 457 @Override 458 public void setCurrentUser(int newUserId) { 459 if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId); 460 mCurrentUserId = newUserId; 461 } 462 463 464 @Override 465 public void preloadRecentApps() { 466 IStatusBar bar = mBar; 467 if (bar != null) { 468 try { 469 bar.preloadRecentApps(); 470 } catch (RemoteException ex) {} 471 } 472 } 473 474 @Override 475 public void cancelPreloadRecentApps() { 476 IStatusBar bar = mBar; 477 if (bar != null) { 478 try { 479 bar.cancelPreloadRecentApps(); 480 } catch (RemoteException ex) {} 481 } 482 } 483 484 @Override 485 public void showRecentApps(boolean triggeredFromAltTab) { 486 IStatusBar bar = mBar; 487 if (bar != null) { 488 try { 489 bar.showRecentApps(triggeredFromAltTab); 490 } catch (RemoteException ex) {} 491 } 492 } 493 494 @Override 495 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 496 IStatusBar bar = mBar; 497 if (bar != null) { 498 try { 499 bar.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey); 500 } catch (RemoteException ex) {} 501 } 502 } 503 504 @Override 505 public void collapsePanels() { 506 IStatusBar bar = mBar; 507 if (bar != null) { 508 try { 509 bar.animateCollapsePanels(); 510 } catch (RemoteException ex) { 511 } 512 } 513 } 514 515 @Override 516 public void dismissKeyboardShortcutsMenu() { 517 IStatusBar bar = mBar; 518 if (bar != null) { 519 try { 520 bar.dismissKeyboardShortcutsMenu(); 521 } catch (RemoteException ex) {} 522 } 523 } 524 525 @Override 526 public void toggleKeyboardShortcutsMenu(int deviceId) { 527 IStatusBar bar = mBar; 528 if (bar != null) { 529 try { 530 bar.toggleKeyboardShortcutsMenu(deviceId); 531 } catch (RemoteException ex) {} 532 } 533 } 534 535 @Override 536 public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, 537 boolean showImeSwitcher) { 538 StatusBarManagerService.this.setImeWindowStatus(displayId, token, vis, backDisposition, 539 showImeSwitcher); 540 } 541 542 @Override 543 public void setIcon(String slot, String iconPackage, int iconId, int iconLevel, 544 String contentDescription) { 545 StatusBarManagerService.this.setIcon(slot, iconPackage, iconId, iconLevel, 546 contentDescription); 547 } 548 549 @Override 550 public void setIconVisibility(String slot, boolean visibility) { 551 StatusBarManagerService.this.setIconVisibility(slot, visibility); 552 } 553 554 @Override 555 public void showChargingAnimation(int batteryLevel) { 556 IStatusBar bar = mBar; 557 if (bar != null) { 558 try { 559 bar.showWirelessChargingAnimation(batteryLevel); 560 } catch (RemoteException ex){ 561 } 562 } 563 } 564 565 @Override 566 public void showPictureInPictureMenu() { 567 IStatusBar bar = mBar; 568 if (bar != null) { 569 try { 570 mBar.showPictureInPictureMenu(); 571 } catch (RemoteException ex) {} 572 } 573 } 574 575 @Override 576 public void setWindowState(int displayId, int window, int state) { 577 IStatusBar bar = mBar; 578 if (bar != null) { 579 try { 580 bar.setWindowState(displayId, window, state); 581 } catch (RemoteException ex) {} 582 } 583 } 584 585 @Override 586 public void appTransitionPending(int displayId) { 587 IStatusBar bar = mBar; 588 if (bar != null) { 589 try { 590 bar.appTransitionPending(displayId); 591 } catch (RemoteException ex) {} 592 } 593 } 594 595 @Override 596 public void appTransitionCancelled(int displayId) { 597 IStatusBar bar = mBar; 598 if (bar != null) { 599 try { 600 bar.appTransitionCancelled(displayId); 601 } catch (RemoteException ex) {} 602 } 603 } 604 605 @Override 606 public void appTransitionStarting(int displayId, long statusBarAnimationsStartTime, 607 long statusBarAnimationsDuration) { 608 IStatusBar bar = mBar; 609 if (bar != null) { 610 try { 611 bar.appTransitionStarting( 612 displayId, statusBarAnimationsStartTime, statusBarAnimationsDuration); 613 } catch (RemoteException ex) {} 614 } 615 } 616 617 @Override 618 public void setTopAppHidesStatusBar(boolean hidesStatusBar) { 619 IStatusBar bar = mBar; 620 if (bar != null) { 621 try { 622 bar.setTopAppHidesStatusBar(hidesStatusBar); 623 } catch (RemoteException ex) {} 624 } 625 } 626 627 @Override 628 public boolean showShutdownUi(boolean isReboot, String reason) { 629 if (!mContext.getResources().getBoolean(R.bool.config_showSysuiShutdown)) { 630 return false; 631 } 632 IStatusBar bar = mBar; 633 if (bar != null) { 634 try { 635 bar.showShutdownUi(isReboot, reason); 636 return true; 637 } catch (RemoteException ex) {} 638 } 639 return false; 640 } 641 642 @Override 643 public void confirmImmersivePrompt() { 644 if (mBar == null) { 645 return; 646 } 647 try { 648 mBar.confirmImmersivePrompt(); 649 } catch (RemoteException ex) { 650 } 651 } 652 653 @Override 654 public void immersiveModeChanged(int rootDisplayAreaId, boolean isImmersiveMode) { 655 if (mBar == null) { 656 return; 657 } 658 if (!CLIENT_TRANSIENT) { 659 // Only call from here when the client transient is not enabled. 660 try { 661 mBar.immersiveModeChanged(rootDisplayAreaId, isImmersiveMode); 662 } catch (RemoteException ex) { 663 } 664 } 665 } 666 667 // TODO(b/118592525): support it per display if necessary. 668 @Override 669 public void onProposedRotationChanged(int rotation, boolean isValid) { 670 if (mBar != null){ 671 try { 672 mBar.onProposedRotationChanged(rotation, isValid); 673 } catch (RemoteException ex) {} 674 } 675 } 676 677 @Override 678 public void onDisplayReady(int displayId) { 679 IStatusBar bar = mBar; 680 if (bar != null) { 681 try { 682 bar.onDisplayReady(displayId); 683 } catch (RemoteException ex) {} 684 } 685 } 686 687 @Override 688 public void onRecentsAnimationStateChanged(boolean running) { 689 IStatusBar bar = mBar; 690 if (bar != null) { 691 try { 692 bar.onRecentsAnimationStateChanged(running); 693 } catch (RemoteException ex) {} 694 } 695 696 } 697 698 @Override 699 public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance, 700 AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, 701 @Behavior int behavior, @InsetsType int requestedVisibleTypes, 702 String packageName, LetterboxDetails[] letterboxDetails) { 703 getUiState(displayId).setBarAttributes(appearance, appearanceRegions, 704 navbarColorManagedByIme, behavior, requestedVisibleTypes, packageName, 705 letterboxDetails); 706 IStatusBar bar = mBar; 707 if (bar != null) { 708 try { 709 bar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions, 710 navbarColorManagedByIme, behavior, requestedVisibleTypes, packageName, 711 letterboxDetails); 712 } catch (RemoteException ex) { } 713 } 714 } 715 716 @Override 717 public void showTransient(int displayId, @InsetsType int types, 718 boolean isGestureOnSystemBar) { 719 getUiState(displayId).showTransient(types); 720 IStatusBar bar = mBar; 721 if (bar != null) { 722 try { 723 bar.showTransient(displayId, types, isGestureOnSystemBar); 724 } catch (RemoteException ex) { } 725 } 726 } 727 728 @Override 729 public void abortTransient(int displayId, @InsetsType int types) { 730 getUiState(displayId).clearTransient(types); 731 IStatusBar bar = mBar; 732 if (bar != null) { 733 try { 734 bar.abortTransient(displayId, types); 735 } catch (RemoteException ex) { } 736 } 737 } 738 739 @Override 740 public void showToast(int uid, String packageName, IBinder token, CharSequence text, 741 IBinder windowToken, int duration, 742 @Nullable ITransientNotificationCallback callback, int displayId) { 743 IStatusBar bar = mBar; 744 if (bar != null) { 745 try { 746 bar.showToast(uid, packageName, token, text, windowToken, duration, callback, 747 displayId); 748 } catch (RemoteException ex) { } 749 } 750 } 751 752 @Override 753 public void hideToast(String packageName, IBinder token) { 754 IStatusBar bar = mBar; 755 if (bar != null) { 756 try { 757 bar.hideToast(packageName, token); 758 } catch (RemoteException ex) { } 759 } 760 } 761 762 @Override 763 public boolean requestWindowMagnificationConnection(boolean request) { 764 IStatusBar bar = mBar; 765 if (bar != null) { 766 try { 767 bar.requestWindowMagnificationConnection(request); 768 return true; 769 } catch (RemoteException ex) { } 770 } 771 return false; 772 } 773 774 @Override 775 public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) { 776 IStatusBar bar = mBar; 777 if (bar != null) { 778 try { 779 bar.setNavigationBarLumaSamplingEnabled(displayId, enable); 780 } catch (RemoteException ex) { } 781 } 782 } 783 784 @Override 785 public void setUdfpsRefreshRateCallback(IUdfpsRefreshRateRequestCallback callback) { 786 synchronized (mLock) { 787 mUdfpsRefreshRateRequestCallback = callback; 788 } 789 IStatusBar bar = mBar; 790 if (bar != null) { 791 try { 792 bar.setUdfpsRefreshRateCallback(callback); 793 } catch (RemoteException ex) { } 794 } 795 } 796 797 @Override 798 public void showRearDisplayDialog(int currentBaseState) { 799 IStatusBar bar = mBar; 800 if (bar != null) { 801 try { 802 bar.showRearDisplayDialog(currentBaseState); 803 } catch (RemoteException ex) { } 804 } 805 } 806 807 @Override 808 public void goToFullscreenFromSplit() { 809 IStatusBar bar = mBar; 810 if (bar != null) { 811 try { 812 bar.goToFullscreenFromSplit(); 813 } catch (RemoteException ex) { } 814 } 815 } 816 817 @Override 818 public void enterStageSplitFromRunningApp(boolean leftOrTop) { 819 IStatusBar bar = mBar; 820 if (bar != null) { 821 try { 822 bar.enterStageSplitFromRunningApp(leftOrTop); 823 } catch (RemoteException ex) { } 824 } 825 } 826 827 @Override 828 public void showMediaOutputSwitcher(String packageName) { 829 IStatusBar bar = mBar; 830 if (bar != null) { 831 try { 832 bar.showMediaOutputSwitcher(packageName); 833 } catch (RemoteException ex) { 834 } 835 } 836 } 837 }; 838 839 private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() { 840 @Override 841 public boolean isGlobalActionsDisabled() { 842 // TODO(b/118592525): support global actions for multi-display. 843 final int disabled2 = mDisplayUiState.get(DEFAULT_DISPLAY).getDisabled2(); 844 return (disabled2 & DISABLE2_GLOBAL_ACTIONS) != 0; 845 } 846 847 @Override 848 public void setGlobalActionsListener(GlobalActionsProvider.GlobalActionsListener listener) { 849 mGlobalActionListener = listener; 850 mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null); 851 } 852 853 @Override 854 public void showGlobalActions() { 855 IStatusBar bar = mBar; 856 if (bar != null) { 857 try { 858 bar.showGlobalActionsMenu(); 859 } catch (RemoteException ex) {} 860 } 861 } 862 }; 863 864 /** 865 * Returns true if the target disable flag (target2) is set 866 */ isDisable2FlagSet(int target2)867 private boolean isDisable2FlagSet(int target2) { 868 final int disabled2 = mDisplayUiState.get(DEFAULT_DISPLAY).getDisabled2(); 869 return ((disabled2 & target2) == target2); 870 } 871 872 // ================================================================================ 873 // From IStatusBarService 874 // ================================================================================ 875 876 @Override expandNotificationsPanel()877 public void expandNotificationsPanel() { 878 enforceExpandStatusBar(); 879 880 if (isDisable2FlagSet(DISABLE2_NOTIFICATION_SHADE)) { 881 return; 882 } 883 884 if (mBar != null) { 885 try { 886 mBar.animateExpandNotificationsPanel(); 887 } catch (RemoteException ex) { 888 } 889 } 890 } 891 892 @Override collapsePanels()893 public void collapsePanels() { 894 if (!checkCanCollapseStatusBar("collapsePanels")) { 895 return; 896 } 897 898 if (mBar != null) { 899 try { 900 mBar.animateCollapsePanels(); 901 } catch (RemoteException ex) { 902 } 903 } 904 } 905 906 @Override togglePanel()907 public void togglePanel() { 908 if (!checkCanCollapseStatusBar("togglePanel")) { 909 return; 910 } 911 912 if (isDisable2FlagSet(DISABLE2_NOTIFICATION_SHADE)) { 913 return; 914 } 915 916 if (mBar != null) { 917 try { 918 mBar.togglePanel(); 919 } catch (RemoteException ex) { 920 } 921 } 922 } 923 924 @Override expandSettingsPanel(String subPanel)925 public void expandSettingsPanel(String subPanel) { 926 enforceExpandStatusBar(); 927 928 if (mBar != null) { 929 try { 930 mBar.animateExpandSettingsPanel(subPanel); 931 } catch (RemoteException ex) { 932 } 933 } 934 } 935 addTile(ComponentName component)936 public void addTile(ComponentName component) { 937 enforceStatusBarOrShell(); 938 939 if (mBar != null) { 940 try { 941 mBar.addQsTile(component); 942 } catch (RemoteException ex) { 943 } 944 } 945 } 946 remTile(ComponentName component)947 public void remTile(ComponentName component) { 948 enforceStatusBarOrShell(); 949 950 if (mBar != null) { 951 try { 952 mBar.remQsTile(component); 953 } catch (RemoteException ex) { 954 } 955 } 956 } 957 clickTile(ComponentName component)958 public void clickTile(ComponentName component) { 959 enforceStatusBarOrShell(); 960 961 if (mBar != null) { 962 try { 963 mBar.clickQsTile(component); 964 } catch (RemoteException ex) { 965 } 966 } 967 } 968 969 @Override handleSystemKey(KeyEvent key)970 public void handleSystemKey(KeyEvent key) throws RemoteException { 971 if (!checkCanCollapseStatusBar("handleSystemKey")) { 972 return; 973 } 974 975 mLastSystemKey = key.getKeyCode(); 976 977 if (mBar != null) { 978 try { 979 mBar.handleSystemKey(key); 980 } catch (RemoteException ex) { 981 } 982 } 983 } 984 985 @Override 986 @TestApi getLastSystemKey()987 public int getLastSystemKey() { 988 enforceStatusBar(); 989 990 return mLastSystemKey; 991 } 992 993 @Override showPinningEnterExitToast(boolean entering)994 public void showPinningEnterExitToast(boolean entering) throws RemoteException { 995 if (mBar != null) { 996 try { 997 mBar.showPinningEnterExitToast(entering); 998 } catch (RemoteException ex) { 999 } 1000 } 1001 } 1002 1003 @Override showPinningEscapeToast()1004 public void showPinningEscapeToast() throws RemoteException { 1005 if (mBar != null) { 1006 try { 1007 mBar.showPinningEscapeToast(); 1008 } catch (RemoteException ex) { 1009 } 1010 } 1011 } 1012 1013 @Override showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, long operationId, String opPackageName, long requestId)1014 public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, 1015 int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, 1016 int userId, long operationId, String opPackageName, long requestId) { 1017 enforceBiometricDialog(); 1018 if (mBar != null) { 1019 try { 1020 mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed, 1021 requireConfirmation, userId, operationId, opPackageName, requestId); 1022 } catch (RemoteException ex) { 1023 } 1024 } 1025 } 1026 1027 @Override onBiometricAuthenticated(@odality int modality)1028 public void onBiometricAuthenticated(@Modality int modality) { 1029 enforceBiometricDialog(); 1030 if (mBar != null) { 1031 try { 1032 mBar.onBiometricAuthenticated(modality); 1033 } catch (RemoteException ex) { 1034 } 1035 } 1036 } 1037 1038 @Override onBiometricHelp(@odality int modality, String message)1039 public void onBiometricHelp(@Modality int modality, String message) { 1040 enforceBiometricDialog(); 1041 if (mBar != null) { 1042 try { 1043 mBar.onBiometricHelp(modality, message); 1044 } catch (RemoteException ex) { 1045 } 1046 } 1047 } 1048 1049 @Override onBiometricError(int modality, int error, int vendorCode)1050 public void onBiometricError(int modality, int error, int vendorCode) { 1051 enforceBiometricDialog(); 1052 if (mBar != null) { 1053 try { 1054 mBar.onBiometricError(modality, error, vendorCode); 1055 } catch (RemoteException ex) { 1056 } 1057 } 1058 } 1059 1060 @Override hideAuthenticationDialog(long requestId)1061 public void hideAuthenticationDialog(long requestId) { 1062 enforceBiometricDialog(); 1063 if (mBar != null) { 1064 try { 1065 mBar.hideAuthenticationDialog(requestId); 1066 } catch (RemoteException ex) { 1067 } 1068 } 1069 } 1070 1071 @Override setBiometicContextListener(IBiometricContextListener listener)1072 public void setBiometicContextListener(IBiometricContextListener listener) { 1073 enforceStatusBarService(); 1074 synchronized (mLock) { 1075 mBiometricContextListener = listener; 1076 } 1077 if (mBar != null) { 1078 try { 1079 mBar.setBiometicContextListener(listener); 1080 } catch (RemoteException ex) { 1081 } 1082 } 1083 } 1084 1085 @Override setUdfpsRefreshRateCallback(IUdfpsRefreshRateRequestCallback callback)1086 public void setUdfpsRefreshRateCallback(IUdfpsRefreshRateRequestCallback callback) { 1087 enforceStatusBarService(); 1088 if (mBar != null) { 1089 try { 1090 mBar.setUdfpsRefreshRateCallback(callback); 1091 } catch (RemoteException ex) { 1092 } 1093 } 1094 } 1095 1096 @Override startTracing()1097 public void startTracing() { 1098 if (mBar != null) { 1099 try { 1100 mBar.startTracing(); 1101 mTracingEnabled = true; 1102 } catch (RemoteException ex) { 1103 } 1104 } 1105 } 1106 1107 @Override stopTracing()1108 public void stopTracing() { 1109 if (mBar != null) { 1110 try { 1111 mTracingEnabled = false; 1112 mBar.stopTracing(); 1113 } catch (RemoteException ex) {} 1114 } 1115 } 1116 1117 @Override isTracing()1118 public boolean isTracing() { 1119 return mTracingEnabled; 1120 } 1121 1122 // TODO(b/117478341): make it aware of multi-display if needed. 1123 @Override disable(int what, IBinder token, String pkg)1124 public void disable(int what, IBinder token, String pkg) { 1125 disableForUser(what, token, pkg, mCurrentUserId); 1126 } 1127 1128 // TODO(b/117478341): make it aware of multi-display if needed. 1129 @Override disableForUser(int what, IBinder token, String pkg, int userId)1130 public void disableForUser(int what, IBinder token, String pkg, int userId) { 1131 enforceStatusBar(); 1132 1133 synchronized (mLock) { 1134 disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 1); 1135 } 1136 } 1137 1138 // TODO(b/117478341): make it aware of multi-display if needed. 1139 /** 1140 * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags. 1141 * To re-enable everything, pass {@link #DISABLE2_NONE}. 1142 * 1143 * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. 1144 */ 1145 @Override disable2(int what, IBinder token, String pkg)1146 public void disable2(int what, IBinder token, String pkg) { 1147 disable2ForUser(what, token, pkg, mCurrentUserId); 1148 } 1149 1150 // TODO(b/117478341): make it aware of multi-display if needed. 1151 /** 1152 * Disable additional status bar features for a given user. Pass the bitwise-or of the 1153 * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}. 1154 * 1155 * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. 1156 */ 1157 @Override disable2ForUser(int what, IBinder token, String pkg, int userId)1158 public void disable2ForUser(int what, IBinder token, String pkg, int userId) { 1159 enforceStatusBar(); 1160 1161 synchronized (mLock) { 1162 disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 2); 1163 } 1164 } 1165 disableLocked(int displayId, int userId, int what, IBinder token, String pkg, int whichFlag)1166 private void disableLocked(int displayId, int userId, int what, IBinder token, String pkg, 1167 int whichFlag) { 1168 // It's important that the the callback and the call to mBar get done 1169 // in the same order when multiple threads are calling this function 1170 // so they are paired correctly. The messages on the handler will be 1171 // handled in the order they were enqueued, but will be outside the lock. 1172 manageDisableListLocked(userId, what, token, pkg, whichFlag); 1173 1174 // Ensure state for the current user is applied, even if passed a non-current user. 1175 final int net1 = gatherDisableActionsLocked(mCurrentUserId, 1); 1176 final int net2 = gatherDisableActionsLocked(mCurrentUserId, 2); 1177 final UiState state = getUiState(displayId); 1178 if (!state.disableEquals(net1, net2)) { 1179 state.setDisabled(net1, net2); 1180 mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1)); 1181 IStatusBar bar = mBar; 1182 if (bar != null) { 1183 try { 1184 bar.disable(displayId, net1, net2); 1185 } catch (RemoteException ex) { 1186 } 1187 } 1188 } 1189 } 1190 1191 /** 1192 * Get the currently applied disable flags, in the form of one Pair<Integer, Integer>. 1193 * 1194 * @return pair of disable flags in the form of (disabled1, disabled2), where (0, 0) indicates 1195 * no flags are set for this token. 1196 */ 1197 @Override getDisableFlags(IBinder token, int userId)1198 public int[] getDisableFlags(IBinder token, int userId) { 1199 enforceStatusBar(); 1200 1201 int disable1 = 0; 1202 int disable2 = 0; 1203 synchronized (mLock) { 1204 // Find a matching record if it exists 1205 DisableRecord record = findMatchingRecordLocked(token, userId).second; 1206 if (record != null) { 1207 disable1 = record.what1; 1208 disable2 = record.what2; 1209 } 1210 } 1211 1212 return new int[] {disable1, disable2}; 1213 } 1214 runGcForTest()1215 void runGcForTest() { 1216 if (!Build.IS_DEBUGGABLE) { 1217 throw new SecurityException("runGcForTest requires a debuggable build"); 1218 } 1219 1220 // Gc the system along the way 1221 GcUtils.runGcAndFinalizersSync(); 1222 1223 if (mBar != null) { 1224 try { 1225 mBar.runGcForTest(); 1226 } catch (RemoteException ex) { 1227 } 1228 } 1229 } 1230 1231 @Override setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription)1232 public void setIcon(String slot, String iconPackage, int iconId, int iconLevel, 1233 String contentDescription) { 1234 enforceStatusBar(); 1235 1236 synchronized (mIcons) { 1237 StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId, 1238 iconLevel, 0, contentDescription); 1239 //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon); 1240 mIcons.put(slot, icon); 1241 1242 IStatusBar bar = mBar; 1243 if (bar != null) { 1244 try { 1245 bar.setIcon(slot, icon); 1246 } catch (RemoteException ex) { 1247 } 1248 } 1249 } 1250 } 1251 1252 @Override setIconVisibility(String slot, boolean visibility)1253 public void setIconVisibility(String slot, boolean visibility) { 1254 enforceStatusBar(); 1255 1256 synchronized (mIcons) { 1257 StatusBarIcon icon = mIcons.get(slot); 1258 if (icon == null) { 1259 return; 1260 } 1261 if (icon.visible != visibility) { 1262 icon.visible = visibility; 1263 1264 IStatusBar bar = mBar; 1265 if (bar != null) { 1266 try { 1267 bar.setIcon(slot, icon); 1268 } catch (RemoteException ex) { 1269 } 1270 } 1271 } 1272 } 1273 } 1274 1275 @Override removeIcon(String slot)1276 public void removeIcon(String slot) { 1277 enforceStatusBar(); 1278 1279 synchronized (mIcons) { 1280 mIcons.remove(slot); 1281 1282 IStatusBar bar = mBar; 1283 if (bar != null) { 1284 try { 1285 bar.removeIcon(slot); 1286 } catch (RemoteException ex) { 1287 } 1288 } 1289 } 1290 } 1291 1292 @Override setImeWindowStatus(int displayId, final IBinder token, final int vis, final int backDisposition, final boolean showImeSwitcher)1293 public void setImeWindowStatus(int displayId, final IBinder token, final int vis, 1294 final int backDisposition, final boolean showImeSwitcher) { 1295 enforceStatusBar(); 1296 1297 if (SPEW) { 1298 Slog.d(TAG, "swetImeWindowStatus vis=" + vis + " backDisposition=" + backDisposition); 1299 } 1300 1301 synchronized(mLock) { 1302 // In case of IME change, we need to call up setImeWindowStatus() regardless of 1303 // mImeWindowVis because mImeWindowVis may not have been set to false when the 1304 // previous IME was destroyed. 1305 getUiState(displayId).setImeWindowState(vis, backDisposition, showImeSwitcher, token); 1306 1307 mHandler.post(() -> { 1308 if (mBar == null) return; 1309 try { 1310 mBar.setImeWindowStatus( 1311 displayId, token, vis, backDisposition, showImeSwitcher); 1312 } catch (RemoteException ex) { } 1313 }); 1314 } 1315 } 1316 setDisableFlags(int displayId, int flags, String cause)1317 private void setDisableFlags(int displayId, int flags, String cause) { 1318 // also allows calls from window manager which is in this process. 1319 enforceStatusBarService(); 1320 1321 final int unknownFlags = flags & ~StatusBarManager.DISABLE_MASK; 1322 if (unknownFlags != 0) { 1323 Slog.e(TAG, "Unknown disable flags: 0x" + Integer.toHexString(unknownFlags), 1324 new RuntimeException()); 1325 } 1326 1327 if (SPEW) Slog.d(TAG, "setDisableFlags(0x" + Integer.toHexString(flags) + ")"); 1328 1329 synchronized (mLock) { 1330 disableLocked(displayId, mCurrentUserId, flags, mSysUiVisToken, cause, 1); 1331 } 1332 } 1333 1334 /** 1335 * @return {@link UiState} specified by {@code displayId}. 1336 * 1337 * <p> 1338 * Note: If {@link UiState} specified by {@code displayId} does not exist, {@link UiState} 1339 * will be allocated and {@code mDisplayUiState} will be updated accordingly. 1340 * <p/> 1341 */ getUiState(int displayId)1342 private UiState getUiState(int displayId) { 1343 UiState state = mDisplayUiState.get(displayId); 1344 if (state == null) { 1345 state = new UiState(); 1346 mDisplayUiState.put(displayId, state); 1347 } 1348 return state; 1349 } 1350 1351 private static class UiState { 1352 private @Appearance int mAppearance = 0; 1353 private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0]; 1354 private @InsetsType int mTransientBarTypes; 1355 private boolean mNavbarColorManagedByIme = false; 1356 private @Behavior int mBehavior; 1357 private @InsetsType int mRequestedVisibleTypes = WindowInsets.Type.defaultVisible(); 1358 private String mPackageName = "none"; 1359 private int mDisabled1 = 0; 1360 private int mDisabled2 = 0; 1361 private int mImeWindowVis = 0; 1362 private int mImeBackDisposition = 0; 1363 private boolean mShowImeSwitcher = false; 1364 private IBinder mImeToken = null; 1365 private LetterboxDetails[] mLetterboxDetails = new LetterboxDetails[0]; 1366 setBarAttributes(@ppearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, @Behavior int behavior, @InsetsType int requestedVisibleTypes, String packageName, LetterboxDetails[] letterboxDetails)1367 private void setBarAttributes(@Appearance int appearance, 1368 AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, 1369 @Behavior int behavior, @InsetsType int requestedVisibleTypes, 1370 String packageName, 1371 LetterboxDetails[] letterboxDetails) { 1372 mAppearance = appearance; 1373 mAppearanceRegions = appearanceRegions; 1374 mNavbarColorManagedByIme = navbarColorManagedByIme; 1375 mBehavior = behavior; 1376 mRequestedVisibleTypes = requestedVisibleTypes; 1377 mPackageName = packageName; 1378 mLetterboxDetails = letterboxDetails; 1379 } 1380 showTransient(@nsetsType int types)1381 private void showTransient(@InsetsType int types) { 1382 mTransientBarTypes |= types; 1383 } 1384 clearTransient(@nsetsType int types)1385 private void clearTransient(@InsetsType int types) { 1386 mTransientBarTypes &= ~types; 1387 } 1388 getDisabled1()1389 private int getDisabled1() { 1390 return mDisabled1; 1391 } 1392 getDisabled2()1393 private int getDisabled2() { 1394 return mDisabled2; 1395 } 1396 setDisabled(int disabled1, int disabled2)1397 private void setDisabled(int disabled1, int disabled2) { 1398 mDisabled1 = disabled1; 1399 mDisabled2 = disabled2; 1400 } 1401 disableEquals(int disabled1, int disabled2)1402 private boolean disableEquals(int disabled1, int disabled2) { 1403 return mDisabled1 == disabled1 && mDisabled2 == disabled2; 1404 } 1405 setImeWindowState(final int vis, final int backDisposition, final boolean showImeSwitcher, final IBinder token)1406 private void setImeWindowState(final int vis, final int backDisposition, 1407 final boolean showImeSwitcher, final IBinder token) { 1408 mImeWindowVis = vis; 1409 mImeBackDisposition = backDisposition; 1410 mShowImeSwitcher = showImeSwitcher; 1411 mImeToken = token; 1412 } 1413 } 1414 enforceStatusBarOrShell()1415 private void enforceStatusBarOrShell() { 1416 if (Binder.getCallingUid() == Process.SHELL_UID) { 1417 return; 1418 } 1419 enforceStatusBar(); 1420 } 1421 enforceStatusBar()1422 private void enforceStatusBar() { 1423 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR, 1424 "StatusBarManagerService"); 1425 } 1426 enforceExpandStatusBar()1427 private void enforceExpandStatusBar() { 1428 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.EXPAND_STATUS_BAR, 1429 "StatusBarManagerService"); 1430 } 1431 enforceStatusBarService()1432 private void enforceStatusBarService() { 1433 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 1434 "StatusBarManagerService"); 1435 } 1436 enforceBiometricDialog()1437 private void enforceBiometricDialog() { 1438 mContext.enforceCallingOrSelfPermission( 1439 android.Manifest.permission.MANAGE_BIOMETRIC_DIALOG, 1440 "StatusBarManagerService"); 1441 } 1442 enforceMediaContentControl()1443 private void enforceMediaContentControl() { 1444 mContext.enforceCallingOrSelfPermission( 1445 android.Manifest.permission.MEDIA_CONTENT_CONTROL, 1446 "StatusBarManagerService"); 1447 } 1448 1449 @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) enforceControlDeviceStatePermission()1450 private void enforceControlDeviceStatePermission() { 1451 mContext.enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, "StatusBarManagerService"); 1452 } 1453 doesCallerHoldInteractAcrossUserPermission()1454 private boolean doesCallerHoldInteractAcrossUserPermission() { 1455 return mContext.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) == PERMISSION_GRANTED 1456 || mContext.checkCallingPermission(INTERACT_ACROSS_USERS) == PERMISSION_GRANTED; 1457 } 1458 1459 /** 1460 * For targetSdk S+ we require STATUS_BAR. For targetSdk < S, we only require EXPAND_STATUS_BAR 1461 * but also require that it falls into one of the allowed use-cases to lock down abuse vector. 1462 */ checkCanCollapseStatusBar(String method)1463 private boolean checkCanCollapseStatusBar(String method) { 1464 int uid = Binder.getCallingUid(); 1465 int pid = Binder.getCallingPid(); 1466 if (CompatChanges.isChangeEnabled(LOCK_DOWN_COLLAPSE_STATUS_BAR, uid)) { 1467 enforceStatusBar(); 1468 } else { 1469 if (mContext.checkPermission(Manifest.permission.STATUS_BAR, pid, uid) 1470 != PERMISSION_GRANTED) { 1471 enforceExpandStatusBar(); 1472 if (!mActivityTaskManager.canCloseSystemDialogs(pid, uid)) { 1473 Slog.e(TAG, "Permission Denial: Method " + method + "() requires permission " 1474 + Manifest.permission.STATUS_BAR + ", ignoring call."); 1475 return false; 1476 } 1477 } 1478 } 1479 return true; 1480 } 1481 1482 // ================================================================================ 1483 // Callbacks from the status bar service. 1484 // ================================================================================ 1485 // TODO(b/118592525): refactor it as an IStatusBar API. 1486 @Override registerStatusBar(IStatusBar bar)1487 public RegisterStatusBarResult registerStatusBar(IStatusBar bar) { 1488 enforceStatusBarService(); 1489 1490 Slog.i(TAG, "registerStatusBar bar=" + bar); 1491 mBar = bar; 1492 mDeathRecipient.linkToDeath(); 1493 notifyBarAttachChanged(); 1494 final ArrayMap<String, StatusBarIcon> icons; 1495 synchronized (mIcons) { 1496 icons = new ArrayMap<>(mIcons); 1497 } 1498 synchronized (mLock) { 1499 // TODO(b/118592525): Currently, status bar only works on the default display. 1500 // Make it aware of multi-display if needed. 1501 final UiState state = mDisplayUiState.get(DEFAULT_DISPLAY); 1502 return new RegisterStatusBarResult(icons, gatherDisableActionsLocked(mCurrentUserId, 1), 1503 state.mAppearance, state.mAppearanceRegions, state.mImeWindowVis, 1504 state.mImeBackDisposition, state.mShowImeSwitcher, 1505 gatherDisableActionsLocked(mCurrentUserId, 2), state.mImeToken, 1506 state.mNavbarColorManagedByIme, state.mBehavior, state.mRequestedVisibleTypes, 1507 state.mPackageName, state.mTransientBarTypes, state.mLetterboxDetails); 1508 } 1509 } 1510 notifyBarAttachChanged()1511 private void notifyBarAttachChanged() { 1512 UiThread.getHandler().post(() -> { 1513 if (mGlobalActionListener == null) return; 1514 mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null); 1515 }); 1516 // If StatusBarService dies, system_server doesn't get killed with it, so we need to make 1517 // sure the UDFPS callback is refreshed as well. Deferring to the handler just so to avoid 1518 // making registerStatusBar re-entrant. 1519 mHandler.post(() -> { 1520 synchronized (mLock) { 1521 setUdfpsRefreshRateCallback(mUdfpsRefreshRateRequestCallback); 1522 setBiometicContextListener(mBiometricContextListener); 1523 } 1524 }); 1525 } 1526 1527 @VisibleForTesting registerOverlayManager(IOverlayManager overlayManager)1528 void registerOverlayManager(IOverlayManager overlayManager) { 1529 mOverlayManager = overlayManager; 1530 } 1531 1532 /** 1533 * @param clearNotificationEffects whether to consider notifications as "shown" and stop 1534 * LED, vibration, and ringing 1535 */ 1536 @Override onPanelRevealed(boolean clearNotificationEffects, int numItems)1537 public void onPanelRevealed(boolean clearNotificationEffects, int numItems) { 1538 enforceStatusBarService(); 1539 final long identity = Binder.clearCallingIdentity(); 1540 try { 1541 mNotificationDelegate.onPanelRevealed(clearNotificationEffects, numItems); 1542 } finally { 1543 Binder.restoreCallingIdentity(identity); 1544 } 1545 } 1546 1547 @Override clearNotificationEffects()1548 public void clearNotificationEffects() throws RemoteException { 1549 enforceStatusBarService(); 1550 final long identity = Binder.clearCallingIdentity(); 1551 try { 1552 mNotificationDelegate.clearEffects(); 1553 } finally { 1554 Binder.restoreCallingIdentity(identity); 1555 } 1556 } 1557 1558 @Override onPanelHidden()1559 public void onPanelHidden() throws RemoteException { 1560 enforceStatusBarService(); 1561 final long identity = Binder.clearCallingIdentity(); 1562 try { 1563 mNotificationDelegate.onPanelHidden(); 1564 } finally { 1565 Binder.restoreCallingIdentity(identity); 1566 } 1567 } 1568 1569 /** 1570 * Allows the status bar to shutdown the device. 1571 */ 1572 @Override shutdown()1573 public void shutdown() { 1574 enforceStatusBarService(); 1575 String reason = PowerManager.SHUTDOWN_USER_REQUESTED; 1576 ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason); 1577 final long identity = Binder.clearCallingIdentity(); 1578 try { 1579 mNotificationDelegate.prepareForPossibleShutdown(); 1580 // ShutdownThread displays UI, so give it a UI context. 1581 mHandler.post(() -> 1582 ShutdownThread.shutdown(getUiContext(), reason, false)); 1583 } finally { 1584 Binder.restoreCallingIdentity(identity); 1585 } 1586 } 1587 1588 /** 1589 * Allows the status bar to reboot the device. 1590 */ 1591 @Override reboot(boolean safeMode)1592 public void reboot(boolean safeMode) { 1593 enforceStatusBarService(); 1594 String reason = safeMode 1595 ? PowerManager.REBOOT_SAFE_MODE 1596 : PowerManager.SHUTDOWN_USER_REQUESTED; 1597 ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason); 1598 final long identity = Binder.clearCallingIdentity(); 1599 try { 1600 mNotificationDelegate.prepareForPossibleShutdown(); 1601 mHandler.post(() -> { 1602 // ShutdownThread displays UI, so give it a UI context. 1603 if (safeMode) { 1604 ShutdownThread.rebootSafeMode(getUiContext(), true); 1605 } else { 1606 ShutdownThread.reboot(getUiContext(), reason, false); 1607 } 1608 }); 1609 } finally { 1610 Binder.restoreCallingIdentity(identity); 1611 } 1612 } 1613 1614 /** 1615 * Allows the status bar to restart android (vs a full reboot). 1616 */ 1617 @Override restart()1618 public void restart() { 1619 enforceStatusBarService(); 1620 final long identity = Binder.clearCallingIdentity(); 1621 try { 1622 mHandler.post(() -> { 1623 mActivityManagerInternal.restart(); 1624 }); 1625 } finally { 1626 Binder.restoreCallingIdentity(identity); 1627 } 1628 } 1629 1630 @Override onGlobalActionsShown()1631 public void onGlobalActionsShown() { 1632 enforceStatusBarService(); 1633 final long identity = Binder.clearCallingIdentity(); 1634 try { 1635 if (mGlobalActionListener == null) return; 1636 mGlobalActionListener.onGlobalActionsShown(); 1637 } finally { 1638 Binder.restoreCallingIdentity(identity); 1639 } 1640 } 1641 1642 @Override onGlobalActionsHidden()1643 public void onGlobalActionsHidden() { 1644 enforceStatusBarService(); 1645 final long identity = Binder.clearCallingIdentity(); 1646 try { 1647 if (mGlobalActionListener == null) return; 1648 mGlobalActionListener.onGlobalActionsDismissed(); 1649 } finally { 1650 Binder.restoreCallingIdentity(identity); 1651 } 1652 } 1653 1654 @Override onNotificationClick(String key, NotificationVisibility nv)1655 public void onNotificationClick(String key, NotificationVisibility nv) { 1656 enforceStatusBarService(); 1657 final int callingUid = Binder.getCallingUid(); 1658 final int callingPid = Binder.getCallingPid(); 1659 final long identity = Binder.clearCallingIdentity(); 1660 try { 1661 mNotificationDelegate.onNotificationClick(callingUid, callingPid, key, nv); 1662 } finally { 1663 Binder.restoreCallingIdentity(identity); 1664 } 1665 } 1666 1667 @Override onNotificationActionClick( String key, int actionIndex, Notification.Action action, NotificationVisibility nv, boolean generatedByAssistant)1668 public void onNotificationActionClick( 1669 String key, int actionIndex, Notification.Action action, NotificationVisibility nv, 1670 boolean generatedByAssistant) { 1671 enforceStatusBarService(); 1672 final int callingUid = Binder.getCallingUid(); 1673 final int callingPid = Binder.getCallingPid(); 1674 final long identity = Binder.clearCallingIdentity(); 1675 try { 1676 mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key, 1677 actionIndex, action, nv, generatedByAssistant); 1678 } finally { 1679 Binder.restoreCallingIdentity(identity); 1680 } 1681 } 1682 1683 @Override onNotificationError(String pkg, String tag, int id, int uid, int initialPid, String message, int userId)1684 public void onNotificationError(String pkg, String tag, int id, 1685 int uid, int initialPid, String message, int userId) { 1686 enforceStatusBarService(); 1687 final int callingUid = Binder.getCallingUid(); 1688 final int callingPid = Binder.getCallingPid(); 1689 final long identity = Binder.clearCallingIdentity(); 1690 try { 1691 // WARNING: this will call back into us to do the remove. Don't hold any locks. 1692 mNotificationDelegate.onNotificationError(callingUid, callingPid, 1693 pkg, tag, id, uid, initialPid, message, userId); 1694 } finally { 1695 Binder.restoreCallingIdentity(identity); 1696 } 1697 } 1698 1699 @Override onNotificationClear(String pkg, int userId, String key, @NotificationStats.DismissalSurface int dismissalSurface, @NotificationStats.DismissalSentiment int dismissalSentiment, NotificationVisibility nv)1700 public void onNotificationClear(String pkg, int userId, String key, 1701 @NotificationStats.DismissalSurface int dismissalSurface, 1702 @NotificationStats.DismissalSentiment int dismissalSentiment, 1703 NotificationVisibility nv) { 1704 enforceStatusBarService(); 1705 final int callingUid = Binder.getCallingUid(); 1706 final int callingPid = Binder.getCallingPid(); 1707 final long identity = Binder.clearCallingIdentity(); 1708 try { 1709 mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, userId, 1710 key, dismissalSurface, dismissalSentiment, nv); 1711 } finally { 1712 Binder.restoreCallingIdentity(identity); 1713 } 1714 } 1715 1716 @Override onNotificationVisibilityChanged( NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys)1717 public void onNotificationVisibilityChanged( 1718 NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys) 1719 throws RemoteException { 1720 enforceStatusBarService(); 1721 final long identity = Binder.clearCallingIdentity(); 1722 try { 1723 mNotificationDelegate.onNotificationVisibilityChanged( 1724 newlyVisibleKeys, noLongerVisibleKeys); 1725 } finally { 1726 Binder.restoreCallingIdentity(identity); 1727 } 1728 } 1729 1730 @Override onNotificationExpansionChanged(String key, boolean userAction, boolean expanded, int location)1731 public void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded, 1732 int location) throws RemoteException { 1733 enforceStatusBarService(); 1734 final long identity = Binder.clearCallingIdentity(); 1735 try { 1736 mNotificationDelegate.onNotificationExpansionChanged( 1737 key, userAction, expanded, location); 1738 } finally { 1739 Binder.restoreCallingIdentity(identity); 1740 } 1741 } 1742 1743 @Override onNotificationDirectReplied(String key)1744 public void onNotificationDirectReplied(String key) throws RemoteException { 1745 enforceStatusBarService(); 1746 final long identity = Binder.clearCallingIdentity(); 1747 try { 1748 mNotificationDelegate.onNotificationDirectReplied(key); 1749 } finally { 1750 Binder.restoreCallingIdentity(identity); 1751 } 1752 } 1753 1754 @Override onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending)1755 public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, 1756 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) { 1757 enforceStatusBarService(); 1758 final long identity = Binder.clearCallingIdentity(); 1759 try { 1760 mNotificationDelegate.onNotificationSmartSuggestionsAdded(key, smartReplyCount, 1761 smartActionCount, generatedByAssistant, editBeforeSending); 1762 } finally { 1763 Binder.restoreCallingIdentity(identity); 1764 } 1765 } 1766 1767 @Override onNotificationSmartReplySent( String key, int replyIndex, CharSequence reply, int notificationLocation, boolean modifiedBeforeSending)1768 public void onNotificationSmartReplySent( 1769 String key, int replyIndex, CharSequence reply, int notificationLocation, 1770 boolean modifiedBeforeSending) throws RemoteException { 1771 enforceStatusBarService(); 1772 final long identity = Binder.clearCallingIdentity(); 1773 try { 1774 mNotificationDelegate.onNotificationSmartReplySent(key, replyIndex, reply, 1775 notificationLocation, modifiedBeforeSending); 1776 } finally { 1777 Binder.restoreCallingIdentity(identity); 1778 } 1779 } 1780 1781 @Override onNotificationSettingsViewed(String key)1782 public void onNotificationSettingsViewed(String key) throws RemoteException { 1783 enforceStatusBarService(); 1784 final long identity = Binder.clearCallingIdentity(); 1785 try { 1786 mNotificationDelegate.onNotificationSettingsViewed(key); 1787 } finally { 1788 Binder.restoreCallingIdentity(identity); 1789 } 1790 } 1791 1792 @Override onClearAllNotifications(int userId)1793 public void onClearAllNotifications(int userId) { 1794 enforceStatusBarService(); 1795 final int callingUid = Binder.getCallingUid(); 1796 final int callingPid = Binder.getCallingPid(); 1797 final long identity = Binder.clearCallingIdentity(); 1798 try { 1799 mNotificationDelegate.onClearAll(callingUid, callingPid, userId); 1800 } finally { 1801 Binder.restoreCallingIdentity(identity); 1802 } 1803 } 1804 1805 @Override onNotificationBubbleChanged(String key, boolean isBubble, int flags)1806 public void onNotificationBubbleChanged(String key, boolean isBubble, int flags) { 1807 enforceStatusBarService(); 1808 final long identity = Binder.clearCallingIdentity(); 1809 try { 1810 mNotificationDelegate.onNotificationBubbleChanged(key, isBubble, flags); 1811 } finally { 1812 Binder.restoreCallingIdentity(identity); 1813 } 1814 } 1815 1816 @Override onBubbleMetadataFlagChanged(String key, int flags)1817 public void onBubbleMetadataFlagChanged(String key, int flags) { 1818 enforceStatusBarService(); 1819 final long identity = Binder.clearCallingIdentity(); 1820 try { 1821 mNotificationDelegate.onBubbleMetadataFlagChanged(key, flags); 1822 } finally { 1823 Binder.restoreCallingIdentity(identity); 1824 } 1825 } 1826 1827 @Override hideCurrentInputMethodForBubbles()1828 public void hideCurrentInputMethodForBubbles() { 1829 enforceStatusBarService(); 1830 final long token = Binder.clearCallingIdentity(); 1831 try { 1832 InputMethodManagerInternal.get().hideCurrentInputMethod( 1833 SoftInputShowHideReason.HIDE_BUBBLES); 1834 } finally { 1835 Binder.restoreCallingIdentity(token); 1836 } 1837 } 1838 1839 @Override grantInlineReplyUriPermission(String key, Uri uri, UserHandle user, String packageName)1840 public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user, 1841 String packageName) { 1842 enforceStatusBarService(); 1843 int callingUid = Binder.getCallingUid(); 1844 final long identity = Binder.clearCallingIdentity(); 1845 try { 1846 mNotificationDelegate.grantInlineReplyUriPermission(key, uri, user, packageName, 1847 callingUid); 1848 } finally { 1849 Binder.restoreCallingIdentity(identity); 1850 } 1851 } 1852 1853 @Override clearInlineReplyUriPermissions(String key)1854 public void clearInlineReplyUriPermissions(String key) { 1855 enforceStatusBarService(); 1856 int callingUid = Binder.getCallingUid(); 1857 final long identity = Binder.clearCallingIdentity(); 1858 try { 1859 mNotificationDelegate.clearInlineReplyUriPermissions(key, callingUid); 1860 } finally { 1861 Binder.restoreCallingIdentity(identity); 1862 } 1863 } 1864 1865 @Override onNotificationFeedbackReceived(String key, Bundle feedback)1866 public void onNotificationFeedbackReceived(String key, Bundle feedback) { 1867 enforceStatusBarService(); 1868 final long identity = Binder.clearCallingIdentity(); 1869 try { 1870 mNotificationDelegate.onNotificationFeedbackReceived(key, feedback); 1871 } finally { 1872 Binder.restoreCallingIdentity(identity); 1873 } 1874 } 1875 1876 1877 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1878 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 1879 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 1880 (new StatusBarShellCommand(this, mContext)).exec( 1881 this, in, out, err, args, callback, resultReceiver); 1882 } 1883 1884 @Override showInattentiveSleepWarning()1885 public void showInattentiveSleepWarning() { 1886 enforceStatusBarService(); 1887 IStatusBar bar = mBar; 1888 if (bar != null) { 1889 try { 1890 bar.showInattentiveSleepWarning(); 1891 } catch (RemoteException ex) { 1892 } 1893 } 1894 } 1895 1896 @Override dismissInattentiveSleepWarning(boolean animated)1897 public void dismissInattentiveSleepWarning(boolean animated) { 1898 enforceStatusBarService(); 1899 IStatusBar bar = mBar; 1900 if (bar != null) { 1901 try { 1902 bar.dismissInattentiveSleepWarning(animated); 1903 } catch (RemoteException ex) { 1904 } 1905 } 1906 } 1907 1908 @Override suppressAmbientDisplay(boolean suppress)1909 public void suppressAmbientDisplay(boolean suppress) { 1910 enforceStatusBarService(); 1911 IStatusBar bar = mBar; 1912 if (bar != null) { 1913 try { 1914 bar.suppressAmbientDisplay(suppress); 1915 } catch (RemoteException ex) { 1916 } 1917 } 1918 } 1919 checkCallingUidPackage(String packageName, int callingUid, int userId)1920 private void checkCallingUidPackage(String packageName, int callingUid, int userId) { 1921 int packageUid = mPackageManagerInternal.getPackageUid(packageName, 0, userId); 1922 if (UserHandle.getAppId(callingUid) != UserHandle.getAppId(packageUid)) { 1923 throw new SecurityException("Package " + packageName 1924 + " does not belong to the calling uid " + callingUid); 1925 } 1926 } 1927 isComponentValidTileService(ComponentName componentName, int userId)1928 private ResolveInfo isComponentValidTileService(ComponentName componentName, int userId) { 1929 Intent intent = new Intent(TileService.ACTION_QS_TILE); 1930 intent.setComponent(componentName); 1931 ResolveInfo r = mPackageManagerInternal.resolveService(intent, 1932 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 0, userId, 1933 Process.myUid()); 1934 int enabled = mPackageManagerInternal.getComponentEnabledSetting( 1935 componentName, Process.myUid(), userId); 1936 if (r != null 1937 && r.serviceInfo != null 1938 && resolveEnabledComponent(r.serviceInfo.enabled, enabled) 1939 && Manifest.permission.BIND_QUICK_SETTINGS_TILE.equals(r.serviceInfo.permission)) { 1940 return r; 1941 } else { 1942 return null; 1943 } 1944 } 1945 resolveEnabledComponent(boolean defaultValue, int pmResult)1946 private boolean resolveEnabledComponent(boolean defaultValue, int pmResult) { 1947 if (pmResult == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 1948 return true; 1949 } 1950 if (pmResult == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 1951 return defaultValue; 1952 } 1953 return false; 1954 } 1955 1956 @Override requestTileServiceListeningState( @onNull ComponentName componentName, int userId )1957 public void requestTileServiceListeningState( 1958 @NonNull ComponentName componentName, 1959 int userId 1960 ) { 1961 int callingUid = Binder.getCallingUid(); 1962 String packageName = componentName.getPackageName(); 1963 1964 boolean mustPerformChecks = CompatChanges.isChangeEnabled( 1965 REQUEST_LISTENING_MUST_MATCH_PACKAGE, callingUid); 1966 1967 if (mustPerformChecks) { 1968 // Check calling user can act on behalf of current user 1969 userId = mActivityManagerInternal.handleIncomingUser(Binder.getCallingPid(), callingUid, 1970 userId, false, ActivityManagerInternal.ALLOW_NON_FULL, 1971 "requestTileServiceListeningState", packageName); 1972 1973 // Check calling uid matches package 1974 checkCallingUidPackage(packageName, callingUid, userId); 1975 1976 int currentUser = mActivityManagerInternal.getCurrentUserId(); 1977 1978 // Check current user 1979 if (userId != currentUser) { 1980 if (CompatChanges.isChangeEnabled(REQUEST_LISTENING_OTHER_USER_NOOP, callingUid)) { 1981 return; 1982 } else { 1983 throw new IllegalArgumentException( 1984 "User " + userId + " is not the current user."); 1985 } 1986 } 1987 } 1988 IStatusBar bar = mBar; 1989 if (bar != null) { 1990 try { 1991 bar.requestTileServiceListeningState(componentName); 1992 } catch (RemoteException e) { 1993 Slog.e(TAG, "requestTileServiceListeningState", e); 1994 } 1995 } 1996 } 1997 1998 @Override requestAddTile( @onNull ComponentName componentName, @NonNull CharSequence label, @NonNull Icon icon, int userId, @NonNull IAddTileResultCallback callback )1999 public void requestAddTile( 2000 @NonNull ComponentName componentName, 2001 @NonNull CharSequence label, 2002 @NonNull Icon icon, 2003 int userId, 2004 @NonNull IAddTileResultCallback callback 2005 ) { 2006 int callingUid = Binder.getCallingUid(); 2007 String packageName = componentName.getPackageName(); 2008 2009 // Check calling user can act on behalf of current user 2010 mActivityManagerInternal.handleIncomingUser(Binder.getCallingPid(), callingUid, userId, 2011 false, ActivityManagerInternal.ALLOW_NON_FULL, "requestAddTile", packageName); 2012 2013 // Check calling uid matches package 2014 checkCallingUidPackage(packageName, callingUid, userId); 2015 2016 int currentUser = mActivityManagerInternal.getCurrentUserId(); 2017 2018 // Check current user 2019 if (userId != currentUser) { 2020 try { 2021 callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER); 2022 } catch (RemoteException e) { 2023 Slog.e(TAG, "requestAddTile", e); 2024 } 2025 return; 2026 } 2027 2028 // We've checked that the package, component name and uid all match. 2029 ResolveInfo r = isComponentValidTileService(componentName, userId); 2030 if (r == null || !r.serviceInfo.exported) { 2031 try { 2032 callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_BAD_COMPONENT); 2033 } catch (RemoteException e) { 2034 Slog.e(TAG, "requestAddTile", e); 2035 } 2036 return; 2037 } 2038 2039 final int procState = mActivityManagerInternal.getUidProcessState(callingUid); 2040 if (ActivityManager.RunningAppProcessInfo.procStateToImportance(procState) 2041 != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { 2042 try { 2043 callback.onTileRequest( 2044 StatusBarManager.TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND); 2045 } catch (RemoteException e) { 2046 Slog.e(TAG, "requestAddTile", e); 2047 } 2048 return; 2049 } 2050 2051 synchronized (mCurrentRequestAddTilePackages) { 2052 Long lastTime = mCurrentRequestAddTilePackages.get(packageName); 2053 final long currentTime = System.nanoTime(); 2054 if (lastTime != null && currentTime - lastTime < REQUEST_TIME_OUT) { 2055 try { 2056 callback.onTileRequest( 2057 StatusBarManager.TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS); 2058 } catch (RemoteException e) { 2059 Slog.e(TAG, "requestAddTile", e); 2060 } 2061 return; 2062 } else { 2063 if (lastTime != null) { 2064 cancelRequestAddTileInternal(packageName); 2065 } 2066 } 2067 2068 mCurrentRequestAddTilePackages.put(packageName, currentTime); 2069 } 2070 2071 if (mTileRequestTracker.shouldBeDenied(userId, componentName)) { 2072 if (clearTileAddRequest(packageName)) { 2073 try { 2074 callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED); 2075 } catch (RemoteException e) { 2076 Slog.e(TAG, "requestAddTile - callback", e); 2077 } 2078 } 2079 return; 2080 } 2081 2082 IAddTileResultCallback proxyCallback = new IAddTileResultCallback.Stub() { 2083 @Override 2084 public void onTileRequest(int i) { 2085 if (i == StatusBarManager.TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED) { 2086 i = StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED; 2087 } else if (i == StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED) { 2088 mTileRequestTracker.addDenial(userId, componentName); 2089 } else if (i == StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ADDED) { 2090 mTileRequestTracker.resetRequests(userId, componentName); 2091 } 2092 if (clearTileAddRequest(packageName)) { 2093 try { 2094 callback.onTileRequest(i); 2095 } catch (RemoteException e) { 2096 Slog.e(TAG, "requestAddTile - callback", e); 2097 } 2098 } 2099 } 2100 }; 2101 2102 CharSequence appName = r.serviceInfo.applicationInfo 2103 .loadLabel(mContext.getPackageManager()); 2104 IStatusBar bar = mBar; 2105 if (bar != null) { 2106 try { 2107 bar.requestAddTile(componentName, appName, label, icon, proxyCallback); 2108 return; 2109 } catch (RemoteException e) { 2110 Slog.e(TAG, "requestAddTile", e); 2111 } 2112 } 2113 clearTileAddRequest(packageName); 2114 try { 2115 callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE); 2116 } catch (RemoteException e) { 2117 Slog.e(TAG, "requestAddTile", e); 2118 } 2119 } 2120 2121 @Override cancelRequestAddTile(@onNull String packageName)2122 public void cancelRequestAddTile(@NonNull String packageName) { 2123 enforceStatusBar(); 2124 cancelRequestAddTileInternal(packageName); 2125 } 2126 cancelRequestAddTileInternal(String packageName)2127 private void cancelRequestAddTileInternal(String packageName) { 2128 clearTileAddRequest(packageName); 2129 IStatusBar bar = mBar; 2130 if (bar != null) { 2131 try { 2132 bar.cancelRequestAddTile(packageName); 2133 } catch (RemoteException e) { 2134 Slog.e(TAG, "requestAddTile", e); 2135 } 2136 } 2137 } 2138 clearTileAddRequest(String packageName)2139 private boolean clearTileAddRequest(String packageName) { 2140 synchronized (mCurrentRequestAddTilePackages) { 2141 return mCurrentRequestAddTilePackages.remove(packageName) != null; 2142 } 2143 } 2144 2145 @Override onSessionStarted(@essionFlags int sessionType, InstanceId instance)2146 public void onSessionStarted(@SessionFlags int sessionType, InstanceId instance) { 2147 mSessionMonitor.onSessionStarted(sessionType, instance); 2148 } 2149 2150 @Override onSessionEnded(@essionFlags int sessionType, InstanceId instance)2151 public void onSessionEnded(@SessionFlags int sessionType, InstanceId instance) { 2152 mSessionMonitor.onSessionEnded(sessionType, instance); 2153 } 2154 2155 @Override registerSessionListener(@essionFlags int sessionFlags, ISessionListener listener)2156 public void registerSessionListener(@SessionFlags int sessionFlags, 2157 ISessionListener listener) { 2158 mSessionMonitor.registerSessionListener(sessionFlags, listener); 2159 } 2160 2161 @Override unregisterSessionListener(@essionFlags int sessionFlags, ISessionListener listener)2162 public void unregisterSessionListener(@SessionFlags int sessionFlags, 2163 ISessionListener listener) { 2164 mSessionMonitor.unregisterSessionListener(sessionFlags, listener); 2165 } 2166 getStatusBarIcons()2167 public String[] getStatusBarIcons() { 2168 return mContext.getResources().getStringArray(R.array.config_statusBarIcons); 2169 } 2170 2171 /** 2172 * Sets or removes the navigation bar mode. 2173 * 2174 * @param navBarMode the mode of the navigation bar to be set. 2175 */ setNavBarMode(@avBarMode int navBarMode)2176 public void setNavBarMode(@NavBarMode int navBarMode) { 2177 enforceStatusBar(); 2178 if (navBarMode != NAV_BAR_MODE_DEFAULT && navBarMode != NAV_BAR_MODE_KIDS) { 2179 throw new IllegalArgumentException("Supplied navBarMode not supported: " + navBarMode); 2180 } 2181 2182 final int userId = mCurrentUserId; 2183 final int callingUserId = UserHandle.getUserId(Binder.getCallingUid()); 2184 if (mCurrentUserId != callingUserId && !doesCallerHoldInteractAcrossUserPermission()) { 2185 throw new SecurityException("Calling user id: " + callingUserId 2186 + ", cannot call on behalf of current user id: " + mCurrentUserId + "."); 2187 } 2188 final long userIdentity = Binder.clearCallingIdentity(); 2189 try { 2190 Settings.Secure.putIntForUser(mContext.getContentResolver(), 2191 Settings.Secure.NAV_BAR_KIDS_MODE, navBarMode, userId); 2192 Settings.Secure.putIntForUser(mContext.getContentResolver(), 2193 Settings.Secure.NAV_BAR_FORCE_VISIBLE, navBarMode, userId); 2194 2195 IOverlayManager overlayManager = getOverlayManager(); 2196 if (overlayManager != null && navBarMode == NAV_BAR_MODE_KIDS 2197 && isPackageSupported(NAV_BAR_MODE_3BUTTON_OVERLAY)) { 2198 overlayManager.setEnabledExclusiveInCategory(NAV_BAR_MODE_3BUTTON_OVERLAY, userId); 2199 } 2200 } catch (RemoteException e) { 2201 throw e.rethrowFromSystemServer(); 2202 } finally { 2203 Binder.restoreCallingIdentity(userIdentity); 2204 } 2205 } 2206 2207 /** 2208 * Gets the navigation bar mode. Returns default value if no mode is set. 2209 * 2210 * @hide 2211 */ getNavBarMode()2212 public @NavBarMode int getNavBarMode() { 2213 enforceStatusBar(); 2214 2215 int navBarKidsMode = NAV_BAR_MODE_DEFAULT; 2216 final int userId = mCurrentUserId; 2217 final long userIdentity = Binder.clearCallingIdentity(); 2218 try { 2219 navBarKidsMode = Settings.Secure.getIntForUser(mContext.getContentResolver(), 2220 Settings.Secure.NAV_BAR_KIDS_MODE, userId); 2221 } catch (Settings.SettingNotFoundException ex) { 2222 return navBarKidsMode; 2223 } finally { 2224 Binder.restoreCallingIdentity(userIdentity); 2225 } 2226 return navBarKidsMode; 2227 } 2228 isPackageSupported(String packageName)2229 private boolean isPackageSupported(String packageName) { 2230 if (packageName == null) { 2231 return false; 2232 } 2233 try { 2234 return mContext.getPackageManager().getPackageInfo(packageName, 2235 PackageManager.PackageInfoFlags.of(0)) != null; 2236 } catch (PackageManager.NameNotFoundException ignored) { 2237 if (SPEW) { 2238 Slog.d(TAG, "Package not found: " + packageName); 2239 } 2240 } 2241 return false; 2242 } 2243 2244 /** 2245 * Notifies the system of a new media tap-to-transfer state for the *sender* device. See 2246 * {@link StatusBarManager.updateMediaTapToTransferSenderDisplay} for more information. 2247 * 2248 * @param undoCallback a callback that will be triggered if the user elects to undo a media 2249 * transfer. 2250 * 2251 * Requires the caller to have the {@link android.Manifest.permission.MEDIA_CONTENT_CONTROL} 2252 * permission. 2253 */ 2254 @Override updateMediaTapToTransferSenderDisplay( @tatusBarManager.MediaTransferSenderState int displayState, @NonNull MediaRoute2Info routeInfo, @Nullable IUndoMediaTransferCallback undoCallback )2255 public void updateMediaTapToTransferSenderDisplay( 2256 @StatusBarManager.MediaTransferSenderState int displayState, 2257 @NonNull MediaRoute2Info routeInfo, 2258 @Nullable IUndoMediaTransferCallback undoCallback 2259 ) { 2260 enforceMediaContentControl(); 2261 IStatusBar bar = mBar; 2262 if (bar != null) { 2263 try { 2264 bar.updateMediaTapToTransferSenderDisplay(displayState, routeInfo, undoCallback); 2265 } catch (RemoteException e) { 2266 Slog.e(TAG, "updateMediaTapToTransferSenderDisplay", e); 2267 } 2268 } 2269 } 2270 2271 /** 2272 * Notifies the system of a new media tap-to-transfer state for the *receiver* device. See 2273 * {@link StatusBarManager.updateMediaTapToTransferReceiverDisplay} for more information. 2274 * 2275 * Requires the caller to have the {@link android.Manifest.permission.MEDIA_CONTENT_CONTROL} 2276 * permission. 2277 */ 2278 @Override updateMediaTapToTransferReceiverDisplay( @tatusBarManager.MediaTransferReceiverState int displayState, MediaRoute2Info routeInfo, @Nullable Icon appIcon, @Nullable CharSequence appName)2279 public void updateMediaTapToTransferReceiverDisplay( 2280 @StatusBarManager.MediaTransferReceiverState int displayState, 2281 MediaRoute2Info routeInfo, 2282 @Nullable Icon appIcon, 2283 @Nullable CharSequence appName) { 2284 enforceMediaContentControl(); 2285 IStatusBar bar = mBar; 2286 if (bar != null) { 2287 try { 2288 bar.updateMediaTapToTransferReceiverDisplay( 2289 displayState, routeInfo, appIcon, appName); 2290 } catch (RemoteException e) { 2291 Slog.e(TAG, "updateMediaTapToTransferReceiverDisplay", e); 2292 } 2293 } 2294 } 2295 2296 /** 2297 * Registers a provider that gives information about nearby devices that are able to play media. 2298 * See {@link StatusBarmanager.registerNearbyMediaDevicesProvider}. 2299 * 2300 * Requires the caller to have the {@link android.Manifest.permission.MEDIA_CONTENT_CONTROL} 2301 * permission. 2302 * 2303 * @param provider the nearby device information provider to register 2304 * 2305 * @hide 2306 */ 2307 @Override registerNearbyMediaDevicesProvider( @onNull INearbyMediaDevicesProvider provider )2308 public void registerNearbyMediaDevicesProvider( 2309 @NonNull INearbyMediaDevicesProvider provider 2310 ) { 2311 enforceMediaContentControl(); 2312 IStatusBar bar = mBar; 2313 if (bar != null) { 2314 try { 2315 bar.registerNearbyMediaDevicesProvider(provider); 2316 } catch (RemoteException e) { 2317 Slog.e(TAG, "registerNearbyMediaDevicesProvider", e); 2318 } 2319 } 2320 } 2321 2322 /** 2323 * Unregisters a provider that gives information about nearby devices that are able to play 2324 * media. See {@link StatusBarmanager.unregisterNearbyMediaDevicesProvider}. 2325 * 2326 * Requires the caller to have the {@link android.Manifest.permission.MEDIA_CONTENT_CONTROL} 2327 * permission. 2328 * 2329 * @param provider the nearby device information provider to unregister 2330 * 2331 * @hide 2332 */ 2333 @Override unregisterNearbyMediaDevicesProvider( @onNull INearbyMediaDevicesProvider provider )2334 public void unregisterNearbyMediaDevicesProvider( 2335 @NonNull INearbyMediaDevicesProvider provider 2336 ) { 2337 enforceMediaContentControl(); 2338 IStatusBar bar = mBar; 2339 if (bar != null) { 2340 try { 2341 bar.unregisterNearbyMediaDevicesProvider(provider); 2342 } catch (RemoteException e) { 2343 Slog.e(TAG, "unregisterNearbyMediaDevicesProvider", e); 2344 } 2345 } 2346 } 2347 2348 @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) 2349 @Override showRearDisplayDialog(int currentState)2350 public void showRearDisplayDialog(int currentState) { 2351 enforceControlDeviceStatePermission(); 2352 IStatusBar bar = mBar; 2353 if (bar != null) { 2354 try { 2355 bar.showRearDisplayDialog(currentState); 2356 } catch (RemoteException e) { 2357 Slog.e(TAG, "showRearDisplayDialog", e); 2358 } 2359 } 2360 } 2361 2362 /** @hide */ passThroughShellCommand(String[] args, FileDescriptor fd)2363 public void passThroughShellCommand(String[] args, FileDescriptor fd) { 2364 enforceStatusBarOrShell(); 2365 if (mBar == null) return; 2366 2367 try (TransferPipe tp = new TransferPipe()) { 2368 // Sending the command to the remote, which needs to execute async to avoid blocking 2369 // See Binder#dumpAsync() for inspiration 2370 tp.setBufferPrefix(" "); 2371 mBar.passThroughShellCommand(args, tp.getWriteFd()); 2372 // Times out after 5s 2373 tp.go(fd); 2374 } catch (Throwable t) { 2375 Slog.e(TAG, "Error sending command to IStatusBar", t); 2376 } 2377 } 2378 2379 // ================================================================================ 2380 // Can be called from any thread 2381 // ================================================================================ 2382 2383 // lock on mDisableRecords manageDisableListLocked(int userId, int what, IBinder token, String pkg, int which)2384 void manageDisableListLocked(int userId, int what, IBinder token, String pkg, int which) { 2385 if (SPEW) { 2386 Slog.d(TAG, "manageDisableList userId=" + userId 2387 + " what=0x" + Integer.toHexString(what) + " pkg=" + pkg); 2388 } 2389 2390 // Find matching record, if any 2391 Pair<Integer, DisableRecord> match = findMatchingRecordLocked(token, userId); 2392 int i = match.first; 2393 DisableRecord record = match.second; 2394 2395 // Remove record if binder is already dead 2396 if (!token.isBinderAlive()) { 2397 if (record != null) { 2398 mDisableRecords.remove(i); 2399 record.token.unlinkToDeath(record, 0); 2400 } 2401 return; 2402 } 2403 2404 // Update existing record 2405 if (record != null) { 2406 record.setFlags(what, which, pkg); 2407 if (record.isEmpty()) { 2408 mDisableRecords.remove(i); 2409 record.token.unlinkToDeath(record, 0); 2410 } 2411 return; 2412 } 2413 2414 // Record doesn't exist, so we create a new one 2415 record = new DisableRecord(userId, token); 2416 record.setFlags(what, which, pkg); 2417 mDisableRecords.add(record); 2418 } 2419 2420 @Nullable 2421 @GuardedBy("mLock") findMatchingRecordLocked(IBinder token, int userId)2422 private Pair<Integer, DisableRecord> findMatchingRecordLocked(IBinder token, int userId) { 2423 final int numRecords = mDisableRecords.size(); 2424 DisableRecord record = null; 2425 int i; 2426 for (i = 0; i < numRecords; i++) { 2427 DisableRecord r = mDisableRecords.get(i); 2428 if (r.token == token && r.userId == userId) { 2429 record = r; 2430 break; 2431 } 2432 } 2433 2434 return new Pair<Integer, DisableRecord>(i, record); 2435 } 2436 2437 // lock on mDisableRecords gatherDisableActionsLocked(int userId, int which)2438 int gatherDisableActionsLocked(int userId, int which) { 2439 final int N = mDisableRecords.size(); 2440 // gather the new net flags 2441 int net = 0; 2442 for (int i=0; i<N; i++) { 2443 final DisableRecord rec = mDisableRecords.get(i); 2444 if (rec.userId == userId) { 2445 net |= rec.getFlags(which); 2446 } 2447 } 2448 return net; 2449 } 2450 2451 // ================================================================================ 2452 // Always called from UI thread 2453 // ================================================================================ 2454 dump(FileDescriptor fd, PrintWriter pw, String[] args)2455 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2456 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 2457 boolean proto = false; 2458 for (int i = 0; i < args.length; i++) { 2459 if ("--proto".equals(args[i])) { 2460 proto = true; 2461 } 2462 } 2463 if (proto) { 2464 if (mBar == null) return; 2465 try (TransferPipe tp = new TransferPipe()) { 2466 // Sending the command to the remote, which needs to execute async to avoid blocking 2467 // See Binder#dumpAsync() for inspiration 2468 mBar.dumpProto(args, tp.getWriteFd()); 2469 // Times out after 5s 2470 tp.go(fd); 2471 } catch (Throwable t) { 2472 Slog.e(TAG, "Error sending command to IStatusBar", t); 2473 } 2474 return; 2475 } 2476 2477 synchronized (mLock) { 2478 for (int i = 0; i < mDisplayUiState.size(); i++) { 2479 final int key = mDisplayUiState.keyAt(i); 2480 final UiState state = mDisplayUiState.get(key); 2481 pw.println(" displayId=" + key); 2482 pw.println(" mDisabled1=0x" + Integer.toHexString(state.getDisabled1())); 2483 pw.println(" mDisabled2=0x" + Integer.toHexString(state.getDisabled2())); 2484 } 2485 final int N = mDisableRecords.size(); 2486 pw.println(" mDisableRecords.size=" + N); 2487 for (int i=0; i<N; i++) { 2488 DisableRecord tok = mDisableRecords.get(i); 2489 pw.println(" [" + i + "] " + tok); 2490 } 2491 pw.println(" mCurrentUserId=" + mCurrentUserId); 2492 pw.println(" mIcons="); 2493 for (String slot : mIcons.keySet()) { 2494 pw.println(" "); 2495 pw.print(slot); 2496 pw.print(" -> "); 2497 final StatusBarIcon icon = mIcons.get(slot); 2498 pw.print(icon); 2499 if (!TextUtils.isEmpty(icon.contentDescription)) { 2500 pw.print(" \""); 2501 pw.print(icon.contentDescription); 2502 pw.print("\""); 2503 } 2504 pw.println(); 2505 } 2506 ArrayList<String> requests; 2507 synchronized (mCurrentRequestAddTilePackages) { 2508 requests = new ArrayList<>(mCurrentRequestAddTilePackages.keySet()); 2509 } 2510 pw.println(" mCurrentRequestAddTilePackages=["); 2511 final int reqN = requests.size(); 2512 for (int i = 0; i < reqN; i++) { 2513 pw.println(" " + requests.get(i) + ","); 2514 } 2515 pw.println(" ]"); 2516 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 2517 mTileRequestTracker.dump(fd, ipw.increaseIndent(), args); 2518 } 2519 } 2520 getUiContext()2521 private static final Context getUiContext() { 2522 return ActivityThread.currentActivityThread().getSystemUiContext(); 2523 } 2524 } 2525