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