StatusBarManagerService.java revision c99f05e1b0d3b13bbf46ebcb5b23307d6af4e1ce
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
228    // ================================================================================
229    // From IStatusBarService
230    // ================================================================================
231    @Override
232    public void expandNotificationsPanel() {
233        enforceExpandStatusBar();
234
235        if (mBar != null) {
236            try {
237                mBar.animateExpandNotificationsPanel();
238            } catch (RemoteException ex) {
239            }
240        }
241    }
242
243    @Override
244    public void collapsePanels() {
245        enforceExpandStatusBar();
246
247        if (mBar != null) {
248            try {
249                mBar.animateCollapsePanels();
250            } catch (RemoteException ex) {
251            }
252        }
253    }
254
255    @Override
256    public void expandSettingsPanel(String subPanel) {
257        enforceExpandStatusBar();
258
259        if (mBar != null) {
260            try {
261                mBar.animateExpandSettingsPanel(subPanel);
262            } catch (RemoteException ex) {
263            }
264        }
265    }
266
267    public void addTile(ComponentName component) {
268        enforceStatusBarOrShell();
269
270        if (mBar != null) {
271            try {
272                mBar.addQsTile(component);
273            } catch (RemoteException ex) {
274            }
275        }
276    }
277
278    public void remTile(ComponentName component) {
279        enforceStatusBarOrShell();
280
281        if (mBar != null) {
282            try {
283                mBar.remQsTile(component);
284            } catch (RemoteException ex) {
285            }
286        }
287    }
288
289    public void clickTile(ComponentName component) {
290        enforceStatusBarOrShell();
291
292        if (mBar != null) {
293            try {
294                mBar.clickQsTile(component);
295            } catch (RemoteException ex) {
296            }
297        }
298    }
299
300    @Override
301    public void disable(int what, IBinder token, String pkg) {
302        disableForUser(what, token, pkg, mCurrentUserId);
303    }
304
305    @Override
306    public void disableForUser(int what, IBinder token, String pkg, int userId) {
307        enforceStatusBar();
308
309        synchronized (mLock) {
310            disableLocked(userId, what, token, pkg, 1);
311        }
312    }
313
314    /**
315     * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags.
316     * To re-enable everything, pass {@link #DISABLE_NONE}.
317     *
318     * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
319     */
320    @Override
321    public void disable2(int what, IBinder token, String pkg) {
322        disable2ForUser(what, token, pkg, mCurrentUserId);
323    }
324
325    /**
326     * Disable additional status bar features for a given user. Pass the bitwise-or of the
327     * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}.
328     *
329     * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
330     */
331    @Override
332    public void disable2ForUser(int what, IBinder token, String pkg, int userId) {
333        enforceStatusBar();
334
335        synchronized (mLock) {
336            disableLocked(userId, what, token, pkg, 2);
337        }
338    }
339
340    private void disableLocked(int userId, int what, IBinder token, String pkg, int whichFlag) {
341        // It's important that the the callback and the call to mBar get done
342        // in the same order when multiple threads are calling this function
343        // so they are paired correctly.  The messages on the handler will be
344        // handled in the order they were enqueued, but will be outside the lock.
345        manageDisableListLocked(userId, what, token, pkg, whichFlag);
346
347        // Ensure state for the current user is applied, even if passed a non-current user.
348        final int net1 = gatherDisableActionsLocked(mCurrentUserId, 1);
349        final int net2 = gatherDisableActionsLocked(mCurrentUserId, 2);
350        if (net1 != mDisabled1 || net2 != mDisabled2) {
351            mDisabled1 = net1;
352            mDisabled2 = net2;
353            mHandler.post(new Runnable() {
354                    public void run() {
355                        mNotificationDelegate.onSetDisabled(net1);
356                    }
357                });
358            if (mBar != null) {
359                try {
360                    mBar.disable(net1, net2);
361                } catch (RemoteException ex) {
362                }
363            }
364        }
365    }
366
367    @Override
368    public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,
369            String contentDescription) {
370        enforceStatusBar();
371
372        synchronized (mIcons) {
373            StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId,
374                    iconLevel, 0, contentDescription);
375            //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
376            mIcons.put(slot, icon);
377
378            if (mBar != null) {
379                try {
380                    mBar.setIcon(slot, icon);
381                } catch (RemoteException ex) {
382                }
383            }
384        }
385    }
386
387    @Override
388    public void setIconVisibility(String slot, boolean visibility) {
389        enforceStatusBar();
390
391        synchronized (mIcons) {
392            StatusBarIcon icon = mIcons.get(slot);
393            if (icon == null) {
394                return;
395            }
396            if (icon.visible != visibility) {
397                icon.visible = visibility;
398
399                if (mBar != null) {
400                    try {
401                        mBar.setIcon(slot, icon);
402                    } catch (RemoteException ex) {
403                    }
404                }
405            }
406        }
407    }
408
409    @Override
410    public void removeIcon(String slot) {
411        enforceStatusBar();
412
413        synchronized (mIcons) {
414            mIcons.remove(slot);
415
416            if (mBar != null) {
417                try {
418                    mBar.removeIcon(slot);
419                } catch (RemoteException ex) {
420                }
421            }
422        }
423    }
424
425    /**
426     * Hide or show the on-screen Menu key. Only call this from the window manager, typically in
427     * response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set
428     * to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}.
429     */
430    private void topAppWindowChanged(final boolean menuVisible) {
431        enforceStatusBar();
432
433        if (SPEW) Slog.d(TAG, (menuVisible?"showing":"hiding") + " MENU key");
434
435        synchronized(mLock) {
436            mMenuVisible = menuVisible;
437            mHandler.post(new Runnable() {
438                public void run() {
439                    if (mBar != null) {
440                        try {
441                            mBar.topAppWindowChanged(menuVisible);
442                        } catch (RemoteException ex) {
443                        }
444                    }
445                }
446            });
447        }
448    }
449
450    @Override
451    public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition,
452            final boolean showImeSwitcher) {
453        enforceStatusBar();
454
455        if (SPEW) {
456            Slog.d(TAG, "swetImeWindowStatus vis=" + vis + " backDisposition=" + backDisposition);
457        }
458
459        synchronized(mLock) {
460            // In case of IME change, we need to call up setImeWindowStatus() regardless of
461            // mImeWindowVis because mImeWindowVis may not have been set to false when the
462            // previous IME was destroyed.
463            mImeWindowVis = vis;
464            mImeBackDisposition = backDisposition;
465            mImeToken = token;
466            mShowImeSwitcher = showImeSwitcher;
467            mHandler.post(new Runnable() {
468                public void run() {
469                    if (mBar != null) {
470                        try {
471                            mBar.setImeWindowStatus(token, vis, backDisposition, showImeSwitcher);
472                        } catch (RemoteException ex) {
473                        }
474                    }
475                }
476            });
477        }
478    }
479
480    @Override
481    public void setSystemUiVisibility(int vis, int mask, String cause) {
482        setSystemUiVisibility(vis, 0, 0, mask, mFullscreenStackBounds, mDockedStackBounds, cause);
483    }
484
485    private void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
486            Rect fullscreenBounds, Rect dockedBounds, String cause) {
487        // also allows calls from window manager which is in this process.
488        enforceStatusBarService();
489
490        if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");
491
492        synchronized (mLock) {
493            updateUiVisibilityLocked(vis, fullscreenStackVis, dockedStackVis, mask,
494                    fullscreenBounds, dockedBounds);
495            disableLocked(
496                    mCurrentUserId,
497                    vis & StatusBarManager.DISABLE_MASK,
498                    mSysUiVisToken,
499                    cause, 1);
500        }
501    }
502
503    private void updateUiVisibilityLocked(final int vis,
504            final int fullscreenStackVis, final int dockedStackVis, final int mask,
505            final Rect fullscreenBounds, final Rect dockedBounds) {
506        if (mSystemUiVisibility != vis
507                || mFullscreenStackSysUiVisibility != fullscreenStackVis
508                || mDockedStackSysUiVisibility != dockedStackVis
509                || !mFullscreenStackBounds.equals(fullscreenBounds)
510                || !mDockedStackBounds.equals(dockedBounds)) {
511            mSystemUiVisibility = vis;
512            mFullscreenStackSysUiVisibility = fullscreenStackVis;
513            mDockedStackSysUiVisibility = dockedStackVis;
514            mFullscreenStackBounds.set(fullscreenBounds);
515            mDockedStackBounds.set(dockedBounds);
516            mHandler.post(new Runnable() {
517                    public void run() {
518                        if (mBar != null) {
519                            try {
520                                mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis,
521                                        mask, fullscreenBounds, dockedBounds);
522                            } catch (RemoteException ex) {
523                            }
524                        }
525                    }
526                });
527        }
528    }
529
530    @Override
531    public void toggleRecentApps() {
532        if (mBar != null) {
533            try {
534                mBar.toggleRecentApps();
535            } catch (RemoteException ex) {}
536        }
537    }
538
539    @Override
540    public void preloadRecentApps() {
541        if (mBar != null) {
542            try {
543                mBar.preloadRecentApps();
544            } catch (RemoteException ex) {}
545        }
546    }
547
548    @Override
549    public void cancelPreloadRecentApps() {
550        if (mBar != null) {
551            try {
552                mBar.cancelPreloadRecentApps();
553            } catch (RemoteException ex) {}
554        }
555    }
556
557    @Override
558    public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
559        if (mBar != null) {
560            try {
561                mBar.showRecentApps(triggeredFromAltTab, fromHome);
562            } catch (RemoteException ex) {}
563        }
564    }
565
566    @Override
567    public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
568        if (mBar != null) {
569            try {
570                mBar.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey);
571            } catch (RemoteException ex) {}
572        }
573    }
574
575    @Override
576    public void toggleKeyboardShortcutsMenu(int deviceId) {
577        if (mBar != null) {
578            try {
579                mBar.toggleKeyboardShortcutsMenu(deviceId);
580            } catch (RemoteException ex) {}
581        }
582    }
583
584    @Override
585    public void requestTvPictureInPicture() {
586        if (mBar != null) {
587            try {
588                mBar.requestTvPictureInPicture();
589            } catch (RemoteException ex) {}
590        }
591    }
592
593    @Override
594    public void setCurrentUser(int newUserId) {
595        if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId);
596        mCurrentUserId = newUserId;
597    }
598
599    @Override
600    public void setWindowState(int window, int state) {
601        if (mBar != null) {
602            try {
603                mBar.setWindowState(window, state);
604            } catch (RemoteException ex) {}
605        }
606    }
607
608    @Override
609    public void appTransitionPending() {
610        if (mBar != null) {
611            try {
612                mBar.appTransitionPending();
613            } catch (RemoteException ex) {}
614        }
615    }
616
617    @Override
618    public void appTransitionCancelled() {
619        if (mBar != null) {
620            try {
621                mBar.appTransitionCancelled();
622            } catch (RemoteException ex) {}
623        }
624    }
625
626    @Override
627    public void appTransitionStarting(long statusBarAnimationsStartTime,
628            long statusBarAnimationsDuration) {
629        if (mBar != null) {
630            try {
631                mBar.appTransitionStarting(
632                        statusBarAnimationsStartTime, statusBarAnimationsDuration);
633            } catch (RemoteException ex) {}
634        }
635    }
636
637    @Override
638    public void startAssist(Bundle args) {
639        if (mBar != null) {
640            try {
641                mBar.startAssist(args);
642            } catch (RemoteException ex) {}
643        }
644    }
645
646    private void enforceStatusBarOrShell() {
647        if (Binder.getCallingUid() == Process.SHELL_UID) {
648            return;
649        }
650        enforceStatusBar();
651    }
652
653    private void enforceStatusBar() {
654        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
655                "StatusBarManagerService");
656    }
657
658    private void enforceExpandStatusBar() {
659        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.EXPAND_STATUS_BAR,
660                "StatusBarManagerService");
661    }
662
663    private void enforceStatusBarService() {
664        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
665                "StatusBarManagerService");
666    }
667
668    // ================================================================================
669    // Callbacks from the status bar service.
670    // ================================================================================
671    @Override
672    public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
673            List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
674            Rect fullscreenStackBounds, Rect dockedStackBounds) {
675        enforceStatusBarService();
676
677        Slog.i(TAG, "registerStatusBar bar=" + bar);
678        mBar = bar;
679        synchronized (mIcons) {
680            for (String slot : mIcons.keySet()) {
681                iconSlots.add(slot);
682                iconList.add(mIcons.get(slot));
683            }
684        }
685        synchronized (mLock) {
686            switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1);
687            switches[1] = mSystemUiVisibility;
688            switches[2] = mMenuVisible ? 1 : 0;
689            switches[3] = mImeWindowVis;
690            switches[4] = mImeBackDisposition;
691            switches[5] = mShowImeSwitcher ? 1 : 0;
692            switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
693            switches[7] = mFullscreenStackSysUiVisibility;
694            switches[8] = mDockedStackSysUiVisibility;
695            binders.add(mImeToken);
696            fullscreenStackBounds.set(mFullscreenStackBounds);
697            dockedStackBounds.set(mDockedStackBounds);
698        }
699    }
700
701    /**
702     * @param clearNotificationEffects whether to consider notifications as "shown" and stop
703     *     LED, vibration, and ringing
704     */
705    @Override
706    public void onPanelRevealed(boolean clearNotificationEffects, int numItems) {
707        enforceStatusBarService();
708        long identity = Binder.clearCallingIdentity();
709        try {
710            mNotificationDelegate.onPanelRevealed(clearNotificationEffects, numItems);
711        } finally {
712            Binder.restoreCallingIdentity(identity);
713        }
714    }
715
716    @Override
717    public void clearNotificationEffects() throws RemoteException {
718        enforceStatusBarService();
719        long identity = Binder.clearCallingIdentity();
720        try {
721            mNotificationDelegate.clearEffects();
722        } finally {
723            Binder.restoreCallingIdentity(identity);
724        }
725    }
726
727    @Override
728    public void onPanelHidden() throws RemoteException {
729        enforceStatusBarService();
730        long identity = Binder.clearCallingIdentity();
731        try {
732            mNotificationDelegate.onPanelHidden();
733        } finally {
734            Binder.restoreCallingIdentity(identity);
735        }
736    }
737
738    @Override
739    public void onNotificationClick(String key) {
740        enforceStatusBarService();
741        final int callingUid = Binder.getCallingUid();
742        final int callingPid = Binder.getCallingPid();
743        long identity = Binder.clearCallingIdentity();
744        try {
745            mNotificationDelegate.onNotificationClick(callingUid, callingPid, key);
746        } finally {
747            Binder.restoreCallingIdentity(identity);
748        }
749    }
750
751    @Override
752    public void onNotificationActionClick(String key, int actionIndex) {
753        enforceStatusBarService();
754        final int callingUid = Binder.getCallingUid();
755        final int callingPid = Binder.getCallingPid();
756        long identity = Binder.clearCallingIdentity();
757        try {
758            mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key,
759                    actionIndex);
760        } finally {
761            Binder.restoreCallingIdentity(identity);
762        }
763    }
764
765    @Override
766    public void onNotificationError(String pkg, String tag, int id,
767            int uid, int initialPid, String message, int userId) {
768        enforceStatusBarService();
769        final int callingUid = Binder.getCallingUid();
770        final int callingPid = Binder.getCallingPid();
771        long identity = Binder.clearCallingIdentity();
772        try {
773            // WARNING: this will call back into us to do the remove.  Don't hold any locks.
774            mNotificationDelegate.onNotificationError(callingUid, callingPid,
775                    pkg, tag, id, uid, initialPid, message, userId);
776        } finally {
777            Binder.restoreCallingIdentity(identity);
778        }
779    }
780
781    @Override
782    public void onNotificationClear(String pkg, String tag, int id, int userId) {
783        enforceStatusBarService();
784        final int callingUid = Binder.getCallingUid();
785        final int callingPid = Binder.getCallingPid();
786        long identity = Binder.clearCallingIdentity();
787        try {
788            mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId);
789        } finally {
790            Binder.restoreCallingIdentity(identity);
791        }
792    }
793
794    @Override
795    public void onNotificationVisibilityChanged(
796            NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys)
797            throws RemoteException {
798        enforceStatusBarService();
799        long identity = Binder.clearCallingIdentity();
800        try {
801            mNotificationDelegate.onNotificationVisibilityChanged(
802                    newlyVisibleKeys, noLongerVisibleKeys);
803        } finally {
804            Binder.restoreCallingIdentity(identity);
805        }
806    }
807
808    @Override
809    public void onNotificationExpansionChanged(String key, boolean userAction,
810            boolean expanded) throws RemoteException {
811        enforceStatusBarService();
812        long identity = Binder.clearCallingIdentity();
813        try {
814            mNotificationDelegate.onNotificationExpansionChanged(
815                    key, userAction, expanded);
816        } finally {
817            Binder.restoreCallingIdentity(identity);
818        }
819    }
820
821    @Override
822    public void onClearAllNotifications(int userId) {
823        enforceStatusBarService();
824        final int callingUid = Binder.getCallingUid();
825        final int callingPid = Binder.getCallingPid();
826        long identity = Binder.clearCallingIdentity();
827        try {
828            mNotificationDelegate.onClearAll(callingUid, callingPid, userId);
829        } finally {
830            Binder.restoreCallingIdentity(identity);
831        }
832    }
833
834    @Override
835    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
836            String[] args, ResultReceiver resultReceiver) throws RemoteException {
837        (new StatusBarShellCommand(this)).exec(
838                this, in, out, err, args, resultReceiver);
839    }
840
841    // ================================================================================
842    // Can be called from any thread
843    // ================================================================================
844
845    // lock on mDisableRecords
846    void manageDisableListLocked(int userId, int what, IBinder token, String pkg, int which) {
847        if (SPEW) {
848            Slog.d(TAG, "manageDisableList userId=" + userId
849                    + " what=0x" + Integer.toHexString(what) + " pkg=" + pkg);
850        }
851        // update the list
852        final int N = mDisableRecords.size();
853        DisableRecord tok = null;
854        int i;
855        for (i=0; i<N; i++) {
856            DisableRecord t = mDisableRecords.get(i);
857            if (t.token == token && t.userId == userId) {
858                tok = t;
859                break;
860            }
861        }
862        if (what == 0 || !token.isBinderAlive()) {
863            if (tok != null) {
864                mDisableRecords.remove(i);
865                tok.token.unlinkToDeath(tok, 0);
866            }
867        } else {
868            if (tok == null) {
869                tok = new DisableRecord();
870                tok.userId = userId;
871                try {
872                    token.linkToDeath(tok, 0);
873                }
874                catch (RemoteException ex) {
875                    return; // give up
876                }
877                mDisableRecords.add(tok);
878            }
879            if (which == 1) {
880                tok.what1 = what;
881            } else {
882                tok.what2 = what;
883            }
884            tok.token = token;
885            tok.pkg = pkg;
886        }
887    }
888
889    // lock on mDisableRecords
890    int gatherDisableActionsLocked(int userId, int which) {
891        final int N = mDisableRecords.size();
892        // gather the new net flags
893        int net = 0;
894        for (int i=0; i<N; i++) {
895            final DisableRecord rec = mDisableRecords.get(i);
896            if (rec.userId == userId) {
897                net |= (which == 1) ? rec.what1 : rec.what2;
898            }
899        }
900        return net;
901    }
902
903    // ================================================================================
904    // Always called from UI thread
905    // ================================================================================
906
907    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
908        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
909                != PackageManager.PERMISSION_GRANTED) {
910            pw.println("Permission Denial: can't dump StatusBar from from pid="
911                    + Binder.getCallingPid()
912                    + ", uid=" + Binder.getCallingUid());
913            return;
914        }
915
916        synchronized (mLock) {
917            pw.println("  mDisabled1=0x" + Integer.toHexString(mDisabled1));
918            pw.println("  mDisabled2=0x" + Integer.toHexString(mDisabled2));
919            final int N = mDisableRecords.size();
920            pw.println("  mDisableRecords.size=" + N);
921            for (int i=0; i<N; i++) {
922                DisableRecord tok = mDisableRecords.get(i);
923                pw.println("    [" + i + "] userId=" + tok.userId
924                                + " what1=0x" + Integer.toHexString(tok.what1)
925                                + " what2=0x" + Integer.toHexString(tok.what2)
926                                + " pkg=" + tok.pkg
927                                + " token=" + tok.token);
928            }
929            pw.println("  mCurrentUserId=" + mCurrentUserId);
930        }
931    }
932}
933