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