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