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 static android.Manifest.permission.CONTROL_DEVICE_STATE;
20 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
21 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
22 import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
23 import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
24 import static android.app.StatusBarManager.NAV_BAR_MODE_DEFAULT;
25 import static android.app.StatusBarManager.NAV_BAR_MODE_KIDS;
26 import static android.app.StatusBarManager.NavBarMode;
27 import static android.app.StatusBarManager.SessionFlags;
28 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
29 import static android.view.Display.DEFAULT_DISPLAY;
30 import static android.view.ViewRootImpl.CLIENT_TRANSIENT;
31 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
32 
33 import android.Manifest;
34 import android.annotation.NonNull;
35 import android.annotation.Nullable;
36 import android.annotation.RequiresPermission;
37 import android.annotation.TestApi;
38 import android.app.ActivityManager;
39 import android.app.ActivityManagerInternal;
40 import android.app.ActivityThread;
41 import android.app.ITransientNotificationCallback;
42 import android.app.Notification;
43 import android.app.StatusBarManager;
44 import android.app.compat.CompatChanges;
45 import android.compat.annotation.ChangeId;
46 import android.compat.annotation.EnabledAfter;
47 import android.compat.annotation.EnabledSince;
48 import android.content.ComponentName;
49 import android.content.Context;
50 import android.content.Intent;
51 import android.content.om.IOverlayManager;
52 import android.content.pm.PackageManager;
53 import android.content.pm.PackageManagerInternal;
54 import android.content.pm.ResolveInfo;
55 import android.graphics.drawable.Icon;
56 import android.hardware.biometrics.BiometricAuthenticator.Modality;
57 import android.hardware.biometrics.IBiometricContextListener;
58 import android.hardware.biometrics.IBiometricSysuiReceiver;
59 import android.hardware.biometrics.PromptInfo;
60 import android.hardware.display.DisplayManager;
61 import android.hardware.display.DisplayManager.DisplayListener;
62 import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
63 import android.media.INearbyMediaDevicesProvider;
64 import android.media.MediaRoute2Info;
65 import android.net.Uri;
66 import android.os.Binder;
67 import android.os.Build;
68 import android.os.Bundle;
69 import android.os.Handler;
70 import android.os.IBinder;
71 import android.os.PowerManager;
72 import android.os.Process;
73 import android.os.RemoteException;
74 import android.os.ResultReceiver;
75 import android.os.ServiceManager;
76 import android.os.ShellCallback;
77 import android.os.UserHandle;
78 import android.provider.Settings;
79 import android.service.notification.NotificationStats;
80 import android.service.quicksettings.TileService;
81 import android.text.TextUtils;
82 import android.util.ArrayMap;
83 import android.util.IndentingPrintWriter;
84 import android.util.Pair;
85 import android.util.Slog;
86 import android.util.SparseArray;
87 import android.view.KeyEvent;
88 import android.view.WindowInsets;
89 import android.view.WindowInsets.Type.InsetsType;
90 import android.view.WindowInsetsController.Appearance;
91 import android.view.WindowInsetsController.Behavior;
92 
93 import com.android.internal.R;
94 import com.android.internal.annotations.GuardedBy;
95 import com.android.internal.annotations.VisibleForTesting;
96 import com.android.internal.inputmethod.SoftInputShowHideReason;
97 import com.android.internal.logging.InstanceId;
98 import com.android.internal.os.TransferPipe;
99 import com.android.internal.statusbar.IAddTileResultCallback;
100 import com.android.internal.statusbar.ISessionListener;
101 import com.android.internal.statusbar.IStatusBar;
102 import com.android.internal.statusbar.IStatusBarService;
103 import com.android.internal.statusbar.IUndoMediaTransferCallback;
104 import com.android.internal.statusbar.LetterboxDetails;
105 import com.android.internal.statusbar.NotificationVisibility;
106 import com.android.internal.statusbar.RegisterStatusBarResult;
107 import com.android.internal.statusbar.StatusBarIcon;
108 import com.android.internal.util.DumpUtils;
109 import com.android.internal.util.GcUtils;
110 import com.android.internal.view.AppearanceRegion;
111 import com.android.server.LocalServices;
112 import com.android.server.UiThread;
113 import com.android.server.inputmethod.InputMethodManagerInternal;
114 import com.android.server.notification.NotificationDelegate;
115 import com.android.server.policy.GlobalActionsProvider;
116 import com.android.server.power.ShutdownCheckPoints;
117 import com.android.server.power.ShutdownThread;
118 import com.android.server.wm.ActivityTaskManagerInternal;
119 
120 import java.io.FileDescriptor;
121 import java.io.PrintWriter;
122 import java.util.ArrayList;
123 import java.util.concurrent.TimeUnit;
124 
125 /**
126  * A note on locking:  We rely on the fact that calls onto mBar are oneway or
127  * if they are local, that they just enqueue messages to not deadlock.
128  */
129 public class StatusBarManagerService extends IStatusBarService.Stub implements DisplayListener {
130     private static final String TAG = "StatusBarManagerService";
131     private static final boolean SPEW = false;
132 
133     /**
134      * Apps targeting {@code Build.VERSION_CODES.S} or higher need {@link
135      * android.Manifest.permission#STATUS_BAR} permission to collapse the status bar panels due to
136      * security reasons.
137      *
138      * This was being exploited by malware to prevent the user from accessing critical
139      * notifications.
140      */
141     @ChangeId
142     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
143     private static final long LOCK_DOWN_COLLAPSE_STATUS_BAR = 173031413L;
144 
145     /**
146      * In apps targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher, calling
147      * {@link android.service.quicksettings.TileService#requestListeningState} will check that the
148      * calling package (uid) and the package of the target {@link android.content.ComponentName}
149      * match. It'll also make sure that the context used can take actions on behalf of the current
150      * user.
151      */
152     @ChangeId
153     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
154     static final long REQUEST_LISTENING_MUST_MATCH_PACKAGE = 172251878L;
155 
156     /**
157      * @hide
158      */
159     @ChangeId
160     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
161     static final long REQUEST_LISTENING_OTHER_USER_NOOP = 242194868L;
162 
163     private final Context mContext;
164 
165     private final Handler mHandler = new Handler();
166     private NotificationDelegate mNotificationDelegate;
167     private volatile IStatusBar mBar;
168     private final ArrayMap<String, StatusBarIcon> mIcons = new ArrayMap<>();
169 
170     // for disabling the status bar
171     private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
172     private GlobalActionsProvider.GlobalActionsListener mGlobalActionListener;
173     private final IBinder mSysUiVisToken = new Binder();
174 
175     private final Object mLock = new Object();
176     private final DeathRecipient mDeathRecipient = new DeathRecipient();
177     private final ActivityManagerInternal mActivityManagerInternal;
178     private final ActivityTaskManagerInternal mActivityTaskManager;
179     private final PackageManagerInternal mPackageManagerInternal;
180     private final SessionMonitor mSessionMonitor;
181     private int mCurrentUserId;
182     private boolean mTracingEnabled;
183     private int mLastSystemKey = -1;
184 
185     private final TileRequestTracker mTileRequestTracker;
186 
187     private final SparseArray<UiState> mDisplayUiState = new SparseArray<>();
188     @GuardedBy("mLock")
189     private IUdfpsRefreshRateRequestCallback mUdfpsRefreshRateRequestCallback;
190     @GuardedBy("mLock")
191     private IBiometricContextListener mBiometricContextListener;
192 
193     @GuardedBy("mCurrentRequestAddTilePackages")
194     private final ArrayMap<String, Long> mCurrentRequestAddTilePackages = new ArrayMap<>();
195     private static final long REQUEST_TIME_OUT = TimeUnit.MINUTES.toNanos(5);
196 
197     private IOverlayManager mOverlayManager;
198 
199     private class DeathRecipient implements IBinder.DeathRecipient {
binderDied()200         public void binderDied() {
201             mBar.asBinder().unlinkToDeath(this,0);
202             mBar = null;
203             notifyBarAttachChanged();
204         }
205 
linkToDeath()206         public void linkToDeath() {
207             try {
208                 mBar.asBinder().linkToDeath(mDeathRecipient,0);
209             } catch (RemoteException e) {
210                 Slog.e(TAG,"Unable to register Death Recipient for status bar", e);
211             }
212         }
213 
214     }
215 
216     private class DisableRecord implements IBinder.DeathRecipient {
217         int userId;
218         String pkg;
219         int what1;
220         int what2;
221         IBinder token;
222 
DisableRecord(int userId, IBinder token)223         public DisableRecord(int userId, IBinder token) {
224             this.userId = userId;
225             this.token = token;
226             try {
227                 token.linkToDeath(this, 0);
228             } catch (RemoteException re) {
229                 // Give up
230             }
231         }
232 
233         @Override
binderDied()234         public void binderDied() {
235             Slog.i(TAG, "binder died for pkg=" + pkg);
236             disableForUser(0, token, pkg, userId);
237             disable2ForUser(0, token, pkg, userId);
238             token.unlinkToDeath(this, 0);
239         }
240 
setFlags(int what, int which, String pkg)241         public void setFlags(int what, int which, String pkg) {
242             switch (which) {
243                 case 1:
244                     what1 = what;
245                     break;
246                 case 2:
247                     what2 = what;
248                     break;
249                 default:
250                     Slog.w(TAG, "Can't set unsupported disable flag " + which
251                             + ": 0x" + Integer.toHexString(what));
252                     break;
253             }
254             this.pkg = pkg;
255         }
256 
getFlags(int which)257         public int getFlags(int which) {
258             switch (which) {
259                 case 1: return what1;
260                 case 2: return what2;
261                 default:
262                     Slog.w(TAG, "Can't get unsupported disable flag " + which);
263                     return 0;
264             }
265         }
266 
isEmpty()267         public boolean isEmpty() {
268             return what1 == 0 && what2 == 0;
269         }
270 
271         @Override
toString()272         public String toString() {
273             return String.format("userId=%d what1=0x%08X what2=0x%08X pkg=%s token=%s",
274                     userId, what1, what2, pkg, token);
275         }
276     }
277 
278     /**
279      * Construct the service
280      */
StatusBarManagerService(Context context)281     public StatusBarManagerService(Context context) {
282         mContext = context;
283 
284         LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
285 
286         // We always have a default display.
287         final UiState state = new UiState();
288         mDisplayUiState.put(DEFAULT_DISPLAY, state);
289 
290         final DisplayManager displayManager =
291                 (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
292         displayManager.registerDisplayListener(this, mHandler);
293         mActivityTaskManager = LocalServices.getService(ActivityTaskManagerInternal.class);
294         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
295         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
296 
297         mTileRequestTracker = new TileRequestTracker(mContext);
298         mSessionMonitor = new SessionMonitor(mContext);
299     }
300 
301     /**
302      * Publish the {@link GlobalActionsProvider}.
303      */
304     // TODO(b/259420401): investigate if we can extract GlobalActionsProvider to its own system
305     // service.
publishGlobalActionsProvider()306     public void publishGlobalActionsProvider() {
307         if (LocalServices.getService(GlobalActionsProvider.class) == null) {
308             LocalServices.addService(GlobalActionsProvider.class, mGlobalActionsProvider);
309         }
310     }
311 
getOverlayManager()312     private IOverlayManager getOverlayManager() {
313         // No need to synchronize; worst-case scenario it will be fetched twice.
314         if (mOverlayManager == null) {
315             mOverlayManager = IOverlayManager.Stub.asInterface(
316                     ServiceManager.getService(Context.OVERLAY_SERVICE));
317             if (mOverlayManager == null) {
318                 Slog.w("StatusBarManager", "warning: no OVERLAY_SERVICE");
319             }
320         }
321         return mOverlayManager;
322     }
323 
324     @Override
onDisplayAdded(int displayId)325     public void onDisplayAdded(int displayId) {}
326 
327     @Override
onDisplayRemoved(int displayId)328     public void onDisplayRemoved(int displayId) {
329         synchronized (mLock) {
330             mDisplayUiState.remove(displayId);
331         }
332     }
333 
334     @Override
onDisplayChanged(int displayId)335     public void onDisplayChanged(int displayId) {}
336 
337     /**
338      * Private API used by NotificationManagerService.
339      */
340     private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {
341         private boolean mNotificationLightOn;
342 
343         @Override
344         public void setNotificationDelegate(NotificationDelegate delegate) {
345             mNotificationDelegate = delegate;
346         }
347 
348         @Override
349         public void showScreenPinningRequest(int taskId) {
350             IStatusBar bar = mBar;
351             if (bar != null) {
352                 try {
353                     bar.showScreenPinningRequest(taskId);
354                 } catch (RemoteException e) {
355                 }
356             }
357         }
358 
359         @Override
360         public void showAssistDisclosure() {
361             IStatusBar bar = mBar;
362             if (bar != null) {
363                 try {
364                     bar.showAssistDisclosure();
365                 } catch (RemoteException e) {
366                 }
367             }
368         }
369 
370         @Override
371         public void startAssist(Bundle args) {
372             IStatusBar bar = mBar;
373             if (bar != null) {
374                 try {
375                     bar.startAssist(args);
376                 } catch (RemoteException e) {
377                 }
378             }
379         }
380 
381         @Override
382         public void onCameraLaunchGestureDetected(int source) {
383             IStatusBar bar = mBar;
384             if (bar != null) {
385                 try {
386                     bar.onCameraLaunchGestureDetected(source);
387                 } catch (RemoteException e) {
388                 }
389             }
390         }
391 
392         /**
393          * Notifies the status bar that a Emergency Action launch gesture has been detected.
394          *
395          * TODO (b/169175022) Update method name and docs when feature name is locked.
396          */
397         @Override
398         public void onEmergencyActionLaunchGestureDetected() {
399             if (SPEW) Slog.d(TAG, "Launching emergency action");
400             IStatusBar bar = mBar;
401             if (bar != null) {
402                 try {
403                     bar.onEmergencyActionLaunchGestureDetected();
404                 } catch (RemoteException e) {
405                     if (SPEW) Slog.d(TAG, "Failed to launch emergency action");
406                 }
407             }
408         }
409 
410         @Override
411         public void setDisableFlags(int displayId, int flags, String cause) {
412             StatusBarManagerService.this.setDisableFlags(displayId, flags, cause);
413         }
414 
415         @Override
416         public void toggleSplitScreen() {
417             enforceStatusBarService();
418             IStatusBar bar = mBar;
419             if (bar != null) {
420                 try {
421                     bar.toggleSplitScreen();
422                 } catch (RemoteException ex) {}
423             }
424         }
425 
426         @Override
427         public void appTransitionFinished(int displayId) {
428             enforceStatusBarService();
429             IStatusBar bar = mBar;
430             if (bar != null) {
431                 try {
432                     bar.appTransitionFinished(displayId);
433                 } catch (RemoteException ex) {}
434             }
435         }
436 
437         @Override
438         public void toggleTaskbar() {
439             IStatusBar bar = mBar;
440             if (bar != null) {
441                 try {
442                     bar.toggleTaskbar();
443                 } catch (RemoteException ex) {}
444             }
445         }
446 
447         @Override
448         public void toggleRecentApps() {
449             IStatusBar bar = mBar;
450             if (bar != null) {
451                 try {
452                     bar.toggleRecentApps();
453                 } catch (RemoteException ex) {}
454             }
455         }
456 
457         @Override
458         public void setCurrentUser(int newUserId) {
459             if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId);
460             mCurrentUserId = newUserId;
461         }
462 
463 
464         @Override
465         public void preloadRecentApps() {
466             IStatusBar bar = mBar;
467             if (bar != null) {
468                 try {
469                     bar.preloadRecentApps();
470                 } catch (RemoteException ex) {}
471             }
472         }
473 
474         @Override
475         public void cancelPreloadRecentApps() {
476             IStatusBar bar = mBar;
477             if (bar != null) {
478                 try {
479                     bar.cancelPreloadRecentApps();
480                 } catch (RemoteException ex) {}
481             }
482         }
483 
484         @Override
485         public void showRecentApps(boolean triggeredFromAltTab) {
486             IStatusBar bar = mBar;
487             if (bar != null) {
488                 try {
489                     bar.showRecentApps(triggeredFromAltTab);
490                 } catch (RemoteException ex) {}
491             }
492         }
493 
494         @Override
495         public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
496             IStatusBar bar = mBar;
497             if (bar != null) {
498                 try {
499                     bar.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey);
500                 } catch (RemoteException ex) {}
501             }
502         }
503 
504         @Override
505         public void collapsePanels() {
506             IStatusBar bar = mBar;
507             if (bar != null) {
508                 try {
509                     bar.animateCollapsePanels();
510                 } catch (RemoteException ex) {
511                 }
512             }
513         }
514 
515         @Override
516         public void dismissKeyboardShortcutsMenu() {
517             IStatusBar bar = mBar;
518             if (bar != null) {
519                 try {
520                     bar.dismissKeyboardShortcutsMenu();
521                 } catch (RemoteException ex) {}
522             }
523         }
524 
525         @Override
526         public void toggleKeyboardShortcutsMenu(int deviceId) {
527             IStatusBar bar = mBar;
528             if (bar != null) {
529                 try {
530                     bar.toggleKeyboardShortcutsMenu(deviceId);
531                 } catch (RemoteException ex) {}
532             }
533         }
534 
535         @Override
536         public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
537                 boolean showImeSwitcher) {
538             StatusBarManagerService.this.setImeWindowStatus(displayId, token, vis, backDisposition,
539                     showImeSwitcher);
540         }
541 
542         @Override
543         public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,
544                 String contentDescription) {
545             StatusBarManagerService.this.setIcon(slot, iconPackage, iconId, iconLevel,
546                     contentDescription);
547         }
548 
549         @Override
550         public void setIconVisibility(String slot, boolean visibility) {
551             StatusBarManagerService.this.setIconVisibility(slot, visibility);
552         }
553 
554         @Override
555         public void showChargingAnimation(int batteryLevel) {
556             IStatusBar bar = mBar;
557             if (bar != null) {
558                 try {
559                     bar.showWirelessChargingAnimation(batteryLevel);
560                 } catch (RemoteException ex){
561                 }
562             }
563         }
564 
565         @Override
566         public void showPictureInPictureMenu() {
567             IStatusBar bar = mBar;
568             if (bar != null) {
569                 try {
570                     mBar.showPictureInPictureMenu();
571                 } catch (RemoteException ex) {}
572             }
573         }
574 
575         @Override
576         public void setWindowState(int displayId, int window, int state) {
577             IStatusBar bar = mBar;
578             if (bar != null) {
579                 try {
580                     bar.setWindowState(displayId, window, state);
581                 } catch (RemoteException ex) {}
582             }
583         }
584 
585         @Override
586         public void appTransitionPending(int displayId) {
587             IStatusBar bar = mBar;
588             if (bar != null) {
589                 try {
590                     bar.appTransitionPending(displayId);
591                 } catch (RemoteException ex) {}
592             }
593         }
594 
595         @Override
596         public void appTransitionCancelled(int displayId) {
597             IStatusBar bar = mBar;
598             if (bar != null) {
599                 try {
600                     bar.appTransitionCancelled(displayId);
601                 } catch (RemoteException ex) {}
602             }
603         }
604 
605         @Override
606         public void appTransitionStarting(int displayId, long statusBarAnimationsStartTime,
607                 long statusBarAnimationsDuration) {
608             IStatusBar bar = mBar;
609             if (bar != null) {
610                 try {
611                     bar.appTransitionStarting(
612                             displayId, statusBarAnimationsStartTime, statusBarAnimationsDuration);
613                 } catch (RemoteException ex) {}
614             }
615         }
616 
617         @Override
618         public void setTopAppHidesStatusBar(boolean hidesStatusBar) {
619             IStatusBar bar = mBar;
620             if (bar != null) {
621                 try {
622                     bar.setTopAppHidesStatusBar(hidesStatusBar);
623                 } catch (RemoteException ex) {}
624             }
625         }
626 
627         @Override
628         public boolean showShutdownUi(boolean isReboot, String reason) {
629             if (!mContext.getResources().getBoolean(R.bool.config_showSysuiShutdown)) {
630                 return false;
631             }
632             IStatusBar bar = mBar;
633             if (bar != null) {
634                 try {
635                     bar.showShutdownUi(isReboot, reason);
636                     return true;
637                 } catch (RemoteException ex) {}
638             }
639             return false;
640         }
641 
642         @Override
643         public void confirmImmersivePrompt() {
644             if (mBar == null) {
645                 return;
646             }
647             try {
648                 mBar.confirmImmersivePrompt();
649             } catch (RemoteException ex) {
650             }
651         }
652 
653         @Override
654         public void immersiveModeChanged(int rootDisplayAreaId, boolean isImmersiveMode) {
655             if (mBar == null) {
656                 return;
657             }
658             if (!CLIENT_TRANSIENT) {
659                 // Only call from here when the client transient is not enabled.
660                 try {
661                     mBar.immersiveModeChanged(rootDisplayAreaId, isImmersiveMode);
662                 } catch (RemoteException ex) {
663                 }
664             }
665         }
666 
667         // TODO(b/118592525): support it per display if necessary.
668         @Override
669         public void onProposedRotationChanged(int rotation, boolean isValid) {
670             if (mBar != null){
671                 try {
672                     mBar.onProposedRotationChanged(rotation, isValid);
673                 } catch (RemoteException ex) {}
674             }
675         }
676 
677         @Override
678         public void onDisplayReady(int displayId) {
679             IStatusBar bar = mBar;
680             if (bar != null) {
681                 try {
682                     bar.onDisplayReady(displayId);
683                 } catch (RemoteException ex) {}
684             }
685         }
686 
687         @Override
688         public void onRecentsAnimationStateChanged(boolean running) {
689             IStatusBar bar = mBar;
690             if (bar != null) {
691                 try {
692                     bar.onRecentsAnimationStateChanged(running);
693                 } catch (RemoteException ex) {}
694             }
695 
696         }
697 
698         @Override
699         public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
700                 AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
701                 @Behavior int behavior, @InsetsType int requestedVisibleTypes,
702                 String packageName, LetterboxDetails[] letterboxDetails) {
703             getUiState(displayId).setBarAttributes(appearance, appearanceRegions,
704                     navbarColorManagedByIme, behavior, requestedVisibleTypes, packageName,
705                     letterboxDetails);
706             IStatusBar bar = mBar;
707             if (bar != null) {
708                 try {
709                     bar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
710                             navbarColorManagedByIme, behavior, requestedVisibleTypes, packageName,
711                             letterboxDetails);
712                 } catch (RemoteException ex) { }
713             }
714         }
715 
716         @Override
717         public void showTransient(int displayId, @InsetsType int types,
718                 boolean isGestureOnSystemBar) {
719             getUiState(displayId).showTransient(types);
720             IStatusBar bar = mBar;
721             if (bar != null) {
722                 try {
723                     bar.showTransient(displayId, types, isGestureOnSystemBar);
724                 } catch (RemoteException ex) { }
725             }
726         }
727 
728         @Override
729         public void abortTransient(int displayId, @InsetsType int types) {
730             getUiState(displayId).clearTransient(types);
731             IStatusBar bar = mBar;
732             if (bar != null) {
733                 try {
734                     bar.abortTransient(displayId, types);
735                 } catch (RemoteException ex) { }
736             }
737         }
738 
739         @Override
740         public void showToast(int uid, String packageName, IBinder token, CharSequence text,
741                 IBinder windowToken, int duration,
742                 @Nullable ITransientNotificationCallback callback, int displayId) {
743             IStatusBar bar = mBar;
744             if (bar != null) {
745                 try {
746                     bar.showToast(uid, packageName, token, text, windowToken, duration, callback,
747                             displayId);
748                 } catch (RemoteException ex) { }
749             }
750         }
751 
752         @Override
753         public void hideToast(String packageName, IBinder token) {
754             IStatusBar bar = mBar;
755             if (bar != null) {
756                 try {
757                     bar.hideToast(packageName, token);
758                 } catch (RemoteException ex) { }
759             }
760         }
761 
762         @Override
763         public boolean requestWindowMagnificationConnection(boolean request) {
764             IStatusBar bar = mBar;
765             if (bar != null) {
766                 try {
767                     bar.requestWindowMagnificationConnection(request);
768                     return true;
769                 } catch (RemoteException ex) { }
770             }
771             return false;
772         }
773 
774         @Override
775         public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
776             IStatusBar bar = mBar;
777             if (bar != null) {
778                 try {
779                     bar.setNavigationBarLumaSamplingEnabled(displayId, enable);
780                 } catch (RemoteException ex) { }
781             }
782         }
783 
784         @Override
785         public void setUdfpsRefreshRateCallback(IUdfpsRefreshRateRequestCallback callback) {
786             synchronized (mLock) {
787                 mUdfpsRefreshRateRequestCallback = callback;
788             }
789             IStatusBar bar = mBar;
790             if (bar != null) {
791                 try {
792                     bar.setUdfpsRefreshRateCallback(callback);
793                 } catch (RemoteException ex) { }
794             }
795         }
796 
797         @Override
798         public void showRearDisplayDialog(int currentBaseState) {
799             IStatusBar bar = mBar;
800             if (bar != null) {
801                 try {
802                     bar.showRearDisplayDialog(currentBaseState);
803                 } catch (RemoteException ex) { }
804             }
805         }
806 
807         @Override
808         public void goToFullscreenFromSplit() {
809             IStatusBar bar = mBar;
810             if (bar != null) {
811                 try {
812                     bar.goToFullscreenFromSplit();
813                 } catch (RemoteException ex) { }
814             }
815         }
816 
817         @Override
818         public void enterStageSplitFromRunningApp(boolean leftOrTop) {
819             IStatusBar bar = mBar;
820             if (bar != null) {
821                 try {
822                     bar.enterStageSplitFromRunningApp(leftOrTop);
823                 } catch (RemoteException ex) { }
824             }
825         }
826 
827         @Override
828         public void showMediaOutputSwitcher(String packageName) {
829             IStatusBar bar = mBar;
830             if (bar != null) {
831                 try {
832                     bar.showMediaOutputSwitcher(packageName);
833                 } catch (RemoteException ex) {
834                 }
835             }
836         }
837     };
838 
839     private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
840         @Override
841         public boolean isGlobalActionsDisabled() {
842             // TODO(b/118592525): support global actions for multi-display.
843             final int disabled2 = mDisplayUiState.get(DEFAULT_DISPLAY).getDisabled2();
844             return (disabled2 & DISABLE2_GLOBAL_ACTIONS) != 0;
845         }
846 
847         @Override
848         public void setGlobalActionsListener(GlobalActionsProvider.GlobalActionsListener listener) {
849             mGlobalActionListener = listener;
850             mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null);
851         }
852 
853         @Override
854         public void showGlobalActions() {
855             IStatusBar bar = mBar;
856             if (bar != null) {
857                 try {
858                     bar.showGlobalActionsMenu();
859                 } catch (RemoteException ex) {}
860             }
861         }
862     };
863 
864     /**
865      * Returns true if the target disable flag (target2) is set
866      */
isDisable2FlagSet(int target2)867     private boolean isDisable2FlagSet(int target2) {
868         final int disabled2 = mDisplayUiState.get(DEFAULT_DISPLAY).getDisabled2();
869         return ((disabled2 & target2) == target2);
870     }
871 
872     // ================================================================================
873     // From IStatusBarService
874     // ================================================================================
875 
876     @Override
expandNotificationsPanel()877     public void expandNotificationsPanel() {
878         enforceExpandStatusBar();
879 
880         if (isDisable2FlagSet(DISABLE2_NOTIFICATION_SHADE)) {
881             return;
882         }
883 
884         if (mBar != null) {
885             try {
886                 mBar.animateExpandNotificationsPanel();
887             } catch (RemoteException ex) {
888             }
889         }
890     }
891 
892     @Override
collapsePanels()893     public void collapsePanels() {
894         if (!checkCanCollapseStatusBar("collapsePanels")) {
895             return;
896         }
897 
898         if (mBar != null) {
899             try {
900                 mBar.animateCollapsePanels();
901             } catch (RemoteException ex) {
902             }
903         }
904     }
905 
906     @Override
togglePanel()907     public void togglePanel() {
908         if (!checkCanCollapseStatusBar("togglePanel")) {
909             return;
910         }
911 
912         if (isDisable2FlagSet(DISABLE2_NOTIFICATION_SHADE)) {
913             return;
914         }
915 
916         if (mBar != null) {
917             try {
918                 mBar.togglePanel();
919             } catch (RemoteException ex) {
920             }
921         }
922     }
923 
924     @Override
expandSettingsPanel(String subPanel)925     public void expandSettingsPanel(String subPanel) {
926         enforceExpandStatusBar();
927 
928         if (mBar != null) {
929             try {
930                 mBar.animateExpandSettingsPanel(subPanel);
931             } catch (RemoteException ex) {
932             }
933         }
934     }
935 
addTile(ComponentName component)936     public void addTile(ComponentName component) {
937         enforceStatusBarOrShell();
938 
939         if (mBar != null) {
940             try {
941                 mBar.addQsTile(component);
942             } catch (RemoteException ex) {
943             }
944         }
945     }
946 
remTile(ComponentName component)947     public void remTile(ComponentName component) {
948         enforceStatusBarOrShell();
949 
950         if (mBar != null) {
951             try {
952                 mBar.remQsTile(component);
953             } catch (RemoteException ex) {
954             }
955         }
956     }
957 
clickTile(ComponentName component)958     public void clickTile(ComponentName component) {
959         enforceStatusBarOrShell();
960 
961         if (mBar != null) {
962             try {
963                 mBar.clickQsTile(component);
964             } catch (RemoteException ex) {
965             }
966         }
967     }
968 
969     @Override
handleSystemKey(KeyEvent key)970     public void handleSystemKey(KeyEvent key) throws RemoteException {
971         if (!checkCanCollapseStatusBar("handleSystemKey")) {
972             return;
973         }
974 
975         mLastSystemKey = key.getKeyCode();
976 
977         if (mBar != null) {
978             try {
979                 mBar.handleSystemKey(key);
980             } catch (RemoteException ex) {
981             }
982         }
983     }
984 
985     @Override
986     @TestApi
getLastSystemKey()987     public int getLastSystemKey() {
988         enforceStatusBar();
989 
990         return mLastSystemKey;
991     }
992 
993     @Override
showPinningEnterExitToast(boolean entering)994     public void showPinningEnterExitToast(boolean entering) throws RemoteException {
995         if (mBar != null) {
996             try {
997                 mBar.showPinningEnterExitToast(entering);
998             } catch (RemoteException ex) {
999             }
1000         }
1001     }
1002 
1003     @Override
showPinningEscapeToast()1004     public void showPinningEscapeToast() throws RemoteException {
1005         if (mBar != null) {
1006             try {
1007                 mBar.showPinningEscapeToast();
1008             } catch (RemoteException ex) {
1009             }
1010         }
1011     }
1012 
1013     @Override
showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, long operationId, String opPackageName, long requestId)1014     public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
1015             int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
1016             int userId, long operationId, String opPackageName, long requestId) {
1017         enforceBiometricDialog();
1018         if (mBar != null) {
1019             try {
1020                 mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed,
1021                         requireConfirmation, userId, operationId, opPackageName, requestId);
1022             } catch (RemoteException ex) {
1023             }
1024         }
1025     }
1026 
1027     @Override
onBiometricAuthenticated(@odality int modality)1028     public void onBiometricAuthenticated(@Modality int modality) {
1029         enforceBiometricDialog();
1030         if (mBar != null) {
1031             try {
1032                 mBar.onBiometricAuthenticated(modality);
1033             } catch (RemoteException ex) {
1034             }
1035         }
1036     }
1037 
1038     @Override
onBiometricHelp(@odality int modality, String message)1039     public void onBiometricHelp(@Modality int modality, String message) {
1040         enforceBiometricDialog();
1041         if (mBar != null) {
1042             try {
1043                 mBar.onBiometricHelp(modality, message);
1044             } catch (RemoteException ex) {
1045             }
1046         }
1047     }
1048 
1049     @Override
onBiometricError(int modality, int error, int vendorCode)1050     public void onBiometricError(int modality, int error, int vendorCode) {
1051         enforceBiometricDialog();
1052         if (mBar != null) {
1053             try {
1054                 mBar.onBiometricError(modality, error, vendorCode);
1055             } catch (RemoteException ex) {
1056             }
1057         }
1058     }
1059 
1060     @Override
hideAuthenticationDialog(long requestId)1061     public void hideAuthenticationDialog(long requestId) {
1062         enforceBiometricDialog();
1063         if (mBar != null) {
1064             try {
1065                 mBar.hideAuthenticationDialog(requestId);
1066             } catch (RemoteException ex) {
1067             }
1068         }
1069     }
1070 
1071     @Override
setBiometicContextListener(IBiometricContextListener listener)1072     public void setBiometicContextListener(IBiometricContextListener listener) {
1073         enforceStatusBarService();
1074         synchronized (mLock) {
1075             mBiometricContextListener = listener;
1076         }
1077         if (mBar != null) {
1078             try {
1079                 mBar.setBiometicContextListener(listener);
1080             } catch (RemoteException ex) {
1081             }
1082         }
1083     }
1084 
1085     @Override
setUdfpsRefreshRateCallback(IUdfpsRefreshRateRequestCallback callback)1086     public void setUdfpsRefreshRateCallback(IUdfpsRefreshRateRequestCallback callback) {
1087         enforceStatusBarService();
1088         if (mBar != null) {
1089             try {
1090                 mBar.setUdfpsRefreshRateCallback(callback);
1091             } catch (RemoteException ex) {
1092             }
1093         }
1094     }
1095 
1096     @Override
startTracing()1097     public void startTracing() {
1098         if (mBar != null) {
1099             try {
1100                 mBar.startTracing();
1101                 mTracingEnabled = true;
1102             } catch (RemoteException ex) {
1103             }
1104         }
1105     }
1106 
1107     @Override
stopTracing()1108     public void stopTracing() {
1109         if (mBar != null) {
1110             try {
1111                 mTracingEnabled = false;
1112                 mBar.stopTracing();
1113             } catch (RemoteException ex) {}
1114         }
1115     }
1116 
1117     @Override
isTracing()1118     public boolean isTracing() {
1119         return mTracingEnabled;
1120     }
1121 
1122     // TODO(b/117478341): make it aware of multi-display if needed.
1123     @Override
disable(int what, IBinder token, String pkg)1124     public void disable(int what, IBinder token, String pkg) {
1125         disableForUser(what, token, pkg, mCurrentUserId);
1126     }
1127 
1128     // TODO(b/117478341): make it aware of multi-display if needed.
1129     @Override
disableForUser(int what, IBinder token, String pkg, int userId)1130     public void disableForUser(int what, IBinder token, String pkg, int userId) {
1131         enforceStatusBar();
1132 
1133         synchronized (mLock) {
1134             disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 1);
1135         }
1136     }
1137 
1138     // TODO(b/117478341): make it aware of multi-display if needed.
1139     /**
1140      * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags.
1141      * To re-enable everything, pass {@link #DISABLE2_NONE}.
1142      *
1143      * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
1144      */
1145     @Override
disable2(int what, IBinder token, String pkg)1146     public void disable2(int what, IBinder token, String pkg) {
1147         disable2ForUser(what, token, pkg, mCurrentUserId);
1148     }
1149 
1150     // TODO(b/117478341): make it aware of multi-display if needed.
1151     /**
1152      * Disable additional status bar features for a given user. Pass the bitwise-or of the
1153      * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}.
1154      *
1155      * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
1156      */
1157     @Override
disable2ForUser(int what, IBinder token, String pkg, int userId)1158     public void disable2ForUser(int what, IBinder token, String pkg, int userId) {
1159         enforceStatusBar();
1160 
1161         synchronized (mLock) {
1162             disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 2);
1163         }
1164     }
1165 
disableLocked(int displayId, int userId, int what, IBinder token, String pkg, int whichFlag)1166     private void disableLocked(int displayId, int userId, int what, IBinder token, String pkg,
1167             int whichFlag) {
1168         // It's important that the the callback and the call to mBar get done
1169         // in the same order when multiple threads are calling this function
1170         // so they are paired correctly.  The messages on the handler will be
1171         // handled in the order they were enqueued, but will be outside the lock.
1172         manageDisableListLocked(userId, what, token, pkg, whichFlag);
1173 
1174         // Ensure state for the current user is applied, even if passed a non-current user.
1175         final int net1 = gatherDisableActionsLocked(mCurrentUserId, 1);
1176         final int net2 = gatherDisableActionsLocked(mCurrentUserId, 2);
1177         final UiState state = getUiState(displayId);
1178         if (!state.disableEquals(net1, net2)) {
1179             state.setDisabled(net1, net2);
1180             mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1));
1181             IStatusBar bar = mBar;
1182             if (bar != null) {
1183                 try {
1184                     bar.disable(displayId, net1, net2);
1185                 } catch (RemoteException ex) {
1186                 }
1187             }
1188         }
1189     }
1190 
1191     /**
1192      * Get the currently applied disable flags, in the form of one Pair<Integer, Integer>.
1193      *
1194      * @return pair of disable flags in the form of (disabled1, disabled2), where (0, 0) indicates
1195      * no flags are set for this token.
1196      */
1197     @Override
getDisableFlags(IBinder token, int userId)1198     public int[] getDisableFlags(IBinder token, int userId) {
1199         enforceStatusBar();
1200 
1201         int disable1 = 0;
1202         int disable2 = 0;
1203         synchronized (mLock) {
1204             // Find a matching record if it exists
1205             DisableRecord record = findMatchingRecordLocked(token, userId).second;
1206             if (record != null) {
1207                 disable1 = record.what1;
1208                 disable2 = record.what2;
1209             }
1210         }
1211 
1212         return new int[] {disable1, disable2};
1213     }
1214 
runGcForTest()1215     void runGcForTest() {
1216         if (!Build.IS_DEBUGGABLE) {
1217             throw new SecurityException("runGcForTest requires a debuggable build");
1218         }
1219 
1220         // Gc the system along the way
1221         GcUtils.runGcAndFinalizersSync();
1222 
1223         if (mBar != null) {
1224             try {
1225                 mBar.runGcForTest();
1226             } catch (RemoteException ex) {
1227             }
1228         }
1229     }
1230 
1231     @Override
setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription)1232     public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,
1233             String contentDescription) {
1234         enforceStatusBar();
1235 
1236         synchronized (mIcons) {
1237             StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId,
1238                     iconLevel, 0, contentDescription);
1239             //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
1240             mIcons.put(slot, icon);
1241 
1242             IStatusBar bar = mBar;
1243             if (bar != null) {
1244                 try {
1245                     bar.setIcon(slot, icon);
1246                 } catch (RemoteException ex) {
1247                 }
1248             }
1249         }
1250     }
1251 
1252     @Override
setIconVisibility(String slot, boolean visibility)1253     public void setIconVisibility(String slot, boolean visibility) {
1254         enforceStatusBar();
1255 
1256         synchronized (mIcons) {
1257             StatusBarIcon icon = mIcons.get(slot);
1258             if (icon == null) {
1259                 return;
1260             }
1261             if (icon.visible != visibility) {
1262                 icon.visible = visibility;
1263 
1264                 IStatusBar bar = mBar;
1265                 if (bar != null) {
1266                     try {
1267                         bar.setIcon(slot, icon);
1268                     } catch (RemoteException ex) {
1269                     }
1270                 }
1271             }
1272         }
1273     }
1274 
1275     @Override
removeIcon(String slot)1276     public void removeIcon(String slot) {
1277         enforceStatusBar();
1278 
1279         synchronized (mIcons) {
1280             mIcons.remove(slot);
1281 
1282             IStatusBar bar = mBar;
1283             if (bar != null) {
1284                 try {
1285                     bar.removeIcon(slot);
1286                 } catch (RemoteException ex) {
1287                 }
1288             }
1289         }
1290     }
1291 
1292     @Override
setImeWindowStatus(int displayId, final IBinder token, final int vis, final int backDisposition, final boolean showImeSwitcher)1293     public void setImeWindowStatus(int displayId, final IBinder token, final int vis,
1294             final int backDisposition, final boolean showImeSwitcher) {
1295         enforceStatusBar();
1296 
1297         if (SPEW) {
1298             Slog.d(TAG, "swetImeWindowStatus vis=" + vis + " backDisposition=" + backDisposition);
1299         }
1300 
1301         synchronized(mLock) {
1302             // In case of IME change, we need to call up setImeWindowStatus() regardless of
1303             // mImeWindowVis because mImeWindowVis may not have been set to false when the
1304             // previous IME was destroyed.
1305             getUiState(displayId).setImeWindowState(vis, backDisposition, showImeSwitcher, token);
1306 
1307             mHandler.post(() -> {
1308                 if (mBar == null) return;
1309                 try {
1310                     mBar.setImeWindowStatus(
1311                             displayId, token, vis, backDisposition, showImeSwitcher);
1312                 } catch (RemoteException ex) { }
1313             });
1314         }
1315     }
1316 
setDisableFlags(int displayId, int flags, String cause)1317     private void setDisableFlags(int displayId, int flags, String cause) {
1318         // also allows calls from window manager which is in this process.
1319         enforceStatusBarService();
1320 
1321         final int unknownFlags = flags & ~StatusBarManager.DISABLE_MASK;
1322         if (unknownFlags != 0) {
1323             Slog.e(TAG, "Unknown disable flags: 0x" + Integer.toHexString(unknownFlags),
1324                     new RuntimeException());
1325         }
1326 
1327         if (SPEW) Slog.d(TAG, "setDisableFlags(0x" + Integer.toHexString(flags) + ")");
1328 
1329         synchronized (mLock) {
1330             disableLocked(displayId, mCurrentUserId, flags, mSysUiVisToken, cause, 1);
1331         }
1332     }
1333 
1334     /**
1335      * @return {@link UiState} specified by {@code displayId}.
1336      *
1337      * <p>
1338      *   Note: If {@link UiState} specified by {@code displayId} does not exist, {@link UiState}
1339      *   will be allocated and {@code mDisplayUiState} will be updated accordingly.
1340      * <p/>
1341      */
getUiState(int displayId)1342     private UiState getUiState(int displayId) {
1343         UiState state = mDisplayUiState.get(displayId);
1344         if (state == null) {
1345             state = new UiState();
1346             mDisplayUiState.put(displayId, state);
1347         }
1348         return state;
1349     }
1350 
1351     private static class UiState {
1352         private @Appearance int mAppearance = 0;
1353         private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0];
1354         private @InsetsType int mTransientBarTypes;
1355         private boolean mNavbarColorManagedByIme = false;
1356         private @Behavior int mBehavior;
1357         private @InsetsType int mRequestedVisibleTypes = WindowInsets.Type.defaultVisible();
1358         private String mPackageName = "none";
1359         private int mDisabled1 = 0;
1360         private int mDisabled2 = 0;
1361         private int mImeWindowVis = 0;
1362         private int mImeBackDisposition = 0;
1363         private boolean mShowImeSwitcher = false;
1364         private IBinder mImeToken = null;
1365         private LetterboxDetails[] mLetterboxDetails = new LetterboxDetails[0];
1366 
setBarAttributes(@ppearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, @Behavior int behavior, @InsetsType int requestedVisibleTypes, String packageName, LetterboxDetails[] letterboxDetails)1367         private void setBarAttributes(@Appearance int appearance,
1368                 AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
1369                 @Behavior int behavior, @InsetsType int requestedVisibleTypes,
1370                 String packageName,
1371                 LetterboxDetails[] letterboxDetails) {
1372             mAppearance = appearance;
1373             mAppearanceRegions = appearanceRegions;
1374             mNavbarColorManagedByIme = navbarColorManagedByIme;
1375             mBehavior = behavior;
1376             mRequestedVisibleTypes = requestedVisibleTypes;
1377             mPackageName = packageName;
1378             mLetterboxDetails = letterboxDetails;
1379         }
1380 
showTransient(@nsetsType int types)1381         private void showTransient(@InsetsType int types) {
1382             mTransientBarTypes |= types;
1383         }
1384 
clearTransient(@nsetsType int types)1385         private void clearTransient(@InsetsType int types) {
1386             mTransientBarTypes &= ~types;
1387         }
1388 
getDisabled1()1389         private int getDisabled1() {
1390             return mDisabled1;
1391         }
1392 
getDisabled2()1393         private int getDisabled2() {
1394             return mDisabled2;
1395         }
1396 
setDisabled(int disabled1, int disabled2)1397         private void setDisabled(int disabled1, int disabled2) {
1398             mDisabled1 = disabled1;
1399             mDisabled2 = disabled2;
1400         }
1401 
disableEquals(int disabled1, int disabled2)1402         private boolean disableEquals(int disabled1, int disabled2) {
1403             return mDisabled1 == disabled1 && mDisabled2 == disabled2;
1404         }
1405 
setImeWindowState(final int vis, final int backDisposition, final boolean showImeSwitcher, final IBinder token)1406         private void setImeWindowState(final int vis, final int backDisposition,
1407                 final boolean showImeSwitcher, final IBinder token) {
1408             mImeWindowVis = vis;
1409             mImeBackDisposition = backDisposition;
1410             mShowImeSwitcher = showImeSwitcher;
1411             mImeToken = token;
1412         }
1413     }
1414 
enforceStatusBarOrShell()1415     private void enforceStatusBarOrShell() {
1416         if (Binder.getCallingUid() == Process.SHELL_UID) {
1417             return;
1418         }
1419         enforceStatusBar();
1420     }
1421 
enforceStatusBar()1422     private void enforceStatusBar() {
1423         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
1424                 "StatusBarManagerService");
1425     }
1426 
enforceExpandStatusBar()1427     private void enforceExpandStatusBar() {
1428         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.EXPAND_STATUS_BAR,
1429                 "StatusBarManagerService");
1430     }
1431 
enforceStatusBarService()1432     private void enforceStatusBarService() {
1433         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1434                 "StatusBarManagerService");
1435     }
1436 
enforceBiometricDialog()1437     private void enforceBiometricDialog() {
1438         mContext.enforceCallingOrSelfPermission(
1439                 android.Manifest.permission.MANAGE_BIOMETRIC_DIALOG,
1440                 "StatusBarManagerService");
1441     }
1442 
enforceMediaContentControl()1443     private void enforceMediaContentControl() {
1444         mContext.enforceCallingOrSelfPermission(
1445                 android.Manifest.permission.MEDIA_CONTENT_CONTROL,
1446                 "StatusBarManagerService");
1447     }
1448 
1449     @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)
enforceControlDeviceStatePermission()1450     private void enforceControlDeviceStatePermission() {
1451         mContext.enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, "StatusBarManagerService");
1452     }
1453 
doesCallerHoldInteractAcrossUserPermission()1454     private boolean doesCallerHoldInteractAcrossUserPermission() {
1455         return mContext.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) == PERMISSION_GRANTED
1456                 || mContext.checkCallingPermission(INTERACT_ACROSS_USERS) == PERMISSION_GRANTED;
1457     }
1458 
1459     /**
1460      *  For targetSdk S+ we require STATUS_BAR. For targetSdk < S, we only require EXPAND_STATUS_BAR
1461      *  but also require that it falls into one of the allowed use-cases to lock down abuse vector.
1462      */
checkCanCollapseStatusBar(String method)1463     private boolean checkCanCollapseStatusBar(String method) {
1464         int uid = Binder.getCallingUid();
1465         int pid = Binder.getCallingPid();
1466         if (CompatChanges.isChangeEnabled(LOCK_DOWN_COLLAPSE_STATUS_BAR, uid)) {
1467             enforceStatusBar();
1468         } else {
1469             if (mContext.checkPermission(Manifest.permission.STATUS_BAR, pid, uid)
1470                     != PERMISSION_GRANTED) {
1471                 enforceExpandStatusBar();
1472                 if (!mActivityTaskManager.canCloseSystemDialogs(pid, uid)) {
1473                     Slog.e(TAG, "Permission Denial: Method " + method + "() requires permission "
1474                             + Manifest.permission.STATUS_BAR + ", ignoring call.");
1475                     return false;
1476                 }
1477             }
1478         }
1479         return true;
1480     }
1481 
1482     // ================================================================================
1483     // Callbacks from the status bar service.
1484     // ================================================================================
1485     // TODO(b/118592525): refactor it as an IStatusBar API.
1486     @Override
registerStatusBar(IStatusBar bar)1487     public RegisterStatusBarResult registerStatusBar(IStatusBar bar) {
1488         enforceStatusBarService();
1489 
1490         Slog.i(TAG, "registerStatusBar bar=" + bar);
1491         mBar = bar;
1492         mDeathRecipient.linkToDeath();
1493         notifyBarAttachChanged();
1494         final ArrayMap<String, StatusBarIcon> icons;
1495         synchronized (mIcons) {
1496             icons = new ArrayMap<>(mIcons);
1497         }
1498         synchronized (mLock) {
1499             // TODO(b/118592525): Currently, status bar only works on the default display.
1500             // Make it aware of multi-display if needed.
1501             final UiState state = mDisplayUiState.get(DEFAULT_DISPLAY);
1502             return new RegisterStatusBarResult(icons, gatherDisableActionsLocked(mCurrentUserId, 1),
1503                     state.mAppearance, state.mAppearanceRegions, state.mImeWindowVis,
1504                     state.mImeBackDisposition, state.mShowImeSwitcher,
1505                     gatherDisableActionsLocked(mCurrentUserId, 2), state.mImeToken,
1506                     state.mNavbarColorManagedByIme, state.mBehavior, state.mRequestedVisibleTypes,
1507                     state.mPackageName, state.mTransientBarTypes, state.mLetterboxDetails);
1508         }
1509     }
1510 
notifyBarAttachChanged()1511     private void notifyBarAttachChanged() {
1512         UiThread.getHandler().post(() -> {
1513             if (mGlobalActionListener == null) return;
1514             mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null);
1515         });
1516         // If StatusBarService dies, system_server doesn't get killed with it, so we need to make
1517         // sure the UDFPS callback is refreshed as well. Deferring to the handler just so to avoid
1518         // making registerStatusBar re-entrant.
1519         mHandler.post(() -> {
1520             synchronized (mLock) {
1521                 setUdfpsRefreshRateCallback(mUdfpsRefreshRateRequestCallback);
1522                 setBiometicContextListener(mBiometricContextListener);
1523             }
1524         });
1525     }
1526 
1527     @VisibleForTesting
registerOverlayManager(IOverlayManager overlayManager)1528     void registerOverlayManager(IOverlayManager overlayManager) {
1529         mOverlayManager = overlayManager;
1530     }
1531 
1532     /**
1533      * @param clearNotificationEffects whether to consider notifications as "shown" and stop
1534      *     LED, vibration, and ringing
1535      */
1536     @Override
onPanelRevealed(boolean clearNotificationEffects, int numItems)1537     public void onPanelRevealed(boolean clearNotificationEffects, int numItems) {
1538         enforceStatusBarService();
1539         final long identity = Binder.clearCallingIdentity();
1540         try {
1541             mNotificationDelegate.onPanelRevealed(clearNotificationEffects, numItems);
1542         } finally {
1543             Binder.restoreCallingIdentity(identity);
1544         }
1545     }
1546 
1547     @Override
clearNotificationEffects()1548     public void clearNotificationEffects() throws RemoteException {
1549         enforceStatusBarService();
1550         final long identity = Binder.clearCallingIdentity();
1551         try {
1552             mNotificationDelegate.clearEffects();
1553         } finally {
1554             Binder.restoreCallingIdentity(identity);
1555         }
1556     }
1557 
1558     @Override
onPanelHidden()1559     public void onPanelHidden() throws RemoteException {
1560         enforceStatusBarService();
1561         final long identity = Binder.clearCallingIdentity();
1562         try {
1563             mNotificationDelegate.onPanelHidden();
1564         } finally {
1565             Binder.restoreCallingIdentity(identity);
1566         }
1567     }
1568 
1569     /**
1570      * Allows the status bar to shutdown the device.
1571      */
1572     @Override
shutdown()1573     public void shutdown() {
1574         enforceStatusBarService();
1575         String reason = PowerManager.SHUTDOWN_USER_REQUESTED;
1576         ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
1577         final long identity = Binder.clearCallingIdentity();
1578         try {
1579             mNotificationDelegate.prepareForPossibleShutdown();
1580             // ShutdownThread displays UI, so give it a UI context.
1581             mHandler.post(() ->
1582                     ShutdownThread.shutdown(getUiContext(), reason, false));
1583         } finally {
1584             Binder.restoreCallingIdentity(identity);
1585         }
1586     }
1587 
1588     /**
1589      * Allows the status bar to reboot the device.
1590      */
1591     @Override
reboot(boolean safeMode)1592     public void reboot(boolean safeMode) {
1593         enforceStatusBarService();
1594         String reason = safeMode
1595                 ? PowerManager.REBOOT_SAFE_MODE
1596                 : PowerManager.SHUTDOWN_USER_REQUESTED;
1597         ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
1598         final long identity = Binder.clearCallingIdentity();
1599         try {
1600             mNotificationDelegate.prepareForPossibleShutdown();
1601             mHandler.post(() -> {
1602                 // ShutdownThread displays UI, so give it a UI context.
1603                 if (safeMode) {
1604                     ShutdownThread.rebootSafeMode(getUiContext(), true);
1605                 } else {
1606                     ShutdownThread.reboot(getUiContext(), reason, false);
1607                 }
1608             });
1609         } finally {
1610             Binder.restoreCallingIdentity(identity);
1611         }
1612     }
1613 
1614     /**
1615      * Allows the status bar to restart android (vs a full reboot).
1616      */
1617     @Override
restart()1618     public void restart() {
1619         enforceStatusBarService();
1620         final long identity = Binder.clearCallingIdentity();
1621         try {
1622             mHandler.post(() -> {
1623                 mActivityManagerInternal.restart();
1624             });
1625         } finally {
1626             Binder.restoreCallingIdentity(identity);
1627         }
1628     }
1629 
1630     @Override
onGlobalActionsShown()1631     public void onGlobalActionsShown() {
1632         enforceStatusBarService();
1633         final long identity = Binder.clearCallingIdentity();
1634         try {
1635             if (mGlobalActionListener == null) return;
1636             mGlobalActionListener.onGlobalActionsShown();
1637         } finally {
1638             Binder.restoreCallingIdentity(identity);
1639         }
1640     }
1641 
1642     @Override
onGlobalActionsHidden()1643     public void onGlobalActionsHidden() {
1644         enforceStatusBarService();
1645         final long identity = Binder.clearCallingIdentity();
1646         try {
1647             if (mGlobalActionListener == null) return;
1648             mGlobalActionListener.onGlobalActionsDismissed();
1649         } finally {
1650             Binder.restoreCallingIdentity(identity);
1651         }
1652     }
1653 
1654     @Override
onNotificationClick(String key, NotificationVisibility nv)1655     public void onNotificationClick(String key, NotificationVisibility nv) {
1656         enforceStatusBarService();
1657         final int callingUid = Binder.getCallingUid();
1658         final int callingPid = Binder.getCallingPid();
1659         final long identity = Binder.clearCallingIdentity();
1660         try {
1661             mNotificationDelegate.onNotificationClick(callingUid, callingPid, key, nv);
1662         } finally {
1663             Binder.restoreCallingIdentity(identity);
1664         }
1665     }
1666 
1667     @Override
onNotificationActionClick( String key, int actionIndex, Notification.Action action, NotificationVisibility nv, boolean generatedByAssistant)1668     public void onNotificationActionClick(
1669             String key, int actionIndex, Notification.Action action, NotificationVisibility nv,
1670             boolean generatedByAssistant) {
1671         enforceStatusBarService();
1672         final int callingUid = Binder.getCallingUid();
1673         final int callingPid = Binder.getCallingPid();
1674         final long identity = Binder.clearCallingIdentity();
1675         try {
1676             mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key,
1677                     actionIndex, action, nv, generatedByAssistant);
1678         } finally {
1679             Binder.restoreCallingIdentity(identity);
1680         }
1681     }
1682 
1683     @Override
onNotificationError(String pkg, String tag, int id, int uid, int initialPid, String message, int userId)1684     public void onNotificationError(String pkg, String tag, int id,
1685             int uid, int initialPid, String message, int userId) {
1686         enforceStatusBarService();
1687         final int callingUid = Binder.getCallingUid();
1688         final int callingPid = Binder.getCallingPid();
1689         final long identity = Binder.clearCallingIdentity();
1690         try {
1691             // WARNING: this will call back into us to do the remove.  Don't hold any locks.
1692             mNotificationDelegate.onNotificationError(callingUid, callingPid,
1693                     pkg, tag, id, uid, initialPid, message, userId);
1694         } finally {
1695             Binder.restoreCallingIdentity(identity);
1696         }
1697     }
1698 
1699     @Override
onNotificationClear(String pkg, int userId, String key, @NotificationStats.DismissalSurface int dismissalSurface, @NotificationStats.DismissalSentiment int dismissalSentiment, NotificationVisibility nv)1700     public void onNotificationClear(String pkg, int userId, String key,
1701             @NotificationStats.DismissalSurface int dismissalSurface,
1702             @NotificationStats.DismissalSentiment int dismissalSentiment,
1703             NotificationVisibility nv) {
1704         enforceStatusBarService();
1705         final int callingUid = Binder.getCallingUid();
1706         final int callingPid = Binder.getCallingPid();
1707         final long identity = Binder.clearCallingIdentity();
1708         try {
1709             mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, userId,
1710                     key, dismissalSurface, dismissalSentiment, nv);
1711         } finally {
1712             Binder.restoreCallingIdentity(identity);
1713         }
1714     }
1715 
1716     @Override
onNotificationVisibilityChanged( NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys)1717     public void onNotificationVisibilityChanged(
1718             NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys)
1719             throws RemoteException {
1720         enforceStatusBarService();
1721         final long identity = Binder.clearCallingIdentity();
1722         try {
1723             mNotificationDelegate.onNotificationVisibilityChanged(
1724                     newlyVisibleKeys, noLongerVisibleKeys);
1725         } finally {
1726             Binder.restoreCallingIdentity(identity);
1727         }
1728     }
1729 
1730     @Override
onNotificationExpansionChanged(String key, boolean userAction, boolean expanded, int location)1731     public void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded,
1732             int location) throws RemoteException {
1733         enforceStatusBarService();
1734         final long identity = Binder.clearCallingIdentity();
1735         try {
1736             mNotificationDelegate.onNotificationExpansionChanged(
1737                     key, userAction, expanded, location);
1738         } finally {
1739             Binder.restoreCallingIdentity(identity);
1740         }
1741     }
1742 
1743     @Override
onNotificationDirectReplied(String key)1744     public void onNotificationDirectReplied(String key) throws RemoteException {
1745         enforceStatusBarService();
1746         final long identity = Binder.clearCallingIdentity();
1747         try {
1748             mNotificationDelegate.onNotificationDirectReplied(key);
1749         } finally {
1750             Binder.restoreCallingIdentity(identity);
1751         }
1752     }
1753 
1754     @Override
onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending)1755     public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount,
1756             int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) {
1757         enforceStatusBarService();
1758         final long identity = Binder.clearCallingIdentity();
1759         try {
1760             mNotificationDelegate.onNotificationSmartSuggestionsAdded(key, smartReplyCount,
1761                     smartActionCount, generatedByAssistant, editBeforeSending);
1762         } finally {
1763             Binder.restoreCallingIdentity(identity);
1764         }
1765     }
1766 
1767     @Override
onNotificationSmartReplySent( String key, int replyIndex, CharSequence reply, int notificationLocation, boolean modifiedBeforeSending)1768     public void onNotificationSmartReplySent(
1769             String key, int replyIndex, CharSequence reply, int notificationLocation,
1770             boolean modifiedBeforeSending) throws RemoteException {
1771         enforceStatusBarService();
1772         final long identity = Binder.clearCallingIdentity();
1773         try {
1774             mNotificationDelegate.onNotificationSmartReplySent(key, replyIndex, reply,
1775                     notificationLocation, modifiedBeforeSending);
1776         } finally {
1777             Binder.restoreCallingIdentity(identity);
1778         }
1779     }
1780 
1781     @Override
onNotificationSettingsViewed(String key)1782     public void onNotificationSettingsViewed(String key) throws RemoteException {
1783         enforceStatusBarService();
1784         final long identity = Binder.clearCallingIdentity();
1785         try {
1786             mNotificationDelegate.onNotificationSettingsViewed(key);
1787         } finally {
1788             Binder.restoreCallingIdentity(identity);
1789         }
1790     }
1791 
1792     @Override
onClearAllNotifications(int userId)1793     public void onClearAllNotifications(int userId) {
1794         enforceStatusBarService();
1795         final int callingUid = Binder.getCallingUid();
1796         final int callingPid = Binder.getCallingPid();
1797         final long identity = Binder.clearCallingIdentity();
1798         try {
1799             mNotificationDelegate.onClearAll(callingUid, callingPid, userId);
1800         } finally {
1801             Binder.restoreCallingIdentity(identity);
1802         }
1803     }
1804 
1805     @Override
onNotificationBubbleChanged(String key, boolean isBubble, int flags)1806     public void onNotificationBubbleChanged(String key, boolean isBubble, int flags) {
1807         enforceStatusBarService();
1808         final long identity = Binder.clearCallingIdentity();
1809         try {
1810             mNotificationDelegate.onNotificationBubbleChanged(key, isBubble, flags);
1811         } finally {
1812             Binder.restoreCallingIdentity(identity);
1813         }
1814     }
1815 
1816     @Override
onBubbleMetadataFlagChanged(String key, int flags)1817     public void onBubbleMetadataFlagChanged(String key, int flags) {
1818         enforceStatusBarService();
1819         final long identity = Binder.clearCallingIdentity();
1820         try {
1821             mNotificationDelegate.onBubbleMetadataFlagChanged(key, flags);
1822         } finally {
1823             Binder.restoreCallingIdentity(identity);
1824         }
1825     }
1826 
1827     @Override
hideCurrentInputMethodForBubbles()1828     public void hideCurrentInputMethodForBubbles() {
1829         enforceStatusBarService();
1830         final long token = Binder.clearCallingIdentity();
1831         try {
1832             InputMethodManagerInternal.get().hideCurrentInputMethod(
1833                     SoftInputShowHideReason.HIDE_BUBBLES);
1834         } finally {
1835             Binder.restoreCallingIdentity(token);
1836         }
1837     }
1838 
1839     @Override
grantInlineReplyUriPermission(String key, Uri uri, UserHandle user, String packageName)1840     public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user,
1841             String packageName) {
1842         enforceStatusBarService();
1843         int callingUid = Binder.getCallingUid();
1844         final long identity = Binder.clearCallingIdentity();
1845         try {
1846             mNotificationDelegate.grantInlineReplyUriPermission(key, uri, user, packageName,
1847                     callingUid);
1848         } finally {
1849             Binder.restoreCallingIdentity(identity);
1850         }
1851     }
1852 
1853     @Override
clearInlineReplyUriPermissions(String key)1854     public void clearInlineReplyUriPermissions(String key) {
1855         enforceStatusBarService();
1856         int callingUid = Binder.getCallingUid();
1857         final long identity = Binder.clearCallingIdentity();
1858         try {
1859             mNotificationDelegate.clearInlineReplyUriPermissions(key, callingUid);
1860         } finally {
1861             Binder.restoreCallingIdentity(identity);
1862         }
1863     }
1864 
1865     @Override
onNotificationFeedbackReceived(String key, Bundle feedback)1866     public void onNotificationFeedbackReceived(String key, Bundle feedback) {
1867         enforceStatusBarService();
1868         final long identity = Binder.clearCallingIdentity();
1869         try {
1870             mNotificationDelegate.onNotificationFeedbackReceived(key, feedback);
1871         } finally {
1872             Binder.restoreCallingIdentity(identity);
1873         }
1874     }
1875 
1876 
1877     @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1878     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1879             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
1880         (new StatusBarShellCommand(this, mContext)).exec(
1881                 this, in, out, err, args, callback, resultReceiver);
1882     }
1883 
1884     @Override
showInattentiveSleepWarning()1885     public void showInattentiveSleepWarning() {
1886         enforceStatusBarService();
1887         IStatusBar bar = mBar;
1888         if (bar != null) {
1889             try {
1890                 bar.showInattentiveSleepWarning();
1891             } catch (RemoteException ex) {
1892             }
1893         }
1894     }
1895 
1896     @Override
dismissInattentiveSleepWarning(boolean animated)1897     public void dismissInattentiveSleepWarning(boolean animated) {
1898         enforceStatusBarService();
1899         IStatusBar bar = mBar;
1900         if (bar != null) {
1901             try {
1902                 bar.dismissInattentiveSleepWarning(animated);
1903             } catch (RemoteException ex) {
1904             }
1905         }
1906     }
1907 
1908     @Override
suppressAmbientDisplay(boolean suppress)1909     public void suppressAmbientDisplay(boolean suppress) {
1910         enforceStatusBarService();
1911         IStatusBar bar = mBar;
1912         if (bar != null) {
1913             try {
1914                 bar.suppressAmbientDisplay(suppress);
1915             } catch (RemoteException ex) {
1916             }
1917         }
1918     }
1919 
checkCallingUidPackage(String packageName, int callingUid, int userId)1920     private void checkCallingUidPackage(String packageName, int callingUid, int userId) {
1921         int packageUid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
1922         if (UserHandle.getAppId(callingUid) != UserHandle.getAppId(packageUid)) {
1923             throw new SecurityException("Package " + packageName
1924                     + " does not belong to the calling uid " + callingUid);
1925         }
1926     }
1927 
isComponentValidTileService(ComponentName componentName, int userId)1928     private ResolveInfo isComponentValidTileService(ComponentName componentName, int userId) {
1929         Intent intent = new Intent(TileService.ACTION_QS_TILE);
1930         intent.setComponent(componentName);
1931         ResolveInfo r = mPackageManagerInternal.resolveService(intent,
1932                 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 0, userId,
1933                 Process.myUid());
1934         int enabled = mPackageManagerInternal.getComponentEnabledSetting(
1935                 componentName, Process.myUid(), userId);
1936         if (r != null
1937                 && r.serviceInfo != null
1938                 && resolveEnabledComponent(r.serviceInfo.enabled, enabled)
1939                 && Manifest.permission.BIND_QUICK_SETTINGS_TILE.equals(r.serviceInfo.permission)) {
1940             return r;
1941         } else {
1942             return null;
1943         }
1944     }
1945 
resolveEnabledComponent(boolean defaultValue, int pmResult)1946     private boolean resolveEnabledComponent(boolean defaultValue, int pmResult) {
1947         if (pmResult == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
1948             return true;
1949         }
1950         if (pmResult == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1951             return defaultValue;
1952         }
1953         return false;
1954     }
1955 
1956     @Override
requestTileServiceListeningState( @onNull ComponentName componentName, int userId )1957     public void requestTileServiceListeningState(
1958             @NonNull ComponentName componentName,
1959             int userId
1960     ) {
1961         int callingUid = Binder.getCallingUid();
1962         String packageName = componentName.getPackageName();
1963 
1964         boolean mustPerformChecks = CompatChanges.isChangeEnabled(
1965                 REQUEST_LISTENING_MUST_MATCH_PACKAGE, callingUid);
1966 
1967         if (mustPerformChecks) {
1968             // Check calling user can act on behalf of current user
1969             userId = mActivityManagerInternal.handleIncomingUser(Binder.getCallingPid(), callingUid,
1970                     userId, false, ActivityManagerInternal.ALLOW_NON_FULL,
1971                     "requestTileServiceListeningState", packageName);
1972 
1973             // Check calling uid matches package
1974             checkCallingUidPackage(packageName, callingUid, userId);
1975 
1976             int currentUser = mActivityManagerInternal.getCurrentUserId();
1977 
1978             // Check current user
1979             if (userId != currentUser) {
1980                 if (CompatChanges.isChangeEnabled(REQUEST_LISTENING_OTHER_USER_NOOP, callingUid)) {
1981                     return;
1982                 } else {
1983                     throw new IllegalArgumentException(
1984                             "User " + userId + " is not the current user.");
1985                 }
1986             }
1987         }
1988         IStatusBar bar = mBar;
1989         if (bar != null) {
1990             try {
1991                 bar.requestTileServiceListeningState(componentName);
1992             } catch (RemoteException e) {
1993                 Slog.e(TAG, "requestTileServiceListeningState", e);
1994             }
1995         }
1996     }
1997 
1998     @Override
requestAddTile( @onNull ComponentName componentName, @NonNull CharSequence label, @NonNull Icon icon, int userId, @NonNull IAddTileResultCallback callback )1999     public void requestAddTile(
2000             @NonNull ComponentName componentName,
2001             @NonNull CharSequence label,
2002             @NonNull Icon icon,
2003             int userId,
2004             @NonNull IAddTileResultCallback callback
2005     ) {
2006         int callingUid = Binder.getCallingUid();
2007         String packageName = componentName.getPackageName();
2008 
2009         // Check calling user can act on behalf of current user
2010         mActivityManagerInternal.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
2011                 false, ActivityManagerInternal.ALLOW_NON_FULL, "requestAddTile", packageName);
2012 
2013         // Check calling uid matches package
2014         checkCallingUidPackage(packageName, callingUid, userId);
2015 
2016         int currentUser = mActivityManagerInternal.getCurrentUserId();
2017 
2018         // Check current user
2019         if (userId != currentUser) {
2020             try {
2021                 callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER);
2022             } catch (RemoteException e) {
2023                 Slog.e(TAG, "requestAddTile", e);
2024             }
2025             return;
2026         }
2027 
2028         // We've checked that the package, component name and uid all match.
2029         ResolveInfo r = isComponentValidTileService(componentName, userId);
2030         if (r == null || !r.serviceInfo.exported) {
2031             try {
2032                 callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_BAD_COMPONENT);
2033             } catch (RemoteException e) {
2034                 Slog.e(TAG, "requestAddTile", e);
2035             }
2036             return;
2037         }
2038 
2039         final int procState = mActivityManagerInternal.getUidProcessState(callingUid);
2040         if (ActivityManager.RunningAppProcessInfo.procStateToImportance(procState)
2041                 != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
2042             try {
2043                 callback.onTileRequest(
2044                         StatusBarManager.TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND);
2045             } catch (RemoteException e) {
2046                 Slog.e(TAG, "requestAddTile", e);
2047             }
2048             return;
2049         }
2050 
2051         synchronized (mCurrentRequestAddTilePackages) {
2052             Long lastTime = mCurrentRequestAddTilePackages.get(packageName);
2053             final long currentTime = System.nanoTime();
2054             if (lastTime != null && currentTime - lastTime < REQUEST_TIME_OUT) {
2055                 try {
2056                     callback.onTileRequest(
2057                             StatusBarManager.TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS);
2058                 } catch (RemoteException e) {
2059                     Slog.e(TAG, "requestAddTile", e);
2060                 }
2061                 return;
2062             } else {
2063                 if (lastTime != null) {
2064                     cancelRequestAddTileInternal(packageName);
2065                 }
2066             }
2067 
2068             mCurrentRequestAddTilePackages.put(packageName, currentTime);
2069         }
2070 
2071         if (mTileRequestTracker.shouldBeDenied(userId, componentName)) {
2072             if (clearTileAddRequest(packageName)) {
2073                 try {
2074                     callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED);
2075                 } catch (RemoteException e) {
2076                     Slog.e(TAG, "requestAddTile - callback", e);
2077                 }
2078             }
2079             return;
2080         }
2081 
2082         IAddTileResultCallback proxyCallback = new IAddTileResultCallback.Stub() {
2083             @Override
2084             public void onTileRequest(int i) {
2085                 if (i == StatusBarManager.TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED) {
2086                     i = StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED;
2087                 } else if (i == StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED) {
2088                     mTileRequestTracker.addDenial(userId, componentName);
2089                 } else if (i == StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ADDED) {
2090                     mTileRequestTracker.resetRequests(userId, componentName);
2091                 }
2092                 if (clearTileAddRequest(packageName)) {
2093                     try {
2094                         callback.onTileRequest(i);
2095                     } catch (RemoteException e) {
2096                         Slog.e(TAG, "requestAddTile - callback", e);
2097                     }
2098                 }
2099             }
2100         };
2101 
2102         CharSequence appName = r.serviceInfo.applicationInfo
2103                 .loadLabel(mContext.getPackageManager());
2104         IStatusBar bar = mBar;
2105         if (bar != null) {
2106             try {
2107                 bar.requestAddTile(componentName, appName, label, icon, proxyCallback);
2108                 return;
2109             } catch (RemoteException e) {
2110                 Slog.e(TAG, "requestAddTile", e);
2111             }
2112         }
2113         clearTileAddRequest(packageName);
2114         try {
2115             callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE);
2116         } catch (RemoteException e) {
2117             Slog.e(TAG, "requestAddTile", e);
2118         }
2119     }
2120 
2121     @Override
cancelRequestAddTile(@onNull String packageName)2122     public void cancelRequestAddTile(@NonNull String packageName) {
2123         enforceStatusBar();
2124         cancelRequestAddTileInternal(packageName);
2125     }
2126 
cancelRequestAddTileInternal(String packageName)2127     private void cancelRequestAddTileInternal(String packageName) {
2128         clearTileAddRequest(packageName);
2129         IStatusBar bar = mBar;
2130         if (bar != null) {
2131             try {
2132                 bar.cancelRequestAddTile(packageName);
2133             } catch (RemoteException e) {
2134                 Slog.e(TAG, "requestAddTile", e);
2135             }
2136         }
2137     }
2138 
clearTileAddRequest(String packageName)2139     private boolean clearTileAddRequest(String packageName) {
2140         synchronized (mCurrentRequestAddTilePackages) {
2141             return mCurrentRequestAddTilePackages.remove(packageName) != null;
2142         }
2143     }
2144 
2145     @Override
onSessionStarted(@essionFlags int sessionType, InstanceId instance)2146     public void onSessionStarted(@SessionFlags int sessionType, InstanceId instance) {
2147         mSessionMonitor.onSessionStarted(sessionType, instance);
2148     }
2149 
2150     @Override
onSessionEnded(@essionFlags int sessionType, InstanceId instance)2151     public void onSessionEnded(@SessionFlags int sessionType, InstanceId instance) {
2152         mSessionMonitor.onSessionEnded(sessionType, instance);
2153     }
2154 
2155     @Override
registerSessionListener(@essionFlags int sessionFlags, ISessionListener listener)2156     public void registerSessionListener(@SessionFlags int sessionFlags,
2157             ISessionListener listener) {
2158         mSessionMonitor.registerSessionListener(sessionFlags, listener);
2159     }
2160 
2161     @Override
unregisterSessionListener(@essionFlags int sessionFlags, ISessionListener listener)2162     public void unregisterSessionListener(@SessionFlags int sessionFlags,
2163             ISessionListener listener) {
2164         mSessionMonitor.unregisterSessionListener(sessionFlags, listener);
2165     }
2166 
getStatusBarIcons()2167     public String[] getStatusBarIcons() {
2168         return mContext.getResources().getStringArray(R.array.config_statusBarIcons);
2169     }
2170 
2171     /**
2172      * Sets or removes the navigation bar mode.
2173      *
2174      * @param navBarMode the mode of the navigation bar to be set.
2175      */
setNavBarMode(@avBarMode int navBarMode)2176     public void setNavBarMode(@NavBarMode int navBarMode) {
2177         enforceStatusBar();
2178         if (navBarMode != NAV_BAR_MODE_DEFAULT && navBarMode != NAV_BAR_MODE_KIDS) {
2179             throw new IllegalArgumentException("Supplied navBarMode not supported: " + navBarMode);
2180         }
2181 
2182         final int userId = mCurrentUserId;
2183         final int callingUserId = UserHandle.getUserId(Binder.getCallingUid());
2184         if (mCurrentUserId != callingUserId && !doesCallerHoldInteractAcrossUserPermission()) {
2185             throw new SecurityException("Calling user id: " + callingUserId
2186                     + ", cannot call on behalf of current user id: " + mCurrentUserId + ".");
2187         }
2188         final long userIdentity = Binder.clearCallingIdentity();
2189         try {
2190             Settings.Secure.putIntForUser(mContext.getContentResolver(),
2191                     Settings.Secure.NAV_BAR_KIDS_MODE, navBarMode, userId);
2192             Settings.Secure.putIntForUser(mContext.getContentResolver(),
2193                     Settings.Secure.NAV_BAR_FORCE_VISIBLE, navBarMode, userId);
2194 
2195             IOverlayManager overlayManager = getOverlayManager();
2196             if (overlayManager != null && navBarMode == NAV_BAR_MODE_KIDS
2197                     && isPackageSupported(NAV_BAR_MODE_3BUTTON_OVERLAY)) {
2198                 overlayManager.setEnabledExclusiveInCategory(NAV_BAR_MODE_3BUTTON_OVERLAY, userId);
2199             }
2200         } catch (RemoteException e) {
2201             throw e.rethrowFromSystemServer();
2202         } finally {
2203             Binder.restoreCallingIdentity(userIdentity);
2204         }
2205     }
2206 
2207     /**
2208      * Gets the navigation bar mode. Returns default value if no mode is set.
2209      *
2210      * @hide
2211      */
getNavBarMode()2212     public @NavBarMode int getNavBarMode() {
2213         enforceStatusBar();
2214 
2215         int navBarKidsMode = NAV_BAR_MODE_DEFAULT;
2216         final int userId = mCurrentUserId;
2217         final long userIdentity = Binder.clearCallingIdentity();
2218         try {
2219             navBarKidsMode = Settings.Secure.getIntForUser(mContext.getContentResolver(),
2220                     Settings.Secure.NAV_BAR_KIDS_MODE, userId);
2221         } catch (Settings.SettingNotFoundException ex) {
2222             return navBarKidsMode;
2223         } finally {
2224             Binder.restoreCallingIdentity(userIdentity);
2225         }
2226         return navBarKidsMode;
2227     }
2228 
isPackageSupported(String packageName)2229     private boolean isPackageSupported(String packageName) {
2230         if (packageName == null) {
2231             return false;
2232         }
2233         try {
2234             return mContext.getPackageManager().getPackageInfo(packageName,
2235                     PackageManager.PackageInfoFlags.of(0)) != null;
2236         } catch (PackageManager.NameNotFoundException ignored) {
2237             if (SPEW) {
2238                 Slog.d(TAG, "Package not found: " + packageName);
2239             }
2240         }
2241         return false;
2242     }
2243 
2244     /**
2245      * Notifies the system of a new media tap-to-transfer state for the *sender* device. See
2246      * {@link StatusBarManager.updateMediaTapToTransferSenderDisplay} for more information.
2247      *
2248      * @param undoCallback a callback that will be triggered if the user elects to undo a media
2249      *                     transfer.
2250      *
2251      * Requires the caller to have the {@link android.Manifest.permission.MEDIA_CONTENT_CONTROL}
2252      * permission.
2253      */
2254     @Override
updateMediaTapToTransferSenderDisplay( @tatusBarManager.MediaTransferSenderState int displayState, @NonNull MediaRoute2Info routeInfo, @Nullable IUndoMediaTransferCallback undoCallback )2255     public void updateMediaTapToTransferSenderDisplay(
2256             @StatusBarManager.MediaTransferSenderState int displayState,
2257             @NonNull MediaRoute2Info routeInfo,
2258             @Nullable IUndoMediaTransferCallback undoCallback
2259     ) {
2260         enforceMediaContentControl();
2261         IStatusBar bar = mBar;
2262         if (bar != null) {
2263             try {
2264                 bar.updateMediaTapToTransferSenderDisplay(displayState, routeInfo, undoCallback);
2265             } catch (RemoteException e) {
2266                 Slog.e(TAG, "updateMediaTapToTransferSenderDisplay", e);
2267             }
2268         }
2269     }
2270 
2271     /**
2272      * Notifies the system of a new media tap-to-transfer state for the *receiver* device. See
2273      * {@link StatusBarManager.updateMediaTapToTransferReceiverDisplay} for more information.
2274      *
2275      * Requires the caller to have the {@link android.Manifest.permission.MEDIA_CONTENT_CONTROL}
2276      * permission.
2277      */
2278     @Override
updateMediaTapToTransferReceiverDisplay( @tatusBarManager.MediaTransferReceiverState int displayState, MediaRoute2Info routeInfo, @Nullable Icon appIcon, @Nullable CharSequence appName)2279     public void updateMediaTapToTransferReceiverDisplay(
2280             @StatusBarManager.MediaTransferReceiverState int displayState,
2281             MediaRoute2Info routeInfo,
2282             @Nullable Icon appIcon,
2283             @Nullable CharSequence appName) {
2284         enforceMediaContentControl();
2285         IStatusBar bar = mBar;
2286         if (bar != null) {
2287             try {
2288                 bar.updateMediaTapToTransferReceiverDisplay(
2289                         displayState, routeInfo, appIcon, appName);
2290             } catch (RemoteException e) {
2291                 Slog.e(TAG, "updateMediaTapToTransferReceiverDisplay", e);
2292             }
2293         }
2294     }
2295 
2296     /**
2297      * Registers a provider that gives information about nearby devices that are able to play media.
2298      * See {@link StatusBarmanager.registerNearbyMediaDevicesProvider}.
2299      *
2300      * Requires the caller to have the {@link android.Manifest.permission.MEDIA_CONTENT_CONTROL}
2301      * permission.
2302      *
2303      * @param provider the nearby device information provider to register
2304      *
2305      * @hide
2306      */
2307     @Override
registerNearbyMediaDevicesProvider( @onNull INearbyMediaDevicesProvider provider )2308     public void registerNearbyMediaDevicesProvider(
2309             @NonNull INearbyMediaDevicesProvider provider
2310     ) {
2311         enforceMediaContentControl();
2312         IStatusBar bar = mBar;
2313         if (bar != null) {
2314             try {
2315                 bar.registerNearbyMediaDevicesProvider(provider);
2316             } catch (RemoteException e) {
2317                 Slog.e(TAG, "registerNearbyMediaDevicesProvider", e);
2318             }
2319         }
2320     }
2321 
2322     /**
2323      * Unregisters a provider that gives information about nearby devices that are able to play
2324      * media. See {@link StatusBarmanager.unregisterNearbyMediaDevicesProvider}.
2325      *
2326      * Requires the caller to have the {@link android.Manifest.permission.MEDIA_CONTENT_CONTROL}
2327      * permission.
2328      *
2329      * @param provider the nearby device information provider to unregister
2330      *
2331      * @hide
2332      */
2333     @Override
unregisterNearbyMediaDevicesProvider( @onNull INearbyMediaDevicesProvider provider )2334     public void unregisterNearbyMediaDevicesProvider(
2335             @NonNull INearbyMediaDevicesProvider provider
2336     ) {
2337         enforceMediaContentControl();
2338         IStatusBar bar = mBar;
2339         if (bar != null) {
2340             try {
2341                 bar.unregisterNearbyMediaDevicesProvider(provider);
2342             } catch (RemoteException e) {
2343                 Slog.e(TAG, "unregisterNearbyMediaDevicesProvider", e);
2344             }
2345         }
2346     }
2347 
2348     @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)
2349     @Override
showRearDisplayDialog(int currentState)2350     public void showRearDisplayDialog(int currentState) {
2351         enforceControlDeviceStatePermission();
2352         IStatusBar bar = mBar;
2353         if (bar != null) {
2354             try {
2355                 bar.showRearDisplayDialog(currentState);
2356             } catch (RemoteException e) {
2357                 Slog.e(TAG, "showRearDisplayDialog", e);
2358             }
2359         }
2360     }
2361 
2362     /** @hide */
passThroughShellCommand(String[] args, FileDescriptor fd)2363     public void passThroughShellCommand(String[] args, FileDescriptor fd) {
2364         enforceStatusBarOrShell();
2365         if (mBar == null)  return;
2366 
2367         try (TransferPipe tp = new TransferPipe()) {
2368             // Sending the command to the remote, which needs to execute async to avoid blocking
2369             // See Binder#dumpAsync() for inspiration
2370             tp.setBufferPrefix("  ");
2371             mBar.passThroughShellCommand(args, tp.getWriteFd());
2372             // Times out after 5s
2373             tp.go(fd);
2374         } catch (Throwable t) {
2375             Slog.e(TAG, "Error sending command to IStatusBar", t);
2376         }
2377     }
2378 
2379     // ================================================================================
2380     // Can be called from any thread
2381     // ================================================================================
2382 
2383     // lock on mDisableRecords
manageDisableListLocked(int userId, int what, IBinder token, String pkg, int which)2384     void manageDisableListLocked(int userId, int what, IBinder token, String pkg, int which) {
2385         if (SPEW) {
2386             Slog.d(TAG, "manageDisableList userId=" + userId
2387                     + " what=0x" + Integer.toHexString(what) + " pkg=" + pkg);
2388         }
2389 
2390         // Find matching record, if any
2391         Pair<Integer, DisableRecord> match = findMatchingRecordLocked(token, userId);
2392         int i = match.first;
2393         DisableRecord record = match.second;
2394 
2395         // Remove record if binder is already dead
2396         if (!token.isBinderAlive()) {
2397             if (record != null) {
2398                 mDisableRecords.remove(i);
2399                 record.token.unlinkToDeath(record, 0);
2400             }
2401             return;
2402         }
2403 
2404         // Update existing record
2405         if (record != null) {
2406             record.setFlags(what, which, pkg);
2407             if (record.isEmpty()) {
2408                 mDisableRecords.remove(i);
2409                 record.token.unlinkToDeath(record, 0);
2410             }
2411             return;
2412         }
2413 
2414         // Record doesn't exist, so we create a new one
2415         record = new DisableRecord(userId, token);
2416         record.setFlags(what, which, pkg);
2417         mDisableRecords.add(record);
2418     }
2419 
2420     @Nullable
2421     @GuardedBy("mLock")
findMatchingRecordLocked(IBinder token, int userId)2422     private Pair<Integer, DisableRecord> findMatchingRecordLocked(IBinder token, int userId) {
2423         final int numRecords = mDisableRecords.size();
2424         DisableRecord record = null;
2425         int i;
2426         for (i = 0; i < numRecords; i++) {
2427             DisableRecord r = mDisableRecords.get(i);
2428             if (r.token == token && r.userId == userId) {
2429                 record = r;
2430                 break;
2431             }
2432         }
2433 
2434         return new Pair<Integer, DisableRecord>(i, record);
2435     }
2436 
2437     // lock on mDisableRecords
gatherDisableActionsLocked(int userId, int which)2438     int gatherDisableActionsLocked(int userId, int which) {
2439         final int N = mDisableRecords.size();
2440         // gather the new net flags
2441         int net = 0;
2442         for (int i=0; i<N; i++) {
2443             final DisableRecord rec = mDisableRecords.get(i);
2444             if (rec.userId == userId) {
2445                 net |= rec.getFlags(which);
2446             }
2447         }
2448         return net;
2449     }
2450 
2451     // ================================================================================
2452     // Always called from UI thread
2453     // ================================================================================
2454 
dump(FileDescriptor fd, PrintWriter pw, String[] args)2455     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2456         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
2457         boolean proto = false;
2458         for (int i = 0; i < args.length; i++) {
2459             if ("--proto".equals(args[i])) {
2460                 proto = true;
2461             }
2462         }
2463         if (proto) {
2464             if (mBar == null)  return;
2465             try (TransferPipe tp = new TransferPipe()) {
2466                 // Sending the command to the remote, which needs to execute async to avoid blocking
2467                 // See Binder#dumpAsync() for inspiration
2468                 mBar.dumpProto(args, tp.getWriteFd());
2469                 // Times out after 5s
2470                 tp.go(fd);
2471             } catch (Throwable t) {
2472                 Slog.e(TAG, "Error sending command to IStatusBar", t);
2473             }
2474             return;
2475         }
2476 
2477         synchronized (mLock) {
2478             for (int i = 0; i < mDisplayUiState.size(); i++) {
2479                 final int key = mDisplayUiState.keyAt(i);
2480                 final UiState state = mDisplayUiState.get(key);
2481                 pw.println("  displayId=" + key);
2482                 pw.println("    mDisabled1=0x" + Integer.toHexString(state.getDisabled1()));
2483                 pw.println("    mDisabled2=0x" + Integer.toHexString(state.getDisabled2()));
2484             }
2485             final int N = mDisableRecords.size();
2486             pw.println("  mDisableRecords.size=" + N);
2487             for (int i=0; i<N; i++) {
2488                 DisableRecord tok = mDisableRecords.get(i);
2489                 pw.println("    [" + i + "] " + tok);
2490             }
2491             pw.println("  mCurrentUserId=" + mCurrentUserId);
2492             pw.println("  mIcons=");
2493             for (String slot : mIcons.keySet()) {
2494                 pw.println("    ");
2495                 pw.print(slot);
2496                 pw.print(" -> ");
2497                 final StatusBarIcon icon = mIcons.get(slot);
2498                 pw.print(icon);
2499                 if (!TextUtils.isEmpty(icon.contentDescription)) {
2500                     pw.print(" \"");
2501                     pw.print(icon.contentDescription);
2502                     pw.print("\"");
2503                 }
2504                 pw.println();
2505             }
2506             ArrayList<String> requests;
2507             synchronized (mCurrentRequestAddTilePackages) {
2508                 requests = new ArrayList<>(mCurrentRequestAddTilePackages.keySet());
2509             }
2510             pw.println("  mCurrentRequestAddTilePackages=[");
2511             final int reqN = requests.size();
2512             for (int i = 0; i < reqN; i++) {
2513                 pw.println("    " + requests.get(i) + ",");
2514             }
2515             pw.println("  ]");
2516             IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
2517             mTileRequestTracker.dump(fd, ipw.increaseIndent(), args);
2518         }
2519     }
2520 
getUiContext()2521     private static final Context getUiContext() {
2522         return ActivityThread.currentActivityThread().getSystemUiContext();
2523     }
2524 }
2525