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.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS; 20 21 import android.app.ActivityThread; 22 import android.app.StatusBarManager; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.graphics.Rect; 26 import android.hardware.biometrics.IBiometricPromptReceiver; 27 import android.os.Binder; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.IBinder; 31 import android.os.PowerManager; 32 import android.os.Process; 33 import android.os.RemoteException; 34 import android.os.ResultReceiver; 35 import android.os.ShellCallback; 36 import android.os.UserHandle; 37 import android.service.notification.NotificationStats; 38 import android.text.TextUtils; 39 import android.util.ArrayMap; 40 import android.util.Slog; 41 42 import com.android.internal.R; 43 import com.android.internal.statusbar.IStatusBar; 44 import com.android.internal.statusbar.IStatusBarService; 45 import com.android.internal.statusbar.NotificationVisibility; 46 import com.android.internal.statusbar.StatusBarIcon; 47 import com.android.internal.util.DumpUtils; 48 import com.android.server.LocalServices; 49 import com.android.server.notification.NotificationDelegate; 50 import com.android.server.policy.GlobalActionsProvider; 51 import com.android.server.power.ShutdownThread; 52 import com.android.server.wm.WindowManagerService; 53 54 import java.io.FileDescriptor; 55 import java.io.PrintWriter; 56 import java.util.ArrayList; 57 import java.util.List; 58 59 /** 60 * A note on locking: We rely on the fact that calls onto mBar are oneway or 61 * if they are local, that they just enqueue messages to not deadlock. 62 */ 63 public class StatusBarManagerService extends IStatusBarService.Stub { 64 private static final String TAG = "StatusBarManagerService"; 65 private static final boolean SPEW = false; 66 67 private final Context mContext; 68 69 private final WindowManagerService mWindowManager; 70 private Handler mHandler = new Handler(); 71 private NotificationDelegate mNotificationDelegate; 72 private volatile IStatusBar mBar; 73 private ArrayMap<String, StatusBarIcon> mIcons = new ArrayMap<>(); 74 75 // for disabling the status bar 76 private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>(); 77 private GlobalActionsProvider.GlobalActionsListener mGlobalActionListener; 78 private IBinder mSysUiVisToken = new Binder(); 79 private int mDisabled1 = 0; 80 private int mDisabled2 = 0; 81 82 private final Object mLock = new Object(); 83 // encompasses lights-out mode and other flags defined on View 84 private int mSystemUiVisibility = 0; 85 private int mFullscreenStackSysUiVisibility; 86 private int mDockedStackSysUiVisibility; 87 private final Rect mFullscreenStackBounds = new Rect(); 88 private final Rect mDockedStackBounds = new Rect(); 89 private boolean mMenuVisible = false; 90 private int mImeWindowVis = 0; 91 private int mImeBackDisposition; 92 private boolean mShowImeSwitcher; 93 private IBinder mImeToken = null; 94 private int mCurrentUserId; 95 96 private class DisableRecord implements IBinder.DeathRecipient { 97 int userId; 98 String pkg; 99 int what1; 100 int what2; 101 IBinder token; 102 103 public DisableRecord(int userId, IBinder token) { 104 this.userId = userId; 105 this.token = token; 106 try { 107 token.linkToDeath(this, 0); 108 } catch (RemoteException re) { 109 // Give up 110 } 111 } 112 113 @Override 114 public void binderDied() { 115 Slog.i(TAG, "binder died for pkg=" + pkg); 116 disableForUser(0, token, pkg, userId); 117 disable2ForUser(0, token, pkg, userId); 118 token.unlinkToDeath(this, 0); 119 } 120 121 public void setFlags(int what, int which, String pkg) { 122 switch (which) { 123 case 1: 124 what1 = what; 125 return; 126 case 2: 127 what2 = what; 128 return; 129 default: 130 Slog.w(TAG, "Can't set unsupported disable flag " + which 131 + ": 0x" + Integer.toHexString(what)); 132 } 133 this.pkg = pkg; 134 } 135 136 public int getFlags(int which) { 137 switch (which) { 138 case 1: return what1; 139 case 2: return what2; 140 default: 141 Slog.w(TAG, "Can't get unsupported disable flag " + which); 142 return 0; 143 } 144 } 145 146 public boolean isEmpty() { 147 return what1 == 0 && what2 == 0; 148 } 149 150 @Override 151 public String toString() { 152 return String.format("userId=%d what1=0x%08X what2=0x%08X pkg=%s token=%s", 153 userId, what1, what2, pkg, token); 154 } 155 } 156 157 /** 158 * Construct the service, add the status bar view to the window manager 159 */ 160 public StatusBarManagerService(Context context, WindowManagerService windowManager) { 161 mContext = context; 162 mWindowManager = windowManager; 163 164 LocalServices.addService(StatusBarManagerInternal.class, mInternalService); 165 LocalServices.addService(GlobalActionsProvider.class, mGlobalActionsProvider); 166 } 167 168 /** 169 * Private API used by NotificationManagerService. 170 */ 171 private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() { 172 private boolean mNotificationLightOn; 173 174 @Override 175 public void setNotificationDelegate(NotificationDelegate delegate) { 176 mNotificationDelegate = delegate; 177 } 178 179 @Override 180 public void showScreenPinningRequest(int taskId) { 181 if (mBar != null) { 182 try { 183 mBar.showScreenPinningRequest(taskId); 184 } catch (RemoteException e) { 185 } 186 } 187 } 188 189 @Override 190 public void showAssistDisclosure() { 191 if (mBar != null) { 192 try { 193 mBar.showAssistDisclosure(); 194 } catch (RemoteException e) { 195 } 196 } 197 } 198 199 @Override 200 public void startAssist(Bundle args) { 201 if (mBar != null) { 202 try { 203 mBar.startAssist(args); 204 } catch (RemoteException e) { 205 } 206 } 207 } 208 209 @Override 210 public void onCameraLaunchGestureDetected(int source) { 211 if (mBar != null) { 212 try { 213 mBar.onCameraLaunchGestureDetected(source); 214 } catch (RemoteException e) { 215 } 216 } 217 } 218 219 @Override 220 public void topAppWindowChanged(boolean menuVisible) { 221 StatusBarManagerService.this.topAppWindowChanged(menuVisible); 222 } 223 224 @Override 225 public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, 226 int mask, 227 Rect fullscreenBounds, Rect dockedBounds, String cause) { 228 StatusBarManagerService.this.setSystemUiVisibility(vis, fullscreenStackVis, 229 dockedStackVis, mask, fullscreenBounds, dockedBounds, cause); 230 } 231 232 @Override 233 public void toggleSplitScreen() { 234 enforceStatusBarService(); 235 if (mBar != null) { 236 try { 237 mBar.toggleSplitScreen(); 238 } catch (RemoteException ex) {} 239 } 240 } 241 242 public void appTransitionFinished() { 243 enforceStatusBarService(); 244 if (mBar != null) { 245 try { 246 mBar.appTransitionFinished(); 247 } catch (RemoteException ex) {} 248 } 249 } 250 251 @Override 252 public void toggleRecentApps() { 253 if (mBar != null) { 254 try { 255 mBar.toggleRecentApps(); 256 } catch (RemoteException ex) {} 257 } 258 } 259 260 @Override 261 public void setCurrentUser(int newUserId) { 262 if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId); 263 mCurrentUserId = newUserId; 264 } 265 266 267 @Override 268 public void preloadRecentApps() { 269 if (mBar != null) { 270 try { 271 mBar.preloadRecentApps(); 272 } catch (RemoteException ex) {} 273 } 274 } 275 276 @Override 277 public void cancelPreloadRecentApps() { 278 if (mBar != null) { 279 try { 280 mBar.cancelPreloadRecentApps(); 281 } catch (RemoteException ex) {} 282 } 283 } 284 285 @Override 286 public void showRecentApps(boolean triggeredFromAltTab) { 287 if (mBar != null) { 288 try { 289 mBar.showRecentApps(triggeredFromAltTab); 290 } catch (RemoteException ex) {} 291 } 292 } 293 294 @Override 295 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 296 if (mBar != null) { 297 try { 298 mBar.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey); 299 } catch (RemoteException ex) {} 300 } 301 } 302 303 @Override 304 public void dismissKeyboardShortcutsMenu() { 305 if (mBar != null) { 306 try { 307 mBar.dismissKeyboardShortcutsMenu(); 308 } catch (RemoteException ex) {} 309 } 310 } 311 312 @Override 313 public void toggleKeyboardShortcutsMenu(int deviceId) { 314 if (mBar != null) { 315 try { 316 mBar.toggleKeyboardShortcutsMenu(deviceId); 317 } catch (RemoteException ex) {} 318 } 319 } 320 321 @Override 322 public void showChargingAnimation(int batteryLevel) { 323 if (mBar != null) { 324 try { 325 mBar.showWirelessChargingAnimation(batteryLevel); 326 } catch (RemoteException ex){ 327 } 328 } 329 } 330 331 @Override 332 public void showPictureInPictureMenu() { 333 if (mBar != null) { 334 try { 335 mBar.showPictureInPictureMenu(); 336 } catch (RemoteException ex) {} 337 } 338 } 339 340 @Override 341 public void setWindowState(int window, int state) { 342 if (mBar != null) { 343 try { 344 mBar.setWindowState(window, state); 345 } catch (RemoteException ex) {} 346 } 347 } 348 349 @Override 350 public void appTransitionPending() { 351 if (mBar != null) { 352 try { 353 mBar.appTransitionPending(); 354 } catch (RemoteException ex) {} 355 } 356 } 357 358 @Override 359 public void appTransitionCancelled() { 360 if (mBar != null) { 361 try { 362 mBar.appTransitionCancelled(); 363 } catch (RemoteException ex) {} 364 } 365 } 366 367 @Override 368 public void appTransitionStarting(long statusBarAnimationsStartTime, 369 long statusBarAnimationsDuration) { 370 if (mBar != null) { 371 try { 372 mBar.appTransitionStarting( 373 statusBarAnimationsStartTime, statusBarAnimationsDuration); 374 } catch (RemoteException ex) {} 375 } 376 } 377 378 @Override 379 public void setTopAppHidesStatusBar(boolean hidesStatusBar) { 380 if (mBar != null) { 381 try { 382 mBar.setTopAppHidesStatusBar(hidesStatusBar); 383 } catch (RemoteException ex) {} 384 } 385 } 386 387 @Override 388 public boolean showShutdownUi(boolean isReboot, String reason) { 389 if (!mContext.getResources().getBoolean(R.bool.config_showSysuiShutdown)) { 390 return false; 391 } 392 if (mBar != null) { 393 try { 394 mBar.showShutdownUi(isReboot, reason); 395 return true; 396 } catch (RemoteException ex) {} 397 } 398 return false; 399 } 400 401 @Override 402 public void onProposedRotationChanged(int rotation, boolean isValid) { 403 if (mBar != null){ 404 try { 405 mBar.onProposedRotationChanged(rotation, isValid); 406 } catch (RemoteException ex) {} 407 } 408 } 409 }; 410 411 private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() { 412 @Override 413 public boolean isGlobalActionsDisabled() { 414 return (mDisabled2 & DISABLE2_GLOBAL_ACTIONS) != 0; 415 } 416 417 @Override 418 public void setGlobalActionsListener(GlobalActionsProvider.GlobalActionsListener listener) { 419 mGlobalActionListener = listener; 420 mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null); 421 } 422 423 @Override 424 public void showGlobalActions() { 425 if (mBar != null) { 426 try { 427 mBar.showGlobalActionsMenu(); 428 } catch (RemoteException ex) {} 429 } 430 } 431 }; 432 433 // ================================================================================ 434 // From IStatusBarService 435 // ================================================================================ 436 @Override 437 public void expandNotificationsPanel() { 438 enforceExpandStatusBar(); 439 440 if (mBar != null) { 441 try { 442 mBar.animateExpandNotificationsPanel(); 443 } catch (RemoteException ex) { 444 } 445 } 446 } 447 448 @Override 449 public void collapsePanels() { 450 enforceExpandStatusBar(); 451 452 if (mBar != null) { 453 try { 454 mBar.animateCollapsePanels(); 455 } catch (RemoteException ex) { 456 } 457 } 458 } 459 460 @Override 461 public void togglePanel() { 462 enforceExpandStatusBar(); 463 464 if (mBar != null) { 465 try { 466 mBar.togglePanel(); 467 } catch (RemoteException ex) { 468 } 469 } 470 } 471 472 @Override 473 public void expandSettingsPanel(String subPanel) { 474 enforceExpandStatusBar(); 475 476 if (mBar != null) { 477 try { 478 mBar.animateExpandSettingsPanel(subPanel); 479 } catch (RemoteException ex) { 480 } 481 } 482 } 483 484 public void addTile(ComponentName component) { 485 enforceStatusBarOrShell(); 486 487 if (mBar != null) { 488 try { 489 mBar.addQsTile(component); 490 } catch (RemoteException ex) { 491 } 492 } 493 } 494 495 public void remTile(ComponentName component) { 496 enforceStatusBarOrShell(); 497 498 if (mBar != null) { 499 try { 500 mBar.remQsTile(component); 501 } catch (RemoteException ex) { 502 } 503 } 504 } 505 506 public void clickTile(ComponentName component) { 507 enforceStatusBarOrShell(); 508 509 if (mBar != null) { 510 try { 511 mBar.clickQsTile(component); 512 } catch (RemoteException ex) { 513 } 514 } 515 } 516 517 @Override 518 public void handleSystemKey(int key) throws RemoteException { 519 enforceExpandStatusBar(); 520 521 if (mBar != null) { 522 try { 523 mBar.handleSystemKey(key); 524 } catch (RemoteException ex) { 525 } 526 } 527 } 528 529 @Override 530 public void showPinningEnterExitToast(boolean entering) throws RemoteException { 531 if (mBar != null) { 532 try { 533 mBar.showPinningEnterExitToast(entering); 534 } catch (RemoteException ex) { 535 } 536 } 537 } 538 539 @Override 540 public void showPinningEscapeToast() throws RemoteException { 541 if (mBar != null) { 542 try { 543 mBar.showPinningEscapeToast(); 544 } catch (RemoteException ex) { 545 } 546 } 547 } 548 549 @Override 550 public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) { 551 if (mBar != null) { 552 try { 553 mBar.showFingerprintDialog(bundle, receiver); 554 } catch (RemoteException ex) { 555 } 556 } 557 } 558 559 @Override 560 public void onFingerprintAuthenticated() { 561 if (mBar != null) { 562 try { 563 mBar.onFingerprintAuthenticated(); 564 } catch (RemoteException ex) { 565 } 566 } 567 } 568 569 @Override 570 public void onFingerprintHelp(String message) { 571 if (mBar != null) { 572 try { 573 mBar.onFingerprintHelp(message); 574 } catch (RemoteException ex) { 575 } 576 } 577 } 578 579 @Override 580 public void onFingerprintError(String error) { 581 if (mBar != null) { 582 try { 583 mBar.onFingerprintError(error); 584 } catch (RemoteException ex) { 585 } 586 } 587 } 588 589 @Override 590 public void hideFingerprintDialog() { 591 if (mBar != null) { 592 try { 593 mBar.hideFingerprintDialog(); 594 } catch (RemoteException ex) { 595 } 596 } 597 } 598 599 @Override 600 public void disable(int what, IBinder token, String pkg) { 601 disableForUser(what, token, pkg, mCurrentUserId); 602 } 603 604 @Override 605 public void disableForUser(int what, IBinder token, String pkg, int userId) { 606 enforceStatusBar(); 607 608 synchronized (mLock) { 609 disableLocked(userId, what, token, pkg, 1); 610 } 611 } 612 613 /** 614 * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags. 615 * To re-enable everything, pass {@link #DISABLE_NONE}. 616 * 617 * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. 618 */ 619 @Override 620 public void disable2(int what, IBinder token, String pkg) { 621 disable2ForUser(what, token, pkg, mCurrentUserId); 622 } 623 624 /** 625 * Disable additional status bar features for a given user. Pass the bitwise-or of the 626 * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}. 627 * 628 * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. 629 */ 630 @Override 631 public void disable2ForUser(int what, IBinder token, String pkg, int userId) { 632 enforceStatusBar(); 633 634 synchronized (mLock) { 635 disableLocked(userId, what, token, pkg, 2); 636 } 637 } 638 639 private void disableLocked(int userId, int what, IBinder token, String pkg, int whichFlag) { 640 // It's important that the the callback and the call to mBar get done 641 // in the same order when multiple threads are calling this function 642 // so they are paired correctly. The messages on the handler will be 643 // handled in the order they were enqueued, but will be outside the lock. 644 manageDisableListLocked(userId, what, token, pkg, whichFlag); 645 646 // Ensure state for the current user is applied, even if passed a non-current user. 647 final int net1 = gatherDisableActionsLocked(mCurrentUserId, 1); 648 final int net2 = gatherDisableActionsLocked(mCurrentUserId, 2); 649 if (net1 != mDisabled1 || net2 != mDisabled2) { 650 mDisabled1 = net1; 651 mDisabled2 = net2; 652 mHandler.post(new Runnable() { 653 public void run() { 654 mNotificationDelegate.onSetDisabled(net1); 655 } 656 }); 657 if (mBar != null) { 658 try { 659 mBar.disable(net1, net2); 660 } catch (RemoteException ex) { 661 } 662 } 663 } 664 } 665 666 @Override 667 public void setIcon(String slot, String iconPackage, int iconId, int iconLevel, 668 String contentDescription) { 669 enforceStatusBar(); 670 671 synchronized (mIcons) { 672 StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId, 673 iconLevel, 0, contentDescription); 674 //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon); 675 mIcons.put(slot, icon); 676 677 if (mBar != null) { 678 try { 679 mBar.setIcon(slot, icon); 680 } catch (RemoteException ex) { 681 } 682 } 683 } 684 } 685 686 @Override 687 public void setIconVisibility(String slot, boolean visibility) { 688 enforceStatusBar(); 689 690 synchronized (mIcons) { 691 StatusBarIcon icon = mIcons.get(slot); 692 if (icon == null) { 693 return; 694 } 695 if (icon.visible != visibility) { 696 icon.visible = visibility; 697 698 if (mBar != null) { 699 try { 700 mBar.setIcon(slot, icon); 701 } catch (RemoteException ex) { 702 } 703 } 704 } 705 } 706 } 707 708 @Override 709 public void removeIcon(String slot) { 710 enforceStatusBar(); 711 712 synchronized (mIcons) { 713 mIcons.remove(slot); 714 715 if (mBar != null) { 716 try { 717 mBar.removeIcon(slot); 718 } catch (RemoteException ex) { 719 } 720 } 721 } 722 } 723 724 /** 725 * Hide or show the on-screen Menu key. Only call this from the window manager, typically in 726 * response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set 727 * to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}. 728 */ 729 private void topAppWindowChanged(final boolean menuVisible) { 730 enforceStatusBar(); 731 732 if (SPEW) Slog.d(TAG, (menuVisible?"showing":"hiding") + " MENU key"); 733 734 synchronized(mLock) { 735 mMenuVisible = menuVisible; 736 mHandler.post(new Runnable() { 737 public void run() { 738 if (mBar != null) { 739 try { 740 mBar.topAppWindowChanged(menuVisible); 741 } catch (RemoteException ex) { 742 } 743 } 744 } 745 }); 746 } 747 } 748 749 @Override 750 public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition, 751 final boolean showImeSwitcher) { 752 enforceStatusBar(); 753 754 if (SPEW) { 755 Slog.d(TAG, "swetImeWindowStatus vis=" + vis + " backDisposition=" + backDisposition); 756 } 757 758 synchronized(mLock) { 759 // In case of IME change, we need to call up setImeWindowStatus() regardless of 760 // mImeWindowVis because mImeWindowVis may not have been set to false when the 761 // previous IME was destroyed. 762 mImeWindowVis = vis; 763 mImeBackDisposition = backDisposition; 764 mImeToken = token; 765 mShowImeSwitcher = showImeSwitcher; 766 mHandler.post(new Runnable() { 767 public void run() { 768 if (mBar != null) { 769 try { 770 mBar.setImeWindowStatus(token, vis, backDisposition, showImeSwitcher); 771 } catch (RemoteException ex) { 772 } 773 } 774 } 775 }); 776 } 777 } 778 779 @Override 780 public void setSystemUiVisibility(int vis, int mask, String cause) { 781 setSystemUiVisibility(vis, 0, 0, mask, mFullscreenStackBounds, mDockedStackBounds, cause); 782 } 783 784 private void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask, 785 Rect fullscreenBounds, Rect dockedBounds, String cause) { 786 // also allows calls from window manager which is in this process. 787 enforceStatusBarService(); 788 789 if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")"); 790 791 synchronized (mLock) { 792 updateUiVisibilityLocked(vis, fullscreenStackVis, dockedStackVis, mask, 793 fullscreenBounds, dockedBounds); 794 disableLocked( 795 mCurrentUserId, 796 vis & StatusBarManager.DISABLE_MASK, 797 mSysUiVisToken, 798 cause, 1); 799 } 800 } 801 802 private void updateUiVisibilityLocked(final int vis, 803 final int fullscreenStackVis, final int dockedStackVis, final int mask, 804 final Rect fullscreenBounds, final Rect dockedBounds) { 805 if (mSystemUiVisibility != vis 806 || mFullscreenStackSysUiVisibility != fullscreenStackVis 807 || mDockedStackSysUiVisibility != dockedStackVis 808 || !mFullscreenStackBounds.equals(fullscreenBounds) 809 || !mDockedStackBounds.equals(dockedBounds)) { 810 mSystemUiVisibility = vis; 811 mFullscreenStackSysUiVisibility = fullscreenStackVis; 812 mDockedStackSysUiVisibility = dockedStackVis; 813 mFullscreenStackBounds.set(fullscreenBounds); 814 mDockedStackBounds.set(dockedBounds); 815 mHandler.post(new Runnable() { 816 public void run() { 817 if (mBar != null) { 818 try { 819 mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis, 820 mask, fullscreenBounds, dockedBounds); 821 } catch (RemoteException ex) { 822 } 823 } 824 } 825 }); 826 } 827 } 828 829 private void enforceStatusBarOrShell() { 830 if (Binder.getCallingUid() == Process.SHELL_UID) { 831 return; 832 } 833 enforceStatusBar(); 834 } 835 836 private void enforceStatusBar() { 837 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR, 838 "StatusBarManagerService"); 839 } 840 841 private void enforceExpandStatusBar() { 842 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.EXPAND_STATUS_BAR, 843 "StatusBarManagerService"); 844 } 845 846 private void enforceStatusBarService() { 847 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 848 "StatusBarManagerService"); 849 } 850 851 // ================================================================================ 852 // Callbacks from the status bar service. 853 // ================================================================================ 854 @Override 855 public void registerStatusBar(IStatusBar bar, List<String> iconSlots, 856 List<StatusBarIcon> iconList, int switches[], List<IBinder> binders, 857 Rect fullscreenStackBounds, Rect dockedStackBounds) { 858 enforceStatusBarService(); 859 860 Slog.i(TAG, "registerStatusBar bar=" + bar); 861 mBar = bar; 862 try { 863 mBar.asBinder().linkToDeath(new DeathRecipient() { 864 @Override 865 public void binderDied() { 866 mBar = null; 867 notifyBarAttachChanged(); 868 } 869 }, 0); 870 } catch (RemoteException e) { 871 } 872 notifyBarAttachChanged(); 873 synchronized (mIcons) { 874 for (String slot : mIcons.keySet()) { 875 iconSlots.add(slot); 876 iconList.add(mIcons.get(slot)); 877 } 878 } 879 synchronized (mLock) { 880 switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1); 881 switches[1] = mSystemUiVisibility; 882 switches[2] = mMenuVisible ? 1 : 0; 883 switches[3] = mImeWindowVis; 884 switches[4] = mImeBackDisposition; 885 switches[5] = mShowImeSwitcher ? 1 : 0; 886 switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2); 887 switches[7] = mFullscreenStackSysUiVisibility; 888 switches[8] = mDockedStackSysUiVisibility; 889 binders.add(mImeToken); 890 fullscreenStackBounds.set(mFullscreenStackBounds); 891 dockedStackBounds.set(mDockedStackBounds); 892 } 893 } 894 895 private void notifyBarAttachChanged() { 896 mHandler.post(() -> { 897 if (mGlobalActionListener == null) return; 898 mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null); 899 }); 900 } 901 902 /** 903 * @param clearNotificationEffects whether to consider notifications as "shown" and stop 904 * LED, vibration, and ringing 905 */ 906 @Override 907 public void onPanelRevealed(boolean clearNotificationEffects, int numItems) { 908 enforceStatusBarService(); 909 long identity = Binder.clearCallingIdentity(); 910 try { 911 mNotificationDelegate.onPanelRevealed(clearNotificationEffects, numItems); 912 } finally { 913 Binder.restoreCallingIdentity(identity); 914 } 915 } 916 917 @Override 918 public void clearNotificationEffects() throws RemoteException { 919 enforceStatusBarService(); 920 long identity = Binder.clearCallingIdentity(); 921 try { 922 mNotificationDelegate.clearEffects(); 923 } finally { 924 Binder.restoreCallingIdentity(identity); 925 } 926 } 927 928 @Override 929 public void onPanelHidden() throws RemoteException { 930 enforceStatusBarService(); 931 long identity = Binder.clearCallingIdentity(); 932 try { 933 mNotificationDelegate.onPanelHidden(); 934 } finally { 935 Binder.restoreCallingIdentity(identity); 936 } 937 } 938 939 /** 940 * Allows the status bar to shutdown the device. 941 */ 942 @Override 943 public void shutdown() { 944 enforceStatusBarService(); 945 long identity = Binder.clearCallingIdentity(); 946 try { 947 // ShutdownThread displays UI, so give it a UI context. 948 mHandler.post(() -> 949 ShutdownThread.shutdown(getUiContext(), 950 PowerManager.SHUTDOWN_USER_REQUESTED, false)); 951 } finally { 952 Binder.restoreCallingIdentity(identity); 953 } 954 } 955 956 /** 957 * Allows the status bar to reboot the device. 958 */ 959 @Override 960 public void reboot(boolean safeMode) { 961 enforceStatusBarService(); 962 long identity = Binder.clearCallingIdentity(); 963 try { 964 mHandler.post(() -> { 965 // ShutdownThread displays UI, so give it a UI context. 966 if (safeMode) { 967 ShutdownThread.rebootSafeMode(getUiContext(), true); 968 } else { 969 ShutdownThread.reboot(getUiContext(), 970 PowerManager.SHUTDOWN_USER_REQUESTED, false); 971 } 972 }); 973 } finally { 974 Binder.restoreCallingIdentity(identity); 975 } 976 } 977 978 @Override 979 public void onGlobalActionsShown() { 980 enforceStatusBarService(); 981 long identity = Binder.clearCallingIdentity(); 982 try { 983 if (mGlobalActionListener == null) return; 984 mGlobalActionListener.onGlobalActionsShown(); 985 } finally { 986 Binder.restoreCallingIdentity(identity); 987 } 988 } 989 990 @Override 991 public void onGlobalActionsHidden() { 992 enforceStatusBarService(); 993 long identity = Binder.clearCallingIdentity(); 994 try { 995 if (mGlobalActionListener == null) return; 996 mGlobalActionListener.onGlobalActionsDismissed(); 997 } finally { 998 Binder.restoreCallingIdentity(identity); 999 } 1000 } 1001 1002 @Override 1003 public void onNotificationClick(String key, NotificationVisibility nv) { 1004 enforceStatusBarService(); 1005 final int callingUid = Binder.getCallingUid(); 1006 final int callingPid = Binder.getCallingPid(); 1007 long identity = Binder.clearCallingIdentity(); 1008 try { 1009 mNotificationDelegate.onNotificationClick(callingUid, callingPid, key, nv); 1010 } finally { 1011 Binder.restoreCallingIdentity(identity); 1012 } 1013 } 1014 1015 @Override 1016 public void onNotificationActionClick(String key, int actionIndex, NotificationVisibility nv) { 1017 enforceStatusBarService(); 1018 final int callingUid = Binder.getCallingUid(); 1019 final int callingPid = Binder.getCallingPid(); 1020 long identity = Binder.clearCallingIdentity(); 1021 try { 1022 mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key, 1023 actionIndex, nv); 1024 } finally { 1025 Binder.restoreCallingIdentity(identity); 1026 } 1027 } 1028 1029 @Override 1030 public void onNotificationError(String pkg, String tag, int id, 1031 int uid, int initialPid, String message, int userId) { 1032 enforceStatusBarService(); 1033 final int callingUid = Binder.getCallingUid(); 1034 final int callingPid = Binder.getCallingPid(); 1035 long identity = Binder.clearCallingIdentity(); 1036 try { 1037 // WARNING: this will call back into us to do the remove. Don't hold any locks. 1038 mNotificationDelegate.onNotificationError(callingUid, callingPid, 1039 pkg, tag, id, uid, initialPid, message, userId); 1040 } finally { 1041 Binder.restoreCallingIdentity(identity); 1042 } 1043 } 1044 1045 @Override 1046 public void onNotificationClear(String pkg, String tag, int id, int userId, String key, 1047 @NotificationStats.DismissalSurface int dismissalSurface, NotificationVisibility nv) { 1048 enforceStatusBarService(); 1049 final int callingUid = Binder.getCallingUid(); 1050 final int callingPid = Binder.getCallingPid(); 1051 long identity = Binder.clearCallingIdentity(); 1052 try { 1053 mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId, 1054 key, dismissalSurface, nv); 1055 } finally { 1056 Binder.restoreCallingIdentity(identity); 1057 } 1058 } 1059 1060 @Override 1061 public void onNotificationVisibilityChanged( 1062 NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys) 1063 throws RemoteException { 1064 enforceStatusBarService(); 1065 long identity = Binder.clearCallingIdentity(); 1066 try { 1067 mNotificationDelegate.onNotificationVisibilityChanged( 1068 newlyVisibleKeys, noLongerVisibleKeys); 1069 } finally { 1070 Binder.restoreCallingIdentity(identity); 1071 } 1072 } 1073 1074 @Override 1075 public void onNotificationExpansionChanged(String key, boolean userAction, 1076 boolean expanded) throws RemoteException { 1077 enforceStatusBarService(); 1078 long identity = Binder.clearCallingIdentity(); 1079 try { 1080 mNotificationDelegate.onNotificationExpansionChanged( 1081 key, userAction, expanded); 1082 } finally { 1083 Binder.restoreCallingIdentity(identity); 1084 } 1085 } 1086 1087 @Override 1088 public void onNotificationDirectReplied(String key) throws RemoteException { 1089 enforceStatusBarService(); 1090 long identity = Binder.clearCallingIdentity(); 1091 try { 1092 mNotificationDelegate.onNotificationDirectReplied(key); 1093 } finally { 1094 Binder.restoreCallingIdentity(identity); 1095 } 1096 } 1097 1098 @Override 1099 public void onNotificationSmartRepliesAdded(String key, int replyCount) 1100 throws RemoteException { 1101 enforceStatusBarService(); 1102 long identity = Binder.clearCallingIdentity(); 1103 try { 1104 mNotificationDelegate.onNotificationSmartRepliesAdded(key, replyCount); 1105 } finally { 1106 Binder.restoreCallingIdentity(identity); 1107 } 1108 } 1109 1110 @Override 1111 public void onNotificationSmartReplySent(String key, int replyIndex) 1112 throws RemoteException { 1113 enforceStatusBarService(); 1114 long identity = Binder.clearCallingIdentity(); 1115 try { 1116 mNotificationDelegate.onNotificationSmartReplySent(key, replyIndex); 1117 } finally { 1118 Binder.restoreCallingIdentity(identity); 1119 } 1120 } 1121 1122 @Override 1123 public void onNotificationSettingsViewed(String key) throws RemoteException { 1124 enforceStatusBarService(); 1125 long identity = Binder.clearCallingIdentity(); 1126 try { 1127 mNotificationDelegate.onNotificationSettingsViewed(key); 1128 } finally { 1129 Binder.restoreCallingIdentity(identity); 1130 } 1131 } 1132 1133 @Override 1134 public void onClearAllNotifications(int userId) { 1135 enforceStatusBarService(); 1136 final int callingUid = Binder.getCallingUid(); 1137 final int callingPid = Binder.getCallingPid(); 1138 long identity = Binder.clearCallingIdentity(); 1139 try { 1140 mNotificationDelegate.onClearAll(callingUid, callingPid, userId); 1141 } finally { 1142 Binder.restoreCallingIdentity(identity); 1143 } 1144 } 1145 1146 @Override 1147 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 1148 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 1149 (new StatusBarShellCommand(this)).exec( 1150 this, in, out, err, args, callback, resultReceiver); 1151 } 1152 1153 public String[] getStatusBarIcons() { 1154 return mContext.getResources().getStringArray(R.array.config_statusBarIcons); 1155 } 1156 1157 // ================================================================================ 1158 // Can be called from any thread 1159 // ================================================================================ 1160 1161 // lock on mDisableRecords 1162 void manageDisableListLocked(int userId, int what, IBinder token, String pkg, int which) { 1163 if (SPEW) { 1164 Slog.d(TAG, "manageDisableList userId=" + userId 1165 + " what=0x" + Integer.toHexString(what) + " pkg=" + pkg); 1166 } 1167 1168 // Find matching record, if any 1169 final int N = mDisableRecords.size(); 1170 DisableRecord record = null; 1171 int i; 1172 for (i = 0; i < N; i++) { 1173 DisableRecord r = mDisableRecords.get(i); 1174 if (r.token == token && r.userId == userId) { 1175 record = r; 1176 break; 1177 } 1178 } 1179 1180 // Remove record if binder is already dead 1181 if (!token.isBinderAlive()) { 1182 if (record != null) { 1183 mDisableRecords.remove(i); 1184 record.token.unlinkToDeath(record, 0); 1185 } 1186 return; 1187 } 1188 1189 // Update existing record 1190 if (record != null) { 1191 record.setFlags(what, which, pkg); 1192 if (record.isEmpty()) { 1193 mDisableRecords.remove(i); 1194 record.token.unlinkToDeath(record, 0); 1195 } 1196 return; 1197 } 1198 1199 // Record doesn't exist, so we create a new one 1200 record = new DisableRecord(userId, token); 1201 record.setFlags(what, which, pkg); 1202 mDisableRecords.add(record); 1203 } 1204 1205 // lock on mDisableRecords 1206 int gatherDisableActionsLocked(int userId, int which) { 1207 final int N = mDisableRecords.size(); 1208 // gather the new net flags 1209 int net = 0; 1210 for (int i=0; i<N; i++) { 1211 final DisableRecord rec = mDisableRecords.get(i); 1212 if (rec.userId == userId) { 1213 net |= rec.getFlags(which); 1214 } 1215 } 1216 return net; 1217 } 1218 1219 // ================================================================================ 1220 // Always called from UI thread 1221 // ================================================================================ 1222 1223 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1224 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 1225 1226 synchronized (mLock) { 1227 pw.println(" mDisabled1=0x" + Integer.toHexString(mDisabled1)); 1228 pw.println(" mDisabled2=0x" + Integer.toHexString(mDisabled2)); 1229 final int N = mDisableRecords.size(); 1230 pw.println(" mDisableRecords.size=" + N); 1231 for (int i=0; i<N; i++) { 1232 DisableRecord tok = mDisableRecords.get(i); 1233 pw.println(" [" + i + "] " + tok); 1234 } 1235 pw.println(" mCurrentUserId=" + mCurrentUserId); 1236 pw.println(" mIcons="); 1237 for (String slot : mIcons.keySet()) { 1238 pw.println(" "); 1239 pw.print(slot); 1240 pw.print(" -> "); 1241 final StatusBarIcon icon = mIcons.get(slot); 1242 pw.print(icon); 1243 if (!TextUtils.isEmpty(icon.contentDescription)) { 1244 pw.print(" \""); 1245 pw.print(icon.contentDescription); 1246 pw.print("\""); 1247 } 1248 pw.println(); 1249 } 1250 } 1251 } 1252 1253 private static final Context getUiContext() { 1254 return ActivityThread.currentActivityThread().getSystemUiContext(); 1255 } 1256 } 1257