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