• 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 android.app;
18 
19 import android.Manifest;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresPermission;
24 import android.annotation.SystemApi;
25 import android.annotation.SystemService;
26 import android.annotation.TestApi;
27 import android.app.compat.CompatChanges;
28 import android.compat.annotation.ChangeId;
29 import android.compat.annotation.EnabledSince;
30 import android.compat.annotation.UnsupportedAppUsage;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.graphics.drawable.Icon;
34 import android.media.INearbyMediaDevicesProvider;
35 import android.media.INearbyMediaDevicesUpdateCallback;
36 import android.media.MediaRoute2Info;
37 import android.media.NearbyDevice;
38 import android.media.NearbyMediaDevicesProvider;
39 import android.os.Binder;
40 import android.os.Build;
41 import android.os.Bundle;
42 import android.os.IBinder;
43 import android.os.RemoteException;
44 import android.os.ServiceManager;
45 import android.os.UserHandle;
46 import android.util.Pair;
47 import android.util.Slog;
48 import android.view.View;
49 
50 import com.android.internal.statusbar.IAddTileResultCallback;
51 import com.android.internal.statusbar.IStatusBarService;
52 import com.android.internal.statusbar.IUndoMediaTransferCallback;
53 import com.android.internal.statusbar.NotificationVisibility;
54 
55 import java.lang.annotation.Retention;
56 import java.lang.annotation.RetentionPolicy;
57 import java.util.HashMap;
58 import java.util.List;
59 import java.util.Map;
60 import java.util.Objects;
61 import java.util.Set;
62 import java.util.concurrent.Executor;
63 import java.util.function.Consumer;
64 
65 /**
66  * Allows an app to control the status bar.
67  */
68 @SystemService(Context.STATUS_BAR_SERVICE)
69 public class StatusBarManager {
70     // LINT.IfChange
71     /** @hide */
72     public static final int DISABLE_EXPAND = View.STATUS_BAR_DISABLE_EXPAND;
73     /** @hide */
74     public static final int DISABLE_NOTIFICATION_ICONS = View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS;
75     /** @hide */
76     public static final int DISABLE_NOTIFICATION_ALERTS
77             = View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS;
78 
79     /** @hide */
80     @Deprecated
81     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
82     public static final int DISABLE_NOTIFICATION_TICKER
83             = View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER;
84     /** @hide */
85     public static final int DISABLE_SYSTEM_INFO = View.STATUS_BAR_DISABLE_SYSTEM_INFO;
86     /** @hide */
87     public static final int DISABLE_HOME = View.STATUS_BAR_DISABLE_HOME;
88     /** @hide */
89     public static final int DISABLE_RECENT = View.STATUS_BAR_DISABLE_RECENT;
90     /** @hide */
91     public static final int DISABLE_BACK = View.STATUS_BAR_DISABLE_BACK;
92     /** @hide */
93     public static final int DISABLE_CLOCK = View.STATUS_BAR_DISABLE_CLOCK;
94     /** @hide */
95     public static final int DISABLE_SEARCH = View.STATUS_BAR_DISABLE_SEARCH;
96 
97     /** @hide */
98     public static final int DISABLE_ONGOING_CALL_CHIP = View.STATUS_BAR_DISABLE_ONGOING_CALL_CHIP;
99 
100     /** @hide */
101     @Deprecated
102     public static final int DISABLE_NAVIGATION =
103             View.STATUS_BAR_DISABLE_HOME | View.STATUS_BAR_DISABLE_RECENT;
104 
105     /** @hide */
106     public static final int DISABLE_NONE = 0x00000000;
107 
108     /** @hide */
109     public static final int DISABLE_MASK = DISABLE_EXPAND | DISABLE_NOTIFICATION_ICONS
110             | DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER
111             | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK
112             | DISABLE_SEARCH | DISABLE_ONGOING_CALL_CHIP;
113 
114     /** @hide */
115     @IntDef(flag = true, prefix = {"DISABLE_"}, value = {
116             DISABLE_NONE,
117             DISABLE_EXPAND,
118             DISABLE_NOTIFICATION_ICONS,
119             DISABLE_NOTIFICATION_ALERTS,
120             DISABLE_NOTIFICATION_TICKER,
121             DISABLE_SYSTEM_INFO,
122             DISABLE_HOME,
123             DISABLE_RECENT,
124             DISABLE_BACK,
125             DISABLE_CLOCK,
126             DISABLE_SEARCH,
127             DISABLE_ONGOING_CALL_CHIP
128     })
129     @Retention(RetentionPolicy.SOURCE)
130     public @interface DisableFlags {}
131 
132     /**
133      * Flag to disable quick settings.
134      *
135      * Setting this flag disables quick settings completely, but does not disable expanding the
136      * notification shade.
137      */
138     /** @hide */
139     public static final int DISABLE2_QUICK_SETTINGS = 1;
140     /** @hide */
141     public static final int DISABLE2_SYSTEM_ICONS = 1 << 1;
142     /** @hide */
143     public static final int DISABLE2_NOTIFICATION_SHADE = 1 << 2;
144     /** @hide */
145     public static final int DISABLE2_GLOBAL_ACTIONS = 1 << 3;
146     /** @hide */
147     public static final int DISABLE2_ROTATE_SUGGESTIONS = 1 << 4;
148 
149     /** @hide */
150     public static final int DISABLE2_NONE = 0x00000000;
151 
152     /** @hide */
153     public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS
154             | DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS | DISABLE2_ROTATE_SUGGESTIONS;
155 
156     /** @hide */
157     @IntDef(flag = true, prefix = { "DISABLE2_" }, value = {
158             DISABLE2_NONE,
159             DISABLE2_MASK,
160             DISABLE2_QUICK_SETTINGS,
161             DISABLE2_SYSTEM_ICONS,
162             DISABLE2_NOTIFICATION_SHADE,
163             DISABLE2_GLOBAL_ACTIONS,
164             DISABLE2_ROTATE_SUGGESTIONS
165     })
166     @Retention(RetentionPolicy.SOURCE)
167     public @interface Disable2Flags {}
168     // LINT.ThenChange(frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt)
169 
170     /**
171      * Default disable flags for setup
172      *
173      * @hide
174      */
175     public static final int DEFAULT_SETUP_DISABLE_FLAGS = DISABLE_NOTIFICATION_ALERTS
176             | DISABLE_HOME | DISABLE_EXPAND | DISABLE_RECENT | DISABLE_CLOCK | DISABLE_SEARCH;
177 
178     /**
179      * Default disable2 flags for setup
180      *
181      * @hide
182      */
183     public static final int DEFAULT_SETUP_DISABLE2_FLAGS = DISABLE2_NONE;
184 
185     /**
186      * disable flags to be applied when the device is sim-locked.
187      */
188     private static final int DEFAULT_SIM_LOCKED_DISABLED_FLAGS = DISABLE_EXPAND;
189 
190     /** @hide */
191     public static final int NAVIGATION_HINT_BACK_ALT      = 1 << 0;
192     /** @hide */
193     public static final int NAVIGATION_HINT_IME_SHOWN     = 1 << 1;
194     /** @hide */
195     public static final int NAVIGATION_HINT_IME_SWITCHER_SHOWN = 1 << 2;
196 
197     /** @hide */
198     public static final int WINDOW_STATUS_BAR = 1;
199     /** @hide */
200     public static final int WINDOW_NAVIGATION_BAR = 2;
201 
202     /** @hide */
203     @IntDef(flag = true, prefix = { "WINDOW_" }, value = {
204         WINDOW_STATUS_BAR,
205         WINDOW_NAVIGATION_BAR
206     })
207     @Retention(RetentionPolicy.SOURCE)
208     public @interface WindowType {}
209 
210     /** @hide */
211     public static final int WINDOW_STATE_SHOWING = 0;
212     /** @hide */
213     public static final int WINDOW_STATE_HIDING = 1;
214     /** @hide */
215     public static final int WINDOW_STATE_HIDDEN = 2;
216 
217     /** @hide */
218     @IntDef(flag = true, prefix = { "WINDOW_STATE_" }, value = {
219             WINDOW_STATE_SHOWING,
220             WINDOW_STATE_HIDING,
221             WINDOW_STATE_HIDDEN
222     })
223     @Retention(RetentionPolicy.SOURCE)
224     public @interface WindowVisibleState {}
225 
226     /** @hide */
227     public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0;
228     /** @hide */
229     public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1;
230     /** @hide */
231     public static final int CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = 2;
232     /** @hide */
233     public static final int CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE = 3;
234 
235     /**
236      * Session flag for {@link #registerSessionListener} indicating the listener
237      * is interested in sessions on the keygaurd.
238      * Keyguard Session Boundaries:
239      *     START_SESSION: device starts going to sleep OR the keyguard is newly shown
240      *     END_SESSION: device starts going to sleep OR keyguard is no longer showing
241      * @hide
242      */
243     public static final int SESSION_KEYGUARD = 1 << 0;
244 
245     /**
246      * Session flag for {@link #registerSessionListener} indicating the current session
247      * is interested in session on the biometric prompt.
248      * @hide
249      */
250     public static final int SESSION_BIOMETRIC_PROMPT = 1 << 1;
251 
252     /** @hide */
253     public static final Set<Integer> ALL_SESSIONS = Set.of(
254             SESSION_KEYGUARD,
255             SESSION_BIOMETRIC_PROMPT
256     );
257 
258     /** @hide */
259     @Retention(RetentionPolicy.SOURCE)
260     @IntDef(flag = true, prefix = { "SESSION_KEYGUARD" }, value = {
261             SESSION_KEYGUARD,
262             SESSION_BIOMETRIC_PROMPT,
263     })
264     public @interface SessionFlags {}
265 
266     /**
267      * Response indicating that the tile was not added.
268      */
269     public static final int TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED = 0;
270     /**
271      * Response indicating that the tile was already added and the user was not prompted.
272      */
273     public static final int TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED = 1;
274     /**
275      * Response indicating that the tile was added.
276      */
277     public static final int TILE_ADD_REQUEST_RESULT_TILE_ADDED = 2;
278     /** @hide */
279     public static final int TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED = 3;
280 
281     /**
282      * Values greater or equal to this value indicate an error in the request.
283      */
284     private static final int TILE_ADD_REQUEST_FIRST_ERROR_CODE = 1000;
285 
286     /**
287      * Indicates that this package does not match that of the
288      * {@link android.service.quicksettings.TileService}.
289      */
290     public static final int TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE =
291             TILE_ADD_REQUEST_FIRST_ERROR_CODE;
292     /**
293      * Indicates that there's a request in progress for this package.
294      */
295     public static final int TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS =
296             TILE_ADD_REQUEST_FIRST_ERROR_CODE + 1;
297     /**
298      * Indicates that the component does not match an enabled exported
299      * {@link android.service.quicksettings.TileService} for the current user.
300      */
301     public static final int TILE_ADD_REQUEST_ERROR_BAD_COMPONENT =
302             TILE_ADD_REQUEST_FIRST_ERROR_CODE + 2;
303     /**
304      * Indicates that the user is not the current user.
305      */
306     public static final int TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER =
307             TILE_ADD_REQUEST_FIRST_ERROR_CODE + 3;
308     /**
309      * Indicates that the requesting application is not in the foreground.
310      */
311     public static final int TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND =
312             TILE_ADD_REQUEST_FIRST_ERROR_CODE + 4;
313     /**
314      * The request could not be processed because no fulfilling service was found. This could be
315      * a temporary issue (for example, SystemUI has crashed).
316      */
317     public static final int TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE =
318             TILE_ADD_REQUEST_FIRST_ERROR_CODE + 5;
319 
320     /** @hide */
321     @IntDef(prefix = {"TILE_ADD_REQUEST"}, value = {
322             TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED,
323             TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED,
324             TILE_ADD_REQUEST_RESULT_TILE_ADDED,
325             TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE,
326             TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS,
327             TILE_ADD_REQUEST_ERROR_BAD_COMPONENT,
328             TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER,
329             TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND,
330             TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE
331     })
332     @Retention(RetentionPolicy.SOURCE)
333     public @interface RequestResult {}
334 
335     /**
336      * Constant for {@link #setNavBarMode(int)} indicating the default navbar mode.
337      *
338      * @hide
339      */
340     @SystemApi
341     public static final int NAV_BAR_MODE_DEFAULT = 0;
342 
343     /**
344      * Constant for {@link #setNavBarMode(int)} indicating kids navbar mode.
345      *
346      * <p>When used, back and home icons will change drawables and layout, recents will be hidden,
347      * and enables the setting to force navbar visible, even when apps are in immersive mode.
348      *
349      * @hide
350      */
351     @SystemApi
352     public static final int NAV_BAR_MODE_KIDS = 1;
353 
354     /** @hide */
355     @IntDef(prefix = {"NAV_BAR_MODE_"}, value = {
356             NAV_BAR_MODE_DEFAULT,
357             NAV_BAR_MODE_KIDS
358     })
359     @Retention(RetentionPolicy.SOURCE)
360     public @interface NavBarMode {}
361 
362     /**
363      * State indicating that this sender device is close to a receiver device, so the user can
364      * potentially *start* a cast to the receiver device if the user moves their device a bit
365      * closer.
366      * <p>
367      * Important notes:
368      * <ul>
369      *     <li>This state represents that the device is close enough to inform the user that
370      *     transferring is an option, but the device is *not* close enough to actually initiate a
371      *     transfer yet.</li>
372      *     <li>This state is for *starting* a cast. It should be used when this device is currently
373      *     playing media locally and the media should be transferred to be played on the receiver
374      *     device instead.</li>
375      * </ul>
376      *
377      * @hide
378      */
379     @SystemApi
380     public static final int MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST = 0;
381 
382     /**
383      * State indicating that this sender device is close to a receiver device, so the user can
384      * potentially *end* a cast on the receiver device if the user moves this device a bit closer.
385      * <p>
386      * Important notes:
387      * <ul>
388      *     <li>This state represents that the device is close enough to inform the user that
389      *     transferring is an option, but the device is *not* close enough to actually initiate a
390      *     transfer yet.</li>
391      *     <li>This state is for *ending* a cast. It should be used when media is currently being
392      *     played on the receiver device and the media should be transferred to play locally
393      *     instead.</li>
394      * </ul>
395      *
396      * @hide
397      */
398     @SystemApi
399     public static final int MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST = 1;
400 
401     /**
402      * State indicating that a media transfer from this sender device to a receiver device has been
403      * started.
404      * <p>
405      * Important note: This state is for *starting* a cast. It should be used when this device is
406      * currently playing media locally and the media has started being transferred to the receiver
407      * device instead.
408      *
409      * @hide
410      */
411     @SystemApi
412     public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED = 2;
413 
414     /**
415      * State indicating that a media transfer from the receiver and back to this sender device
416      * has been started.
417      * <p>
418      * Important note: This state is for *ending* a cast. It should be used when media is currently
419      * being played on the receiver device and the media has started being transferred to play
420      * locally instead.
421      *
422      * @hide
423      */
424     @SystemApi
425     public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED = 3;
426 
427     /**
428      * State indicating that a media transfer from this sender device to a receiver device has
429      * finished successfully.
430      * <p>
431      * Important note: This state is for *starting* a cast. It should be used when this device had
432      * previously been playing media locally and the media has successfully been transferred to the
433      * receiver device instead.
434      *
435      * @hide
436      */
437     @SystemApi
438     public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED = 4;
439 
440     /**
441      * State indicating that a media transfer from the receiver and back to this sender device has
442      * finished successfully.
443      * <p>
444      * Important note: This state is for *ending* a cast. It should be used when media was
445      * previously being played on the receiver device and has been successfully transferred to play
446      * locally on this device instead.
447      *
448      * @hide
449      */
450     @SystemApi
451     public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED = 5;
452 
453     /**
454      * State indicating that the attempted transfer to the receiver device has failed.
455      *
456      * @hide
457      */
458     @SystemApi
459     public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED = 6;
460 
461     /**
462      * State indicating that the attempted transfer back to this device has failed.
463      *
464      * @hide
465      */
466     @SystemApi
467     public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED = 7;
468 
469     /**
470      * State indicating that this sender device is no longer close to the receiver device.
471      *
472      * @hide
473      */
474     @SystemApi
475     public static final int MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER = 8;
476 
477     /** @hide */
478     @IntDef(prefix = {"MEDIA_TRANSFER_SENDER_STATE_"}, value = {
479             MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
480             MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
481             MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
482             MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
483             MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
484             MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
485             MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
486             MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED,
487             MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
488     })
489     @Retention(RetentionPolicy.SOURCE)
490     public @interface MediaTransferSenderState {}
491 
492     /**
493      * State indicating that this receiver device is close to a sender device, so the user can
494      * potentially start or end a cast to the receiver device if the user moves the sender device a
495      * bit closer.
496      * <p>
497      * Important note: This state represents that the device is close enough to inform the user that
498      * transferring is an option, but the device is *not* close enough to actually initiate a
499      * transfer yet.
500      *
501      * @hide
502      */
503     @SystemApi
504     public static final int MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER = 0;
505 
506     /**
507      * State indicating that this receiver device is no longer close to the sender device.
508      *
509      * @hide
510      */
511     @SystemApi
512     public static final int MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER = 1;
513 
514     /**
515      * State indicating that media transfer to this receiver device is succeeded.
516      *
517      * @hide
518      */
519     public static final int MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED = 2;
520 
521     /**
522      * State indicating that media transfer to this receiver device is failed.
523      *
524      * @hide
525      */
526     public static final int MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_FAILED = 3;
527 
528     /** @hide */
529     @IntDef(prefix = {"MEDIA_TRANSFER_RECEIVER_STATE_"}, value = {
530             MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
531             MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
532             MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
533             MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_FAILED,
534     })
535     @Retention(RetentionPolicy.SOURCE)
536     public @interface MediaTransferReceiverState {}
537 
538     /**
539      * A map from a provider registered in
540      * {@link #registerNearbyMediaDevicesProvider(NearbyMediaDevicesProvider)} to the wrapper
541      * around the provider that was created internally. We need the wrapper to make the provider
542      * binder-compatible, and we need to store a reference to the wrapper so that when the provider
543      * is un-registered, we un-register the saved wrapper instance.
544      */
545     private final Map<NearbyMediaDevicesProvider, NearbyMediaDevicesProviderWrapper>
546             nearbyMediaDevicesProviderMap = new HashMap<>();
547 
548     /**
549      * Media controls based on {@link android.app.Notification.MediaStyle} notifications will have
550      * actions based on the media session's {@link android.media.session.PlaybackState}, rather than
551      * the notification's actions.
552      *
553      * These actions will be:
554      * - Play/Pause (depending on whether the current state is a playing state)
555      * - Previous (if declared), or a custom action if the slot is not reserved with
556      *   {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV}
557      * - Next (if declared), or a custom action if the slot is not reserved with
558      *   {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT}
559      * - Custom action
560      * - Custom action
561      *
562      * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
563      * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
564      */
565     @ChangeId
566     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
567     private static final long MEDIA_CONTROL_SESSION_ACTIONS = 203800354L;
568 
569     @UnsupportedAppUsage
570     private Context mContext;
571     private IStatusBarService mService;
572     @UnsupportedAppUsage
573     private IBinder mToken = new Binder();
574 
575     @UnsupportedAppUsage
StatusBarManager(Context context)576     StatusBarManager(Context context) {
577         mContext = context;
578     }
579 
580     @UnsupportedAppUsage
getService()581     private synchronized IStatusBarService getService() {
582         if (mService == null) {
583             mService = IStatusBarService.Stub.asInterface(
584                     ServiceManager.getService(Context.STATUS_BAR_SERVICE));
585             if (mService == null) {
586                 Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE");
587             }
588         }
589         return mService;
590     }
591 
592     /**
593      * Disable some features in the status bar.  Pass the bitwise-or of the DISABLE_* flags.
594      * To re-enable everything, pass {@link #DISABLE_NONE}.
595      *
596      * @hide
597      */
598     @UnsupportedAppUsage
disable(int what)599     public void disable(int what) {
600         try {
601             final int userId = Binder.getCallingUserHandle().getIdentifier();
602             final IStatusBarService svc = getService();
603             if (svc != null) {
604                 svc.disableForUser(what, mToken, mContext.getPackageName(), userId);
605             }
606         } catch (RemoteException ex) {
607             throw ex.rethrowFromSystemServer();
608         }
609     }
610 
611     /**
612      * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags.
613      * To re-enable everything, pass {@link #DISABLE_NONE}.
614      *
615      * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
616      *
617      * @hide
618      */
disable2(@isable2Flags int what)619     public void disable2(@Disable2Flags int what) {
620         try {
621             final int userId = Binder.getCallingUserHandle().getIdentifier();
622             final IStatusBarService svc = getService();
623             if (svc != null) {
624                 svc.disable2ForUser(what, mToken, mContext.getPackageName(), userId);
625             }
626         } catch (RemoteException ex) {
627             throw ex.rethrowFromSystemServer();
628         }
629     }
630 
631     /**
632      * Simulate notification click for testing
633      *
634      * @hide
635      */
636     @TestApi
clickNotification(@ullable String key, int rank, int count, boolean visible)637     public void clickNotification(@Nullable String key, int rank, int count, boolean visible) {
638         clickNotificationInternal(key, rank, count, visible);
639     }
640 
clickNotificationInternal(String key, int rank, int count, boolean visible)641     private void clickNotificationInternal(String key, int rank, int count, boolean visible) {
642         try {
643             final IStatusBarService svc = getService();
644             if (svc != null) {
645                 svc.onNotificationClick(key,
646                         NotificationVisibility.obtain(key, rank, count, visible));
647             }
648         } catch (RemoteException ex) {
649             throw ex.rethrowFromSystemServer();
650         }
651     }
652 
653     /**
654      * Simulate notification feedback for testing
655      *
656      * @hide
657      */
658     @TestApi
sendNotificationFeedback(@ullable String key, @Nullable Bundle feedback)659     public void sendNotificationFeedback(@Nullable String key, @Nullable Bundle feedback) {
660         try {
661             final IStatusBarService svc = getService();
662             if (svc != null) {
663                 svc.onNotificationFeedbackReceived(key, feedback);
664             }
665         } catch (RemoteException ex) {
666             throw ex.rethrowFromSystemServer();
667         }
668     }
669 
670     /**
671      * Expand the notifications panel.
672      *
673      * @hide
674      */
675     @UnsupportedAppUsage
676     @TestApi
expandNotificationsPanel()677     public void expandNotificationsPanel() {
678         try {
679             final IStatusBarService svc = getService();
680             if (svc != null) {
681                 svc.expandNotificationsPanel();
682             }
683         } catch (RemoteException ex) {
684             throw ex.rethrowFromSystemServer();
685         }
686     }
687 
688     /**
689      * Collapse the notifications and settings panels.
690      *
691      * Starting in Android {@link Build.VERSION_CODES.S}, apps targeting SDK level {@link
692      * Build.VERSION_CODES.S} or higher will need {@link android.Manifest.permission.STATUS_BAR}
693      * permission to call this API.
694      *
695      * @hide
696      */
697     @RequiresPermission(android.Manifest.permission.STATUS_BAR)
698     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "This operation"
699             + " is not allowed anymore, please see {@link android.content"
700             + ".Intent#ACTION_CLOSE_SYSTEM_DIALOGS} for more details.")
701     @TestApi
collapsePanels()702     public void collapsePanels() {
703 
704         try {
705             final IStatusBarService svc = getService();
706             if (svc != null) {
707                 svc.collapsePanels();
708             }
709         } catch (RemoteException ex) {
710             throw ex.rethrowFromSystemServer();
711         }
712     }
713 
714     /**
715      * Toggles the notification panel.
716      *
717      * @hide
718      */
719     @RequiresPermission(android.Manifest.permission.STATUS_BAR)
720     @TestApi
togglePanel()721     public void togglePanel() {
722         try {
723             final IStatusBarService svc = getService();
724             if (svc != null) {
725                 svc.togglePanel();
726             }
727         } catch (RemoteException ex) {
728             throw ex.rethrowFromSystemServer();
729         }
730     }
731 
732     /**
733      * Sends system keys to the status bar.
734      *
735      * @hide
736      */
737     @RequiresPermission(android.Manifest.permission.STATUS_BAR)
738     @TestApi
handleSystemKey(int key)739     public void handleSystemKey(int key) {
740         try {
741             final IStatusBarService svc = getService();
742             if (svc != null) {
743                 svc.handleSystemKey(key);
744             }
745         } catch (RemoteException ex) {
746             throw ex.rethrowFromSystemServer();
747         }
748     }
749 
750     /**
751      * Expand the settings panel.
752      *
753      * @hide
754      */
755     @UnsupportedAppUsage
expandSettingsPanel()756     public void expandSettingsPanel() {
757         expandSettingsPanel(null);
758     }
759 
760     /**
761      * Expand the settings panel and open a subPanel. If the subpanel is null or does not have a
762      * corresponding tile, the QS panel is simply expanded
763      *
764      * @hide
765      */
766     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
expandSettingsPanel(@ullable String subPanel)767     public void expandSettingsPanel(@Nullable String subPanel) {
768         try {
769             final IStatusBarService svc = getService();
770             if (svc != null) {
771                 svc.expandSettingsPanel(subPanel);
772             }
773         } catch (RemoteException ex) {
774             throw ex.rethrowFromSystemServer();
775         }
776     }
777 
778     /** @hide */
779     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setIcon(String slot, int iconId, int iconLevel, String contentDescription)780     public void setIcon(String slot, int iconId, int iconLevel, String contentDescription) {
781         try {
782             final IStatusBarService svc = getService();
783             if (svc != null) {
784                 svc.setIcon(slot, mContext.getPackageName(), iconId, iconLevel,
785                     contentDescription);
786             }
787         } catch (RemoteException ex) {
788             throw ex.rethrowFromSystemServer();
789         }
790     }
791 
792     /** @hide */
793     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
removeIcon(String slot)794     public void removeIcon(String slot) {
795         try {
796             final IStatusBarService svc = getService();
797             if (svc != null) {
798                 svc.removeIcon(slot);
799             }
800         } catch (RemoteException ex) {
801             throw ex.rethrowFromSystemServer();
802         }
803     }
804 
805     /** @hide */
806     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setIconVisibility(String slot, boolean visible)807     public void setIconVisibility(String slot, boolean visible) {
808         try {
809             final IStatusBarService svc = getService();
810             if (svc != null) {
811                 svc.setIconVisibility(slot, visible);
812             }
813         } catch (RemoteException ex) {
814             throw ex.rethrowFromSystemServer();
815         }
816     }
817 
818     /**
819      * Enable or disable status bar elements (notifications, clock) which are inappropriate during
820      * device setup.
821      *
822      * @param disabled whether to apply or remove the disabled flags
823      *
824      * @hide
825      */
826     @SystemApi
827     @RequiresPermission(android.Manifest.permission.STATUS_BAR)
setDisabledForSetup(boolean disabled)828     public void setDisabledForSetup(boolean disabled) {
829         try {
830             final int userId = Binder.getCallingUserHandle().getIdentifier();
831             final IStatusBarService svc = getService();
832             if (svc != null) {
833                 svc.disableForUser(disabled ? DEFAULT_SETUP_DISABLE_FLAGS : DISABLE_NONE,
834                         mToken, mContext.getPackageName(), userId);
835                 svc.disable2ForUser(disabled ? DEFAULT_SETUP_DISABLE2_FLAGS : DISABLE2_NONE,
836                         mToken, mContext.getPackageName(), userId);
837             }
838         } catch (RemoteException ex) {
839             throw ex.rethrowFromSystemServer();
840         }
841     }
842 
843     /**
844      * Enable or disable expansion of the status bar. When the device is SIM-locked, the status
845      * bar should not be expandable.
846      *
847      * @param disabled If {@code true}, the status bar will be set to non-expandable. If
848      *                 {@code false}, re-enables expansion of the status bar.
849      * @hide
850      */
851     @TestApi
852     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
853     @RequiresPermission(android.Manifest.permission.STATUS_BAR)
setExpansionDisabledForSimNetworkLock(boolean disabled)854     public void setExpansionDisabledForSimNetworkLock(boolean disabled) {
855         try {
856             final int userId = Binder.getCallingUserHandle().getIdentifier();
857             final IStatusBarService svc = getService();
858             if (svc != null) {
859                 svc.disableForUser(disabled ? DEFAULT_SIM_LOCKED_DISABLED_FLAGS : DISABLE_NONE,
860                         mToken, mContext.getPackageName(), userId);
861             }
862         } catch (RemoteException ex) {
863             throw ex.rethrowFromSystemServer();
864         }
865     }
866 
867     /**
868      * Get this app's currently requested disabled components
869      *
870      * @return a new DisableInfo
871      *
872      * @hide
873      */
874     @SystemApi
875     @RequiresPermission(android.Manifest.permission.STATUS_BAR)
876     @NonNull
getDisableInfo()877     public DisableInfo getDisableInfo() {
878         try {
879             final int userId = Binder.getCallingUserHandle().getIdentifier();
880             final IStatusBarService svc = getService();
881             int[] flags = new int[] {0, 0};
882             if (svc != null) {
883                 flags = svc.getDisableFlags(mToken, userId);
884             }
885 
886             return new DisableInfo(flags[0], flags[1]);
887         } catch (RemoteException ex) {
888             throw ex.rethrowFromSystemServer();
889         }
890     }
891 
892     /**
893      * Sets an active {@link android.service.quicksettings.TileService} to listening state
894      *
895      * The {@code componentName}'s package must match the calling package.
896      *
897      * @param componentName the tile to set into listening state
898      * @see android.service.quicksettings.TileService#requestListeningState
899      * @hide
900      */
requestTileServiceListeningState(@onNull ComponentName componentName)901     public void requestTileServiceListeningState(@NonNull ComponentName componentName) {
902         Objects.requireNonNull(componentName);
903         try {
904             getService().requestTileServiceListeningState(componentName, mContext.getUserId());
905         } catch (RemoteException ex) {
906             throw ex.rethrowFromSystemServer();
907         }
908     }
909 
910     /**
911      * Request to the user to add a {@link android.service.quicksettings.TileService}
912      * to the set of current QS tiles.
913      * <p>
914      * Calling this will prompt the user to decide whether they want to add the shown
915      * {@link android.service.quicksettings.TileService} to their current tiles. The user can
916      * deny the request and the system can stop processing requests for a given
917      * {@link ComponentName} after a number of requests.
918      * <p>
919      * The request will show to the user information about the tile:
920      * <ul>
921      *     <li>Application name</li>
922      *     <li>Label for the tile</li>
923      *     <li>Icon for the tile</li>
924      * </ul>
925      * <p>
926      * The user for which this will be added is determined from the {@link Context} used to retrieve
927      * this service, and must match the current user. The requesting application must be in the
928      * foreground ({@link ActivityManager.RunningAppProcessInfo#IMPORTANCE_FOREGROUND}
929      * and the {@link android.service.quicksettings.TileService} must be exported.
930      *
931      * Note: the system can choose to auto-deny a request if the user has denied that specific
932      * request (user, ComponentName) enough times before.
933      *
934      * @param tileServiceComponentName {@link ComponentName} of the
935      *        {@link android.service.quicksettings.TileService} for the request.
936      * @param tileLabel label of the tile to show to the user.
937      * @param icon icon to use in the tile shown to the user.
938      * @param resultExecutor an executor to run the callback on
939      * @param resultCallback callback to indicate the {@link RequestResult}.
940      *
941      * @see android.service.quicksettings.TileService
942      */
requestAddTileService( @onNull ComponentName tileServiceComponentName, @NonNull CharSequence tileLabel, @NonNull Icon icon, @NonNull Executor resultExecutor, @NonNull Consumer<Integer> resultCallback )943     public void requestAddTileService(
944             @NonNull ComponentName tileServiceComponentName,
945             @NonNull CharSequence tileLabel,
946             @NonNull Icon icon,
947             @NonNull Executor resultExecutor,
948             @NonNull Consumer<Integer> resultCallback
949     ) {
950         Objects.requireNonNull(tileServiceComponentName);
951         Objects.requireNonNull(tileLabel);
952         Objects.requireNonNull(icon);
953         Objects.requireNonNull(resultExecutor);
954         Objects.requireNonNull(resultCallback);
955         if (!tileServiceComponentName.getPackageName().equals(mContext.getPackageName())) {
956             resultExecutor.execute(
957                     () -> resultCallback.accept(TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE));
958             return;
959         }
960         int userId = mContext.getUserId();
961         RequestResultCallback callbackProxy = new RequestResultCallback(resultExecutor,
962                 resultCallback);
963         IStatusBarService svc = getService();
964         try {
965             svc.requestAddTile(
966                     tileServiceComponentName,
967                     tileLabel,
968                     icon,
969                     userId,
970                     callbackProxy
971             );
972         } catch (RemoteException ex) {
973             ex.rethrowFromSystemServer();
974         }
975     }
976 
977     /**
978      * @hide
979      * @param packageName
980      */
981     @TestApi
cancelRequestAddTile(@onNull String packageName)982     public void cancelRequestAddTile(@NonNull String packageName) {
983         Objects.requireNonNull(packageName);
984         IStatusBarService svc = getService();
985         try {
986             svc.cancelRequestAddTile(packageName);
987         } catch (RemoteException e) {
988             e.rethrowFromSystemServer();
989         }
990     }
991 
992     /**
993      * Sets or removes the navigation bar mode.
994      *
995      * @param navBarMode the mode of the navigation bar to be set.
996      *
997      * @hide
998      */
999     @SystemApi
1000     @RequiresPermission(android.Manifest.permission.STATUS_BAR)
setNavBarMode(@avBarMode int navBarMode)1001     public void setNavBarMode(@NavBarMode int navBarMode) {
1002         if (navBarMode != NAV_BAR_MODE_DEFAULT && navBarMode != NAV_BAR_MODE_KIDS) {
1003             throw new IllegalArgumentException("Supplied navBarMode not supported: " + navBarMode);
1004         }
1005 
1006         try {
1007             final IStatusBarService svc = getService();
1008             if (svc != null) {
1009                 svc.setNavBarMode(navBarMode);
1010             }
1011         } catch (RemoteException e) {
1012             throw e.rethrowFromSystemServer();
1013         }
1014     }
1015 
1016     /**
1017      * Gets the navigation bar mode. Returns default value if no mode is set.
1018      *
1019      * @hide
1020      */
1021     @SystemApi
1022     @RequiresPermission(android.Manifest.permission.STATUS_BAR)
getNavBarMode()1023     public @NavBarMode int getNavBarMode() {
1024         int navBarMode = NAV_BAR_MODE_DEFAULT;
1025         try {
1026             final IStatusBarService svc = getService();
1027             if (svc != null) {
1028                 navBarMode = svc.getNavBarMode();
1029             }
1030         } catch (RemoteException e) {
1031             throw e.rethrowFromSystemServer();
1032         }
1033         return navBarMode;
1034     }
1035 
1036     /**
1037      * Notifies the system of a new media tap-to-transfer state for the <b>sender</b> device.
1038      *
1039      * <p>The callback should only be provided for the {@link
1040      * MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED} or {@link
1041      * MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED} states, since those are the
1042      * only states where an action can be un-done.
1043      *
1044      * @param displayState the new state for media tap-to-transfer.
1045      * @param routeInfo the media route information for the media being transferred.
1046      * @param undoExecutor an executor to run the callback on and must be provided if the
1047      *                     callback is non-null.
1048      * @param undoCallback a callback that will be triggered if the user elects to undo a media
1049      *                     transfer.
1050      *
1051      * @throws IllegalArgumentException if an undo callback is provided for states that are not a
1052      *   succeeded state.
1053      * @throws IllegalArgumentException if an executor is not provided when a callback is.
1054      *
1055      * @hide
1056      */
1057     @SystemApi
1058     @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
updateMediaTapToTransferSenderDisplay( @ediaTransferSenderState int displayState, @NonNull MediaRoute2Info routeInfo, @Nullable Executor undoExecutor, @Nullable Runnable undoCallback )1059     public void updateMediaTapToTransferSenderDisplay(
1060             @MediaTransferSenderState int displayState,
1061             @NonNull MediaRoute2Info routeInfo,
1062             @Nullable Executor undoExecutor,
1063             @Nullable Runnable undoCallback
1064     ) {
1065         Objects.requireNonNull(routeInfo);
1066         if (displayState != MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED
1067                 && displayState != MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED
1068                 && undoCallback != null) {
1069             throw new IllegalArgumentException(
1070                     "The undoCallback should only be provided when the state is a "
1071                             + "transfer succeeded state");
1072         }
1073         if (undoCallback != null && undoExecutor == null) {
1074             throw new IllegalArgumentException(
1075                     "You must pass an executor when you pass an undo callback");
1076         }
1077         IStatusBarService svc = getService();
1078         try {
1079             UndoCallback callbackProxy = null;
1080             if (undoExecutor != null) {
1081                 callbackProxy = new UndoCallback(undoExecutor, undoCallback);
1082             }
1083             svc.updateMediaTapToTransferSenderDisplay(displayState, routeInfo, callbackProxy);
1084         } catch (RemoteException e) {
1085             e.rethrowFromSystemServer();
1086         }
1087     }
1088 
1089     /**
1090      * Notifies the system of a new media tap-to-transfer state for the <b>receiver</b> device.
1091      *
1092      * @param displayState the new state for media tap-to-transfer.
1093      * @param routeInfo the media route information for the media being transferred.
1094      * @param appIcon the icon of the app playing the media.
1095      * @param appName the name of the app playing the media.
1096      *
1097      * @hide
1098      */
1099     @SystemApi
1100     @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
updateMediaTapToTransferReceiverDisplay( @ediaTransferReceiverState int displayState, @NonNull MediaRoute2Info routeInfo, @Nullable Icon appIcon, @Nullable CharSequence appName)1101     public void updateMediaTapToTransferReceiverDisplay(
1102             @MediaTransferReceiverState int displayState,
1103             @NonNull MediaRoute2Info routeInfo,
1104             @Nullable Icon appIcon,
1105             @Nullable CharSequence appName) {
1106         Objects.requireNonNull(routeInfo);
1107         IStatusBarService svc = getService();
1108         try {
1109             svc.updateMediaTapToTransferReceiverDisplay(displayState, routeInfo, appIcon, appName);
1110         } catch (RemoteException e) {
1111             e.rethrowFromSystemServer();
1112         }
1113     }
1114 
1115     /**
1116      * Registers a provider that notifies callbacks about the status of nearby devices that are able
1117      * to play media.
1118      * <p>
1119      * If multiple providers are registered, all the providers will be used for nearby device
1120      * information.
1121      * <p>
1122      * @param provider the nearby device information provider to register
1123      * <p>
1124      * @hide
1125      */
1126     @SystemApi
1127     @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL)
registerNearbyMediaDevicesProvider( @onNull NearbyMediaDevicesProvider provider )1128     public void registerNearbyMediaDevicesProvider(
1129             @NonNull NearbyMediaDevicesProvider provider
1130     ) {
1131         Objects.requireNonNull(provider);
1132         if (nearbyMediaDevicesProviderMap.containsKey(provider)) {
1133             return;
1134         }
1135         try {
1136             final IStatusBarService svc = getService();
1137             NearbyMediaDevicesProviderWrapper providerWrapper =
1138                     new NearbyMediaDevicesProviderWrapper(provider);
1139             nearbyMediaDevicesProviderMap.put(provider, providerWrapper);
1140             svc.registerNearbyMediaDevicesProvider(providerWrapper);
1141         } catch (RemoteException e) {
1142             throw e.rethrowFromSystemServer();
1143         }
1144     }
1145 
1146    /**
1147      * Unregisters a provider that gives information about nearby devices that are able to play
1148      * media.
1149      * <p>
1150      * See {@link registerNearbyMediaDevicesProvider}.
1151      * <p>
1152      * @param provider the nearby device information provider to unregister
1153      * <p>
1154      * @hide
1155      */
1156     @SystemApi
1157     @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL)
unregisterNearbyMediaDevicesProvider( @onNull NearbyMediaDevicesProvider provider )1158     public void unregisterNearbyMediaDevicesProvider(
1159             @NonNull NearbyMediaDevicesProvider provider
1160     ) {
1161         Objects.requireNonNull(provider);
1162         if (!nearbyMediaDevicesProviderMap.containsKey(provider)) {
1163             return;
1164         }
1165         try {
1166             final IStatusBarService svc = getService();
1167             NearbyMediaDevicesProviderWrapper providerWrapper =
1168                     nearbyMediaDevicesProviderMap.get(provider);
1169             nearbyMediaDevicesProviderMap.remove(provider);
1170             svc.unregisterNearbyMediaDevicesProvider(providerWrapper);
1171         } catch (RemoteException e) {
1172             throw e.rethrowFromSystemServer();
1173         }
1174     }
1175 
1176     /**
1177      * Checks whether the given package should use session-based actions for its media controls.
1178      *
1179      * @param packageName App posting media controls
1180      * @param user Current user handle
1181      * @return true if the app supports session actions
1182      *
1183      * @hide
1184      */
1185     @RequiresPermission(allOf = {android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
1186             android.Manifest.permission.LOG_COMPAT_CHANGE})
useMediaSessionActionsForApp(String packageName, UserHandle user)1187     public static boolean useMediaSessionActionsForApp(String packageName, UserHandle user) {
1188         return CompatChanges.isChangeEnabled(MEDIA_CONTROL_SESSION_ACTIONS, packageName, user);
1189     }
1190 
1191     /** @hide */
windowStateToString(int state)1192     public static String windowStateToString(int state) {
1193         if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
1194         if (state == WINDOW_STATE_HIDDEN) return "WINDOW_STATE_HIDDEN";
1195         if (state == WINDOW_STATE_SHOWING) return "WINDOW_STATE_SHOWING";
1196         return "WINDOW_STATE_UNKNOWN";
1197     }
1198 
1199     /**
1200      * DisableInfo describes this app's requested state of the StatusBar with regards to which
1201      * components are enabled/disabled
1202      *
1203      * @hide
1204      */
1205     @SystemApi
1206     public static final class DisableInfo {
1207 
1208         private boolean mStatusBarExpansion;
1209         private boolean mNavigateHome;
1210         private boolean mNotificationPeeking;
1211         private boolean mRecents;
1212         private boolean mSearch;
1213         private boolean mSystemIcons;
1214         private boolean mClock;
1215         private boolean mNotificationIcons;
1216         private boolean mRotationSuggestion;
1217 
1218         /** @hide */
DisableInfo(int flags1, int flags2)1219         public DisableInfo(int flags1, int flags2) {
1220             mStatusBarExpansion = (flags1 & DISABLE_EXPAND) != 0;
1221             mNavigateHome = (flags1 & DISABLE_HOME) != 0;
1222             mNotificationPeeking = (flags1 & DISABLE_NOTIFICATION_ALERTS) != 0;
1223             mRecents = (flags1 & DISABLE_RECENT) != 0;
1224             mSearch = (flags1 & DISABLE_SEARCH) != 0;
1225             mSystemIcons = (flags1 & DISABLE_SYSTEM_INFO) != 0;
1226             mClock = (flags1 & DISABLE_CLOCK) != 0;
1227             mNotificationIcons = (flags1 & DISABLE_NOTIFICATION_ICONS) != 0;
1228             mRotationSuggestion = (flags2 & DISABLE2_ROTATE_SUGGESTIONS) != 0;
1229         }
1230 
1231         /** @hide */
DisableInfo()1232         public DisableInfo() {}
1233 
1234         /**
1235          * @return {@code true} if expanding the notification shade is disabled
1236          *
1237          * @hide
1238          */
1239         @SystemApi
isStatusBarExpansionDisabled()1240         public boolean isStatusBarExpansionDisabled() {
1241             return mStatusBarExpansion;
1242         }
1243 
1244         /** * @hide */
setStatusBarExpansionDisabled(boolean disabled)1245         public void setStatusBarExpansionDisabled(boolean disabled) {
1246             mStatusBarExpansion = disabled;
1247         }
1248 
1249         /**
1250          * @return {@code true} if navigation home is disabled
1251          *
1252          * @hide
1253          */
1254         @SystemApi
isNavigateToHomeDisabled()1255         public boolean isNavigateToHomeDisabled() {
1256             return mNavigateHome;
1257         }
1258 
1259         /** * @hide */
setNagivationHomeDisabled(boolean disabled)1260         public void setNagivationHomeDisabled(boolean disabled) {
1261             mNavigateHome = disabled;
1262         }
1263 
1264         /**
1265          * @return {@code true} if notification peeking (heads-up notification) is disabled
1266          *
1267          * @hide
1268          */
1269         @SystemApi
isNotificationPeekingDisabled()1270         public boolean isNotificationPeekingDisabled() {
1271             return mNotificationPeeking;
1272         }
1273 
1274         /** @hide */
setNotificationPeekingDisabled(boolean disabled)1275         public void setNotificationPeekingDisabled(boolean disabled) {
1276             mNotificationPeeking = disabled;
1277         }
1278 
1279         /**
1280          * @return {@code true} if mRecents/overview is disabled
1281          *
1282          * @hide
1283          */
1284         @SystemApi
isRecentsDisabled()1285         public boolean isRecentsDisabled() {
1286             return mRecents;
1287         }
1288 
1289         /**  @hide */
setRecentsDisabled(boolean disabled)1290         public void setRecentsDisabled(boolean disabled) {
1291             mRecents = disabled;
1292         }
1293 
1294         /**
1295          * @return {@code true} if mSearch is disabled
1296          *
1297          * @hide
1298          */
1299         @SystemApi
isSearchDisabled()1300         public boolean isSearchDisabled() {
1301             return mSearch;
1302         }
1303 
1304         /** @hide */
setSearchDisabled(boolean disabled)1305         public void setSearchDisabled(boolean disabled) {
1306             mSearch = disabled;
1307         }
1308 
1309         /**
1310          * @return {@code true} if system icons are disabled
1311          *
1312          * @hide
1313          */
areSystemIconsDisabled()1314         public boolean areSystemIconsDisabled() {
1315             return mSystemIcons;
1316         }
1317 
1318         /** * @hide */
setSystemIconsDisabled(boolean disabled)1319         public void setSystemIconsDisabled(boolean disabled) {
1320             mSystemIcons = disabled;
1321         }
1322 
1323         /**
1324          * @return {@code true} if the clock icon is disabled
1325          *
1326          * @hide
1327          */
isClockDisabled()1328         public boolean isClockDisabled() {
1329             return mClock;
1330         }
1331 
1332         /** * @hide */
setClockDisabled(boolean disabled)1333         public void setClockDisabled(boolean disabled) {
1334             mClock = disabled;
1335         }
1336 
1337         /**
1338          * @return {@code true} if notification icons are disabled
1339          *
1340          * @hide
1341          */
areNotificationIconsDisabled()1342         public boolean areNotificationIconsDisabled() {
1343             return mNotificationIcons;
1344         }
1345 
1346         /** * @hide */
setNotificationIconsDisabled(boolean disabled)1347         public void setNotificationIconsDisabled(boolean disabled) {
1348             mNotificationIcons = disabled;
1349         }
1350 
1351         /**
1352          * Returns whether the rotation suggestion is disabled.
1353          *
1354          * @hide
1355          */
1356         @TestApi
isRotationSuggestionDisabled()1357         public boolean isRotationSuggestionDisabled() {
1358             return mRotationSuggestion;
1359         }
1360 
1361         /**
1362          * @return {@code true} if no components are disabled (default state)
1363          * @hide
1364          */
1365         @SystemApi
areAllComponentsEnabled()1366         public boolean areAllComponentsEnabled() {
1367             return !mStatusBarExpansion && !mNavigateHome && !mNotificationPeeking && !mRecents
1368                     && !mSearch && !mSystemIcons && !mClock && !mNotificationIcons
1369                     && !mRotationSuggestion;
1370         }
1371 
1372         /** @hide */
setEnableAll()1373         public void setEnableAll() {
1374             mStatusBarExpansion = false;
1375             mNavigateHome = false;
1376             mNotificationPeeking = false;
1377             mRecents = false;
1378             mSearch = false;
1379             mSystemIcons = false;
1380             mClock = false;
1381             mNotificationIcons = false;
1382             mRotationSuggestion = false;
1383         }
1384 
1385         /**
1386          * @return {@code true} if all status bar components are disabled
1387          *
1388          * @hide
1389          */
areAllComponentsDisabled()1390         public boolean areAllComponentsDisabled() {
1391             return mStatusBarExpansion && mNavigateHome && mNotificationPeeking
1392                     && mRecents && mSearch && mSystemIcons && mClock && mNotificationIcons
1393                     && mRotationSuggestion;
1394         }
1395 
1396         /** @hide */
setDisableAll()1397         public void setDisableAll() {
1398             mStatusBarExpansion = true;
1399             mNavigateHome = true;
1400             mNotificationPeeking = true;
1401             mRecents = true;
1402             mSearch = true;
1403             mSystemIcons = true;
1404             mClock = true;
1405             mNotificationIcons = true;
1406             mRotationSuggestion = true;
1407         }
1408 
1409         @NonNull
1410         @Override
toString()1411         public String toString() {
1412             StringBuilder sb = new StringBuilder();
1413             sb.append("DisableInfo: ");
1414             sb.append(" mStatusBarExpansion=").append(mStatusBarExpansion ? "disabled" : "enabled");
1415             sb.append(" mNavigateHome=").append(mNavigateHome ? "disabled" : "enabled");
1416             sb.append(" mNotificationPeeking=")
1417                     .append(mNotificationPeeking ? "disabled" : "enabled");
1418             sb.append(" mRecents=").append(mRecents ? "disabled" : "enabled");
1419             sb.append(" mSearch=").append(mSearch ? "disabled" : "enabled");
1420             sb.append(" mSystemIcons=").append(mSystemIcons ? "disabled" : "enabled");
1421             sb.append(" mClock=").append(mClock ? "disabled" : "enabled");
1422             sb.append(" mNotificationIcons=").append(mNotificationIcons ? "disabled" : "enabled");
1423             sb.append(" mRotationSuggestion=").append(mRotationSuggestion ? "disabled" : "enabled");
1424 
1425             return sb.toString();
1426 
1427         }
1428 
1429         /**
1430          * Convert a DisableInfo to equivalent flags
1431          * @return a pair of equivalent disable flags
1432          *
1433          * @hide
1434          */
toFlags()1435         public Pair<Integer, Integer> toFlags() {
1436             int disable1 = DISABLE_NONE;
1437             int disable2 = DISABLE2_NONE;
1438 
1439             if (mStatusBarExpansion) disable1 |= DISABLE_EXPAND;
1440             if (mNavigateHome) disable1 |= DISABLE_HOME;
1441             if (mNotificationPeeking) disable1 |= DISABLE_NOTIFICATION_ALERTS;
1442             if (mRecents) disable1 |= DISABLE_RECENT;
1443             if (mSearch) disable1 |= DISABLE_SEARCH;
1444             if (mSystemIcons) disable1 |= DISABLE_SYSTEM_INFO;
1445             if (mClock) disable1 |= DISABLE_CLOCK;
1446             if (mNotificationIcons) disable1 |= DISABLE_NOTIFICATION_ICONS;
1447             if (mRotationSuggestion) disable2 |= DISABLE2_ROTATE_SUGGESTIONS;
1448 
1449             return new Pair<Integer, Integer>(disable1, disable2);
1450         }
1451     }
1452 
1453     /**
1454      * @hide
1455      */
1456     static final class RequestResultCallback extends IAddTileResultCallback.Stub {
1457 
1458         @NonNull
1459         private final Executor mExecutor;
1460         @NonNull
1461         private final Consumer<Integer> mCallback;
1462 
RequestResultCallback(@onNull Executor executor, @NonNull Consumer<Integer> callback)1463         RequestResultCallback(@NonNull Executor executor, @NonNull Consumer<Integer> callback) {
1464             mExecutor = executor;
1465             mCallback = callback;
1466         }
1467 
1468         @Override
onTileRequest(int userResponse)1469         public void onTileRequest(int userResponse) {
1470             mExecutor.execute(() -> mCallback.accept(userResponse));
1471         }
1472     }
1473 
1474     /**
1475      * @hide
1476      */
1477     static final class UndoCallback extends IUndoMediaTransferCallback.Stub {
1478         @NonNull
1479         private final Executor mExecutor;
1480         @NonNull
1481         private final Runnable mCallback;
1482 
UndoCallback(@onNull Executor executor, @NonNull Runnable callback)1483         UndoCallback(@NonNull Executor executor, @NonNull Runnable callback) {
1484             mExecutor = executor;
1485             mCallback = callback;
1486         }
1487 
1488         @Override
onUndoTriggered()1489         public void onUndoTriggered() {
1490             final long callingIdentity = Binder.clearCallingIdentity();
1491             try {
1492                 mExecutor.execute(mCallback);
1493             } finally {
1494                 restoreCallingIdentity(callingIdentity);
1495             }
1496         }
1497     }
1498 
1499     /**
1500      * @hide
1501      */
1502     static final class NearbyMediaDevicesProviderWrapper extends INearbyMediaDevicesProvider.Stub {
1503         @NonNull
1504         private final NearbyMediaDevicesProvider mProvider;
1505         // Because we're wrapping a {@link NearbyMediaDevicesProvider} in a binder-compatible
1506         // interface, we also need to wrap the callbacks that the provider receives. We use
1507         // this map to keep track of the original callback and the wrapper callback so that
1508         // unregistering the callback works correctly.
1509         @NonNull
1510         private final Map<INearbyMediaDevicesUpdateCallback, Consumer<List<NearbyDevice>>>
1511                 mRegisteredCallbacks = new HashMap<>();
1512 
NearbyMediaDevicesProviderWrapper(@onNull NearbyMediaDevicesProvider provider)1513         NearbyMediaDevicesProviderWrapper(@NonNull NearbyMediaDevicesProvider provider) {
1514             mProvider = provider;
1515         }
1516 
1517         @Override
registerNearbyDevicesCallback( @onNull INearbyMediaDevicesUpdateCallback callback)1518         public void registerNearbyDevicesCallback(
1519                 @NonNull INearbyMediaDevicesUpdateCallback callback) {
1520             Consumer<List<NearbyDevice>> callbackAsConsumer = nearbyDevices -> {
1521                 try {
1522                     callback.onDevicesUpdated(nearbyDevices);
1523                 } catch (RemoteException ex) {
1524                     throw ex.rethrowFromSystemServer();
1525                 }
1526             };
1527 
1528             mRegisteredCallbacks.put(callback, callbackAsConsumer);
1529             mProvider.registerNearbyDevicesCallback(callbackAsConsumer);
1530         }
1531 
1532         @Override
unregisterNearbyDevicesCallback( @onNull INearbyMediaDevicesUpdateCallback callback)1533         public void unregisterNearbyDevicesCallback(
1534                 @NonNull INearbyMediaDevicesUpdateCallback callback) {
1535             if (!mRegisteredCallbacks.containsKey(callback)) {
1536                 return;
1537             }
1538             mProvider.unregisterNearbyDevicesCallback(mRegisteredCallbacks.get(callback));
1539             mRegisteredCallbacks.remove(callback);
1540         }
1541     }
1542 }
1543