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