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.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