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