Home | History | Annotate | Download | only in statusbar
      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