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 android.app.ActivityThread; 20 import android.app.StatusBarManager; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.content.pm.PackageManager; 24 import android.graphics.Rect; 25 import android.os.Binder; 26 import android.os.Bundle; 27 import android.os.Handler; 28 import android.os.IBinder; 29 import android.os.PowerManager; 30 import android.os.Process; 31 import android.os.RemoteException; 32 import android.os.ResultReceiver; 33 import android.os.ShellCallback; 34 import android.os.UserHandle; 35 import android.text.TextUtils; 36 import android.util.ArrayMap; 37 import android.util.Slog; 38 39 import com.android.internal.statusbar.IStatusBar; 40 import com.android.internal.statusbar.IStatusBarService; 41 import com.android.internal.statusbar.NotificationVisibility; 42 import com.android.internal.statusbar.StatusBarIcon; 43 import com.android.internal.util.DumpUtils; 44 import com.android.server.LocalServices; 45 import com.android.server.notification.NotificationDelegate; 46 import com.android.server.power.ShutdownThread; 47 import com.android.server.statusbar.StatusBarManagerInternal.GlobalActionsListener; 48 import com.android.server.wm.WindowManagerService; 49 50 import java.io.FileDescriptor; 51 import java.io.PrintWriter; 52 import java.util.ArrayList; 53 import 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 */ 60 public 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 334 // ================================================================================ 335 // From IStatusBarService 336 // ================================================================================ 337 @Override 338 public void expandNotificationsPanel() { 339 enforceExpandStatusBar(); 340 341 if (mBar != null) { 342 try { 343 mBar.animateExpandNotificationsPanel(); 344 } catch (RemoteException ex) { 345 } 346 } 347 } 348 349 @Override 350 public void collapsePanels() { 351 enforceExpandStatusBar(); 352 353 if (mBar != null) { 354 try { 355 mBar.animateCollapsePanels(); 356 } catch (RemoteException ex) { 357 } 358 } 359 } 360 361 @Override 362 public void expandSettingsPanel(String subPanel) { 363 enforceExpandStatusBar(); 364 365 if (mBar != null) { 366 try { 367 mBar.animateExpandSettingsPanel(subPanel); 368 } catch (RemoteException ex) { 369 } 370 } 371 } 372 373 public void addTile(ComponentName component) { 374 enforceStatusBarOrShell(); 375 376 if (mBar != null) { 377 try { 378 mBar.addQsTile(component); 379 } catch (RemoteException ex) { 380 } 381 } 382 } 383 384 public void remTile(ComponentName component) { 385 enforceStatusBarOrShell(); 386 387 if (mBar != null) { 388 try { 389 mBar.remQsTile(component); 390 } catch (RemoteException ex) { 391 } 392 } 393 } 394 395 public void clickTile(ComponentName component) { 396 enforceStatusBarOrShell(); 397 398 if (mBar != null) { 399 try { 400 mBar.clickQsTile(component); 401 } catch (RemoteException ex) { 402 } 403 } 404 } 405 406 @Override 407 public void handleSystemNavigationKey(int key) throws RemoteException { 408 enforceExpandStatusBar(); 409 410 if (mBar != null) { 411 try { 412 mBar.handleSystemNavigationKey(key); 413 } catch (RemoteException ex) { 414 } 415 } 416 } 417 418 @Override 419 public void disable(int what, IBinder token, String pkg) { 420 disableForUser(what, token, pkg, mCurrentUserId); 421 } 422 423 @Override 424 public void disableForUser(int what, IBinder token, String pkg, int userId) { 425 enforceStatusBar(); 426 427 synchronized (mLock) { 428 disableLocked(userId, what, token, pkg, 1); 429 } 430 } 431 432 /** 433 * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags. 434 * To re-enable everything, pass {@link #DISABLE_NONE}. 435 * 436 * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. 437 */ 438 @Override 439 public void disable2(int what, IBinder token, String pkg) { 440 disable2ForUser(what, token, pkg, mCurrentUserId); 441 } 442 443 /** 444 * Disable additional status bar features for a given user. Pass the bitwise-or of the 445 * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}. 446 * 447 * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. 448 */ 449 @Override 450 public void disable2ForUser(int what, IBinder token, String pkg, int userId) { 451 enforceStatusBar(); 452 453 synchronized (mLock) { 454 disableLocked(userId, what, token, pkg, 2); 455 } 456 } 457 458 private void disableLocked(int userId, int what, IBinder token, String pkg, int whichFlag) { 459 // It's important that the the callback and the call to mBar get done 460 // in the same order when multiple threads are calling this function 461 // so they are paired correctly. The messages on the handler will be 462 // handled in the order they were enqueued, but will be outside the lock. 463 manageDisableListLocked(userId, what, token, pkg, whichFlag); 464 465 // Ensure state for the current user is applied, even if passed a non-current user. 466 final int net1 = gatherDisableActionsLocked(mCurrentUserId, 1); 467 final int net2 = gatherDisableActionsLocked(mCurrentUserId, 2); 468 if (net1 != mDisabled1 || net2 != mDisabled2) { 469 mDisabled1 = net1; 470 mDisabled2 = net2; 471 mHandler.post(new Runnable() { 472 public void run() { 473 mNotificationDelegate.onSetDisabled(net1); 474 } 475 }); 476 if (mBar != null) { 477 try { 478 mBar.disable(net1, net2); 479 } catch (RemoteException ex) { 480 } 481 } 482 } 483 } 484 485 @Override 486 public void setIcon(String slot, String iconPackage, int iconId, int iconLevel, 487 String contentDescription) { 488 enforceStatusBar(); 489 490 synchronized (mIcons) { 491 StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId, 492 iconLevel, 0, contentDescription); 493 //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon); 494 mIcons.put(slot, icon); 495 496 if (mBar != null) { 497 try { 498 mBar.setIcon(slot, icon); 499 } catch (RemoteException ex) { 500 } 501 } 502 } 503 } 504 505 @Override 506 public void setIconVisibility(String slot, boolean visibility) { 507 enforceStatusBar(); 508 509 synchronized (mIcons) { 510 StatusBarIcon icon = mIcons.get(slot); 511 if (icon == null) { 512 return; 513 } 514 if (icon.visible != visibility) { 515 icon.visible = visibility; 516 517 if (mBar != null) { 518 try { 519 mBar.setIcon(slot, icon); 520 } catch (RemoteException ex) { 521 } 522 } 523 } 524 } 525 } 526 527 @Override 528 public void removeIcon(String slot) { 529 enforceStatusBar(); 530 531 synchronized (mIcons) { 532 mIcons.remove(slot); 533 534 if (mBar != null) { 535 try { 536 mBar.removeIcon(slot); 537 } catch (RemoteException ex) { 538 } 539 } 540 } 541 } 542 543 /** 544 * Hide or show the on-screen Menu key. Only call this from the window manager, typically in 545 * response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set 546 * to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}. 547 */ 548 private void topAppWindowChanged(final boolean menuVisible) { 549 enforceStatusBar(); 550 551 if (SPEW) Slog.d(TAG, (menuVisible?"showing":"hiding") + " MENU key"); 552 553 synchronized(mLock) { 554 mMenuVisible = menuVisible; 555 mHandler.post(new Runnable() { 556 public void run() { 557 if (mBar != null) { 558 try { 559 mBar.topAppWindowChanged(menuVisible); 560 } catch (RemoteException ex) { 561 } 562 } 563 } 564 }); 565 } 566 } 567 568 @Override 569 public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition, 570 final boolean showImeSwitcher) { 571 enforceStatusBar(); 572 573 if (SPEW) { 574 Slog.d(TAG, "swetImeWindowStatus vis=" + vis + " backDisposition=" + backDisposition); 575 } 576 577 synchronized(mLock) { 578 // In case of IME change, we need to call up setImeWindowStatus() regardless of 579 // mImeWindowVis because mImeWindowVis may not have been set to false when the 580 // previous IME was destroyed. 581 mImeWindowVis = vis; 582 mImeBackDisposition = backDisposition; 583 mImeToken = token; 584 mShowImeSwitcher = showImeSwitcher; 585 mHandler.post(new Runnable() { 586 public void run() { 587 if (mBar != null) { 588 try { 589 mBar.setImeWindowStatus(token, vis, backDisposition, showImeSwitcher); 590 } catch (RemoteException ex) { 591 } 592 } 593 } 594 }); 595 } 596 } 597 598 @Override 599 public void setSystemUiVisibility(int vis, int mask, String cause) { 600 setSystemUiVisibility(vis, 0, 0, mask, mFullscreenStackBounds, mDockedStackBounds, cause); 601 } 602 603 private void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask, 604 Rect fullscreenBounds, Rect dockedBounds, String cause) { 605 // also allows calls from window manager which is in this process. 606 enforceStatusBarService(); 607 608 if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")"); 609 610 synchronized (mLock) { 611 updateUiVisibilityLocked(vis, fullscreenStackVis, dockedStackVis, mask, 612 fullscreenBounds, dockedBounds); 613 disableLocked( 614 mCurrentUserId, 615 vis & StatusBarManager.DISABLE_MASK, 616 mSysUiVisToken, 617 cause, 1); 618 } 619 } 620 621 private void updateUiVisibilityLocked(final int vis, 622 final int fullscreenStackVis, final int dockedStackVis, final int mask, 623 final Rect fullscreenBounds, final Rect dockedBounds) { 624 if (mSystemUiVisibility != vis 625 || mFullscreenStackSysUiVisibility != fullscreenStackVis 626 || mDockedStackSysUiVisibility != dockedStackVis 627 || !mFullscreenStackBounds.equals(fullscreenBounds) 628 || !mDockedStackBounds.equals(dockedBounds)) { 629 mSystemUiVisibility = vis; 630 mFullscreenStackSysUiVisibility = fullscreenStackVis; 631 mDockedStackSysUiVisibility = dockedStackVis; 632 mFullscreenStackBounds.set(fullscreenBounds); 633 mDockedStackBounds.set(dockedBounds); 634 mHandler.post(new Runnable() { 635 public void run() { 636 if (mBar != null) { 637 try { 638 mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis, 639 mask, fullscreenBounds, dockedBounds); 640 } catch (RemoteException ex) { 641 } 642 } 643 } 644 }); 645 } 646 } 647 648 private void enforceStatusBarOrShell() { 649 if (Binder.getCallingUid() == Process.SHELL_UID) { 650 return; 651 } 652 enforceStatusBar(); 653 } 654 655 private void enforceStatusBar() { 656 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR, 657 "StatusBarManagerService"); 658 } 659 660 private void enforceExpandStatusBar() { 661 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.EXPAND_STATUS_BAR, 662 "StatusBarManagerService"); 663 } 664 665 private void enforceStatusBarService() { 666 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 667 "StatusBarManagerService"); 668 } 669 670 // ================================================================================ 671 // Callbacks from the status bar service. 672 // ================================================================================ 673 @Override 674 public void registerStatusBar(IStatusBar bar, List<String> iconSlots, 675 List<StatusBarIcon> iconList, int switches[], List<IBinder> binders, 676 Rect fullscreenStackBounds, Rect dockedStackBounds) { 677 enforceStatusBarService(); 678 679 Slog.i(TAG, "registerStatusBar bar=" + bar); 680 mBar = bar; 681 try { 682 mBar.asBinder().linkToDeath(new DeathRecipient() { 683 @Override 684 public void binderDied() { 685 mBar = null; 686 notifyBarAttachChanged(); 687 } 688 }, 0); 689 } catch (RemoteException e) { 690 } 691 notifyBarAttachChanged(); 692 synchronized (mIcons) { 693 for (String slot : mIcons.keySet()) { 694 iconSlots.add(slot); 695 iconList.add(mIcons.get(slot)); 696 } 697 } 698 synchronized (mLock) { 699 switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1); 700 switches[1] = mSystemUiVisibility; 701 switches[2] = mMenuVisible ? 1 : 0; 702 switches[3] = mImeWindowVis; 703 switches[4] = mImeBackDisposition; 704 switches[5] = mShowImeSwitcher ? 1 : 0; 705 switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2); 706 switches[7] = mFullscreenStackSysUiVisibility; 707 switches[8] = mDockedStackSysUiVisibility; 708 binders.add(mImeToken); 709 fullscreenStackBounds.set(mFullscreenStackBounds); 710 dockedStackBounds.set(mDockedStackBounds); 711 } 712 } 713 714 private void notifyBarAttachChanged() { 715 mHandler.post(() -> { 716 if (mGlobalActionListener == null) return; 717 mGlobalActionListener.onStatusBarConnectedChanged(mBar != null); 718 }); 719 } 720 721 /** 722 * @param clearNotificationEffects whether to consider notifications as "shown" and stop 723 * LED, vibration, and ringing 724 */ 725 @Override 726 public void onPanelRevealed(boolean clearNotificationEffects, int numItems) { 727 enforceStatusBarService(); 728 long identity = Binder.clearCallingIdentity(); 729 try { 730 mNotificationDelegate.onPanelRevealed(clearNotificationEffects, numItems); 731 } finally { 732 Binder.restoreCallingIdentity(identity); 733 } 734 } 735 736 @Override 737 public void clearNotificationEffects() throws RemoteException { 738 enforceStatusBarService(); 739 long identity = Binder.clearCallingIdentity(); 740 try { 741 mNotificationDelegate.clearEffects(); 742 } finally { 743 Binder.restoreCallingIdentity(identity); 744 } 745 } 746 747 @Override 748 public void onPanelHidden() throws RemoteException { 749 enforceStatusBarService(); 750 long identity = Binder.clearCallingIdentity(); 751 try { 752 mNotificationDelegate.onPanelHidden(); 753 } finally { 754 Binder.restoreCallingIdentity(identity); 755 } 756 } 757 758 /** 759 * Allows the status bar to shutdown the device. 760 */ 761 @Override 762 public void shutdown() { 763 enforceStatusBarService(); 764 long identity = Binder.clearCallingIdentity(); 765 try { 766 // ShutdownThread displays UI, so give it a UI context. 767 mHandler.post(() -> 768 ShutdownThread.shutdown(getUiContext(), 769 PowerManager.SHUTDOWN_USER_REQUESTED, false)); 770 } finally { 771 Binder.restoreCallingIdentity(identity); 772 } 773 } 774 775 /** 776 * Allows the status bar to reboot the device. 777 */ 778 @Override 779 public void reboot(boolean safeMode) { 780 enforceStatusBarService(); 781 long identity = Binder.clearCallingIdentity(); 782 try { 783 mHandler.post(() -> { 784 // ShutdownThread displays UI, so give it a UI context. 785 if (safeMode) { 786 ShutdownThread.rebootSafeMode(getUiContext(), false); 787 } else { 788 ShutdownThread.reboot(getUiContext(), 789 PowerManager.SHUTDOWN_USER_REQUESTED, false); 790 } 791 }); 792 } finally { 793 Binder.restoreCallingIdentity(identity); 794 } 795 } 796 797 @Override 798 public void onGlobalActionsShown() { 799 enforceStatusBarService(); 800 long identity = Binder.clearCallingIdentity(); 801 try { 802 if (mGlobalActionListener == null) return; 803 mGlobalActionListener.onGlobalActionsShown(); 804 } finally { 805 Binder.restoreCallingIdentity(identity); 806 } 807 } 808 809 @Override 810 public void onGlobalActionsHidden() { 811 enforceStatusBarService(); 812 long identity = Binder.clearCallingIdentity(); 813 try { 814 if (mGlobalActionListener == null) return; 815 mGlobalActionListener.onGlobalActionsDismissed(); 816 } finally { 817 Binder.restoreCallingIdentity(identity); 818 } 819 } 820 821 @Override 822 public void onNotificationClick(String key) { 823 enforceStatusBarService(); 824 final int callingUid = Binder.getCallingUid(); 825 final int callingPid = Binder.getCallingPid(); 826 long identity = Binder.clearCallingIdentity(); 827 try { 828 mNotificationDelegate.onNotificationClick(callingUid, callingPid, key); 829 } finally { 830 Binder.restoreCallingIdentity(identity); 831 } 832 } 833 834 @Override 835 public void onNotificationActionClick(String key, int actionIndex) { 836 enforceStatusBarService(); 837 final int callingUid = Binder.getCallingUid(); 838 final int callingPid = Binder.getCallingPid(); 839 long identity = Binder.clearCallingIdentity(); 840 try { 841 mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key, 842 actionIndex); 843 } finally { 844 Binder.restoreCallingIdentity(identity); 845 } 846 } 847 848 @Override 849 public void onNotificationError(String pkg, String tag, int id, 850 int uid, int initialPid, String message, int userId) { 851 enforceStatusBarService(); 852 final int callingUid = Binder.getCallingUid(); 853 final int callingPid = Binder.getCallingPid(); 854 long identity = Binder.clearCallingIdentity(); 855 try { 856 // WARNING: this will call back into us to do the remove. Don't hold any locks. 857 mNotificationDelegate.onNotificationError(callingUid, callingPid, 858 pkg, tag, id, uid, initialPid, message, userId); 859 } finally { 860 Binder.restoreCallingIdentity(identity); 861 } 862 } 863 864 @Override 865 public void onNotificationClear(String pkg, String tag, int id, int userId) { 866 enforceStatusBarService(); 867 final int callingUid = Binder.getCallingUid(); 868 final int callingPid = Binder.getCallingPid(); 869 long identity = Binder.clearCallingIdentity(); 870 try { 871 mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId); 872 } finally { 873 Binder.restoreCallingIdentity(identity); 874 } 875 } 876 877 @Override 878 public void onNotificationVisibilityChanged( 879 NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys) 880 throws RemoteException { 881 enforceStatusBarService(); 882 long identity = Binder.clearCallingIdentity(); 883 try { 884 mNotificationDelegate.onNotificationVisibilityChanged( 885 newlyVisibleKeys, noLongerVisibleKeys); 886 } finally { 887 Binder.restoreCallingIdentity(identity); 888 } 889 } 890 891 @Override 892 public void onNotificationExpansionChanged(String key, boolean userAction, 893 boolean expanded) throws RemoteException { 894 enforceStatusBarService(); 895 long identity = Binder.clearCallingIdentity(); 896 try { 897 mNotificationDelegate.onNotificationExpansionChanged( 898 key, userAction, expanded); 899 } finally { 900 Binder.restoreCallingIdentity(identity); 901 } 902 } 903 904 @Override 905 public void onClearAllNotifications(int userId) { 906 enforceStatusBarService(); 907 final int callingUid = Binder.getCallingUid(); 908 final int callingPid = Binder.getCallingPid(); 909 long identity = Binder.clearCallingIdentity(); 910 try { 911 mNotificationDelegate.onClearAll(callingUid, callingPid, userId); 912 } finally { 913 Binder.restoreCallingIdentity(identity); 914 } 915 } 916 917 @Override 918 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 919 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 920 (new StatusBarShellCommand(this)).exec( 921 this, in, out, err, args, callback, resultReceiver); 922 } 923 924 // ================================================================================ 925 // Can be called from any thread 926 // ================================================================================ 927 928 // lock on mDisableRecords 929 void manageDisableListLocked(int userId, int what, IBinder token, String pkg, int which) { 930 if (SPEW) { 931 Slog.d(TAG, "manageDisableList userId=" + userId 932 + " what=0x" + Integer.toHexString(what) + " pkg=" + pkg); 933 } 934 // update the list 935 final int N = mDisableRecords.size(); 936 DisableRecord tok = null; 937 int i; 938 for (i=0; i<N; i++) { 939 DisableRecord t = mDisableRecords.get(i); 940 if (t.token == token && t.userId == userId) { 941 tok = t; 942 break; 943 } 944 } 945 if (what == 0 || !token.isBinderAlive()) { 946 if (tok != null) { 947 mDisableRecords.remove(i); 948 tok.token.unlinkToDeath(tok, 0); 949 } 950 } else { 951 if (tok == null) { 952 tok = new DisableRecord(); 953 tok.userId = userId; 954 try { 955 token.linkToDeath(tok, 0); 956 } 957 catch (RemoteException ex) { 958 return; // give up 959 } 960 mDisableRecords.add(tok); 961 } 962 if (which == 1) { 963 tok.what1 = what; 964 } else { 965 tok.what2 = what; 966 } 967 tok.token = token; 968 tok.pkg = pkg; 969 } 970 } 971 972 // lock on mDisableRecords 973 int gatherDisableActionsLocked(int userId, int which) { 974 final int N = mDisableRecords.size(); 975 // gather the new net flags 976 int net = 0; 977 for (int i=0; i<N; i++) { 978 final DisableRecord rec = mDisableRecords.get(i); 979 if (rec.userId == userId) { 980 net |= (which == 1) ? rec.what1 : rec.what2; 981 } 982 } 983 return net; 984 } 985 986 // ================================================================================ 987 // Always called from UI thread 988 // ================================================================================ 989 990 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 991 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 992 993 synchronized (mLock) { 994 pw.println(" mDisabled1=0x" + Integer.toHexString(mDisabled1)); 995 pw.println(" mDisabled2=0x" + Integer.toHexString(mDisabled2)); 996 final int N = mDisableRecords.size(); 997 pw.println(" mDisableRecords.size=" + N); 998 for (int i=0; i<N; i++) { 999 DisableRecord tok = mDisableRecords.get(i); 1000 pw.println(" [" + i + "] userId=" + tok.userId 1001 + " what1=0x" + Integer.toHexString(tok.what1) 1002 + " what2=0x" + Integer.toHexString(tok.what2) 1003 + " pkg=" + tok.pkg 1004 + " token=" + tok.token); 1005 } 1006 pw.println(" mCurrentUserId=" + mCurrentUserId); 1007 pw.println(" mIcons="); 1008 for (String slot : mIcons.keySet()) { 1009 pw.println(" "); 1010 pw.print(slot); 1011 pw.print(" -> "); 1012 final StatusBarIcon icon = mIcons.get(slot); 1013 pw.print(icon); 1014 if (!TextUtils.isEmpty(icon.contentDescription)) { 1015 pw.print(" \""); 1016 pw.print(icon.contentDescription); 1017 pw.print("\""); 1018 } 1019 pw.println(); 1020 } 1021 } 1022 } 1023 1024 private static final Context getUiContext() { 1025 return ActivityThread.currentActivityThread().getSystemUiContext(); 1026 } 1027 } 1028