• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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.media;
18 
19 import static android.media.MediaRouter2Utils.toUniqueId;
20 import static android.media.audio.Flags.FLAG_ENABLE_MULTICHANNEL_GROUP_DEVICE;
21 
22 import static com.android.media.flags.Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER;
23 import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES;
24 import static com.android.media.flags.Flags.FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME;
25 import static com.android.media.flags.Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2;
26 import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES;
27 import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES;
28 import static com.android.media.flags.Flags.FLAG_ENABLE_ROUTE_VISIBILITY_CONTROL_API;
29 
30 import android.annotation.FlaggedApi;
31 import android.annotation.IntDef;
32 import android.annotation.NonNull;
33 import android.annotation.Nullable;
34 import android.annotation.SuppressLint;
35 import android.annotation.TestApi;
36 import android.net.Uri;
37 import android.os.Bundle;
38 import android.os.Parcel;
39 import android.os.Parcelable;
40 import android.text.TextUtils;
41 
42 import com.android.internal.util.Preconditions;
43 
44 import java.io.PrintWriter;
45 import java.lang.annotation.Retention;
46 import java.lang.annotation.RetentionPolicy;
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.List;
50 import java.util.Locale;
51 import java.util.Objects;
52 import java.util.Set;
53 import java.util.stream.Collectors;
54 
55 /**
56  * Describes the properties of a route.
57  */
58 public final class MediaRoute2Info implements Parcelable {
59     @NonNull
60     public static final Creator<MediaRoute2Info> CREATOR = new Creator<MediaRoute2Info>() {
61         @Override
62         public MediaRoute2Info createFromParcel(Parcel in) {
63             return new MediaRoute2Info(in);
64         }
65 
66         @Override
67         public MediaRoute2Info[] newArray(int size) {
68             return new MediaRoute2Info[size];
69         }
70     };
71 
72     /**
73      * The {@link #getOriginalId() original id} of the route that represents the built-in media
74      * route.
75      *
76      * <p>A route with this id will only be visible to apps with permission to do system routing,
77      * which means having {@link android.Manifest.permission#BLUETOOTH_CONNECT} and {@link
78      * android.Manifest.permission#BLUETOOTH_SCAN}, or {@link
79      * android.Manifest.permission#MODIFY_AUDIO_ROUTING}.
80      *
81      * @hide
82      */
83     public static final String ROUTE_ID_DEVICE = "DEVICE_ROUTE";
84 
85     /**
86      * The {@link #getOriginalId() original id} of the route that represents the default system
87      * media route.
88      *
89      * <p>A route with this id will be visible to apps with no permission over system routing. See
90      * {@link #ROUTE_ID_DEVICE} for details.
91      *
92      * @hide
93      */
94     public static final String ROUTE_ID_DEFAULT = "DEFAULT_ROUTE";
95 
96     /** @hide */
97     @IntDef({CONNECTION_STATE_DISCONNECTED, CONNECTION_STATE_CONNECTING,
98             CONNECTION_STATE_CONNECTED})
99     @Retention(RetentionPolicy.SOURCE)
100     public @interface ConnectionState {}
101 
102     /**
103      * The default connection state indicating the route is disconnected.
104      *
105      * @see #getConnectionState
106      */
107     public static final int CONNECTION_STATE_DISCONNECTED = 0;
108 
109     /**
110      * A connection state indicating the route is in the process of connecting and is not yet
111      * ready for use.
112      *
113      * @see #getConnectionState
114      */
115     public static final int CONNECTION_STATE_CONNECTING = 1;
116 
117     /**
118      * A connection state indicating the route is connected.
119      *
120      * @see #getConnectionState
121      */
122     public static final int CONNECTION_STATE_CONNECTED = 2;
123 
124     /** @hide */
125     @IntDef({PLAYBACK_VOLUME_FIXED, PLAYBACK_VOLUME_VARIABLE})
126     @Retention(RetentionPolicy.SOURCE)
127     public @interface PlaybackVolume {}
128 
129     /**
130      * Playback information indicating the playback volume is fixed, i&#46;e&#46; it cannot be
131      * controlled from this object. An example of fixed playback volume is a remote player,
132      * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather
133      * than attenuate at the source.
134      *
135      * @see #getVolumeHandling()
136      */
137     public static final int PLAYBACK_VOLUME_FIXED = 0;
138     /**
139      * Playback information indicating the playback volume is variable and can be controlled
140      * from this object.
141      *
142      * @see #getVolumeHandling()
143      */
144     public static final int PLAYBACK_VOLUME_VARIABLE = 1;
145 
146     /** @hide */
147     @IntDef(
148             prefix = {"TYPE_"},
149             value = {
150                 TYPE_UNKNOWN,
151                 TYPE_BUILTIN_SPEAKER,
152                 TYPE_WIRED_HEADSET,
153                 TYPE_WIRED_HEADPHONES,
154                 TYPE_BLUETOOTH_A2DP,
155                 TYPE_HDMI,
156                 TYPE_HDMI_ARC,
157                 TYPE_HDMI_EARC,
158                 TYPE_LINE_DIGITAL,
159                 TYPE_LINE_ANALOG,
160                 TYPE_AUX_LINE,
161                 TYPE_USB_DEVICE,
162                 TYPE_USB_ACCESSORY,
163                 TYPE_DOCK,
164                 TYPE_USB_HEADSET,
165                 TYPE_HEARING_AID,
166                 TYPE_BLE_HEADSET,
167                 TYPE_REMOTE_TV,
168                 TYPE_REMOTE_SPEAKER,
169                 TYPE_REMOTE_AUDIO_VIDEO_RECEIVER,
170                 TYPE_REMOTE_TABLET,
171                 TYPE_REMOTE_TABLET_DOCKED,
172                 TYPE_REMOTE_COMPUTER,
173                 TYPE_REMOTE_GAME_CONSOLE,
174                 TYPE_REMOTE_CAR,
175                 TYPE_REMOTE_SMARTWATCH,
176                 TYPE_REMOTE_SMARTPHONE,
177                 TYPE_GROUP
178             })
179     @Retention(RetentionPolicy.SOURCE)
180     public @interface Type {}
181 
182     /**
183      * Indicates the route's type is unknown or undefined.
184      *
185      * @see #getType
186      */
187     public static final int TYPE_UNKNOWN = 0;
188 
189     /**
190      * Indicates the route is the speaker system (i.e. a mono speaker or stereo speakers) built into
191      * the device.
192      *
193      * @see #getType
194      * @see AudioDeviceInfo#TYPE_BUILTIN_SPEAKER
195      */
196     public static final int TYPE_BUILTIN_SPEAKER = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
197 
198     /**
199      * Indicates the route is a headset, which is the combination of a headphones and a microphone.
200      *
201      * @see #getType
202      * @see AudioDeviceInfo#TYPE_WIRED_HEADSET
203      */
204     public static final int TYPE_WIRED_HEADSET = AudioDeviceInfo.TYPE_WIRED_HEADSET;
205 
206     /**
207      * Indicates the route is a pair of wired headphones.
208      *
209      * @see #getType
210      * @see AudioDeviceInfo#TYPE_WIRED_HEADPHONES
211      */
212     public static final int TYPE_WIRED_HEADPHONES = AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
213 
214     /**
215      * Indicates the route is a bluetooth device, such as a bluetooth speaker or headphones.
216      *
217      * @see #getType
218      * @see AudioDeviceInfo#TYPE_BLUETOOTH_A2DP
219      */
220     public static final int TYPE_BLUETOOTH_A2DP = AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
221 
222     /**
223      * Indicates the route is an HDMI connection.
224      *
225      * @see #getType
226      * @see AudioDeviceInfo#TYPE_HDMI
227      */
228     public static final int TYPE_HDMI = AudioDeviceInfo.TYPE_HDMI;
229 
230     /**
231      * Indicates the route is an Audio Return Channel of an HDMI connection.
232      *
233      * @see #getType
234      * @see AudioDeviceInfo#TYPE_HDMI_ARC
235      */
236     @FlaggedApi(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
237     public static final int TYPE_HDMI_ARC = AudioDeviceInfo.TYPE_HDMI_ARC;
238 
239     /**
240      * Indicates the route is an Enhanced Audio Return Channel of an HDMI connection.
241      *
242      * @see #getType
243      * @see AudioDeviceInfo#TYPE_HDMI_EARC
244      */
245     @FlaggedApi(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
246     public static final int TYPE_HDMI_EARC = AudioDeviceInfo.TYPE_HDMI_EARC;
247 
248     /**
249      * Indicates the route is a digital line connection (for example S/PDIF).
250      *
251      * @see #getType
252      * @see AudioDeviceInfo#TYPE_LINE_DIGITAL
253      */
254     @FlaggedApi(FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES)
255     public static final int TYPE_LINE_DIGITAL = AudioDeviceInfo.TYPE_LINE_DIGITAL;
256 
257     /**
258      * Indicates the route is an analog line-level connection.
259      *
260      * @see #getType
261      * @see AudioDeviceInfo#TYPE_LINE_ANALOG
262      */
263     @FlaggedApi(FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES)
264     public static final int TYPE_LINE_ANALOG = AudioDeviceInfo.TYPE_LINE_ANALOG;
265 
266     /**
267      * Indicates the route is using the auxiliary line-level connectors.
268      *
269      * @see #getType
270      * @see AudioDeviceInfo#TYPE_AUX_LINE
271      */
272     @FlaggedApi(FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES)
273     public static final int TYPE_AUX_LINE = AudioDeviceInfo.TYPE_AUX_LINE;
274 
275     /**
276      * Indicates the route is a USB audio device.
277      *
278      * @see #getType
279      * @see AudioDeviceInfo#TYPE_USB_DEVICE
280      */
281     public static final int TYPE_USB_DEVICE = AudioDeviceInfo.TYPE_USB_DEVICE;
282 
283     /**
284      * Indicates the route is a USB audio device in accessory mode.
285      *
286      * @see #getType
287      * @see AudioDeviceInfo#TYPE_USB_ACCESSORY
288      */
289     public static final int TYPE_USB_ACCESSORY = AudioDeviceInfo.TYPE_USB_ACCESSORY;
290 
291     /**
292      * Indicates the route is the audio device associated with a dock.
293      *
294      * @see #getType
295      * @see AudioDeviceInfo#TYPE_DOCK
296      */
297     public static final int TYPE_DOCK = AudioDeviceInfo.TYPE_DOCK;
298 
299     /**
300      * Indicates the route is a USB audio headset.
301      *
302      * @see #getType
303      * @see AudioDeviceInfo#TYPE_USB_HEADSET
304      */
305     public static final int TYPE_USB_HEADSET = AudioDeviceInfo.TYPE_USB_HEADSET;
306 
307     /**
308      * Indicates the route is a hearing aid.
309      *
310      * @see #getType
311      * @see AudioDeviceInfo#TYPE_HEARING_AID
312      */
313     public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID;
314 
315     /**
316      * Indicates the route is a Bluetooth Low Energy (BLE) HEADSET.
317      *
318      * @see #getType
319      * @see AudioDeviceInfo#TYPE_BLE_HEADSET
320      */
321     public static final int TYPE_BLE_HEADSET = AudioDeviceInfo.TYPE_BLE_HEADSET;
322 
323     /**
324      * Indicates the route is a speaker group supporting multichannel contents.
325      *
326      * <p>The speakers in the group are connected together using local network based protocols. The
327      * speaker group requires additional input of the physical positions of each individual speaker
328      * to provide a better experience on multichannel contents.
329      *
330      * @see #getType
331      * @see AudioDeviceInfo#TYPE_MULTICHANNEL_GROUP
332      */
333     @FlaggedApi(FLAG_ENABLE_MULTICHANNEL_GROUP_DEVICE)
334     public static final int TYPE_MULTICHANNEL_SPEAKER_GROUP =
335             AudioDeviceInfo.TYPE_MULTICHANNEL_GROUP;
336 
337     /**
338      * Indicates the route is a remote TV.
339      *
340      * <p>A remote device uses a routing protocol managed by the application, as opposed to the
341      * routing being done by the system.
342      *
343      * @see #getType
344      */
345     public static final int TYPE_REMOTE_TV = 1001;
346 
347     /**
348      * Indicates the route is a remote speaker.
349      *
350      * <p>A remote device uses a routing protocol managed by the application, as opposed to the
351      * routing being done by the system.
352      *
353      * @see #getType
354      */
355     public static final int TYPE_REMOTE_SPEAKER = 1002;
356 
357     /**
358      * Indicates the route is a remote Audio/Video Receiver (AVR).
359      *
360      * <p>A remote device uses a routing protocol managed by the application, as opposed to the
361      * routing being done by the system.
362      *
363      * @see #getType
364      */
365     public static final int TYPE_REMOTE_AUDIO_VIDEO_RECEIVER = 1003;
366 
367     /**
368      * Indicates the route is a remote tablet.
369      *
370      * <p>A remote device uses a routing protocol managed by the application, as opposed to the
371      * routing being done by the system.
372      *
373      * @see #getType
374      */
375     @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
376     public static final int TYPE_REMOTE_TABLET = 1004;
377 
378     /**
379      * Indicates the route is a remote docked tablet.
380      *
381      * <p>A remote device uses a routing protocol managed by the application, as opposed to the
382      * routing being done by the system.
383      *
384      * @see #getType
385      */
386     @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
387     public static final int TYPE_REMOTE_TABLET_DOCKED = 1005;
388 
389     /**
390      * Indicates the route is a remote computer.
391      *
392      * <p>A remote device uses a routing protocol managed by the application, as opposed to the
393      * routing being done by the system.
394      *
395      * @see #getType
396      */
397     @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
398     public static final int TYPE_REMOTE_COMPUTER = 1006;
399 
400     /**
401      * Indicates the route is a remote gaming console.
402      *
403      * <p>A remote device uses a routing protocol managed by the application, as opposed to the
404      * routing being done by the system.
405      *
406      * @see #getType
407      */
408     @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
409     public static final int TYPE_REMOTE_GAME_CONSOLE = 1007;
410 
411     /**
412      * Indicates the route is a remote car.
413      *
414      * <p>A remote device uses a routing protocol managed by the application, as opposed to the
415      * routing being done by the system.
416      *
417      * @see #getType
418      */
419     @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
420     public static final int TYPE_REMOTE_CAR = 1008;
421 
422     /**
423      * Indicates the route is a remote smartwatch.
424      *
425      * <p>A remote device uses a routing protocol managed by the application, as opposed to the
426      * routing being done by the system.
427      *
428      * @see #getType
429      */
430     @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
431     public static final int TYPE_REMOTE_SMARTWATCH = 1009;
432 
433     /**
434      * Indicates the route is a remote smartphone.
435      *
436      * <p>A remote device uses a routing protocol managed by the application, as opposed to the
437      * routing being done by the system.
438      *
439      * @see #getType
440      */
441     @FlaggedApi(FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES)
442     public static final int TYPE_REMOTE_SMARTPHONE = 1010;
443 
444     /**
445      * Indicates the route is a group of devices.
446      *
447      * @see #getType
448      */
449     public static final int TYPE_GROUP = 2000;
450 
451     /** @hide */
452     @IntDef(
453             prefix = {"ROUTING_TYPE_"},
454             value = {
455                 FLAG_ROUTING_TYPE_SYSTEM_AUDIO,
456                 FLAG_ROUTING_TYPE_SYSTEM_VIDEO,
457                 FLAG_ROUTING_TYPE_REMOTE
458             },
459             flag = true)
460     @Retention(RetentionPolicy.SOURCE)
461     public @interface RoutingType {}
462 
463     /**
464      * Indicates that a route supports routing of the system audio.
465      *
466      * <p>Providers that support this type of routing require the {@link
467      * android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission.
468      */
469     @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
470     public static final int FLAG_ROUTING_TYPE_SYSTEM_AUDIO = 1;
471 
472     /**
473      * Indicates that a route supports routing of the system video.
474      *
475      * @hide
476      */
477     // TODO: b/380431086 - Enable this API once we add support for system video routing.
478     @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
479     public static final int FLAG_ROUTING_TYPE_SYSTEM_VIDEO = 1 << 1;
480 
481     /**
482      * Indicates that a route supports routing playback to remote routes through control commands.
483      *
484      * <p>This type of routing does not affect this system's audio or video, but instead relies on
485      * the device that corresponds to this route to fetch and play the media. It also requires the
486      * media app to take care of initializing and controlling playback.
487      */
488     @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
489     public static final int FLAG_ROUTING_TYPE_REMOTE = 1 << 2;
490 
491     private static final int FLAG_ROUTING_TYPE_ALL =
492             FLAG_ROUTING_TYPE_SYSTEM_AUDIO
493                     | FLAG_ROUTING_TYPE_SYSTEM_VIDEO
494                     | FLAG_ROUTING_TYPE_REMOTE;
495 
496     /**
497      * Route feature: Live audio.
498      * <p>
499      * A route that supports live audio routing will allow the media audio stream
500      * to be sent to supported destinations.  This can include internal speakers or
501      * audio jacks on the device itself, A2DP devices, and more.
502      * </p><p>
503      * When a live audio route is selected, audio routing is transparent to the application.
504      * All audio played on the media stream will be routed to the selected destination.
505      * </p><p>
506      * Refer to the class documentation for details about live audio routes.
507      * </p>
508      */
509     public static final String FEATURE_LIVE_AUDIO = "android.media.route.feature.LIVE_AUDIO";
510 
511     /**
512      * Route feature: Live video.
513      * <p>
514      * A route that supports live video routing will allow a mirrored version
515      * of the device's primary display or a customized
516      * {@link android.app.Presentation Presentation} to be sent to supported
517      * destinations.
518      * </p><p>
519      * When a live video route is selected, audio and video routing is transparent
520      * to the application.  By default, audio and video is routed to the selected
521      * destination.  For certain live video routes, the application may also use a
522      * {@link android.app.Presentation Presentation} to replace the mirrored view
523      * on the external display with different content.
524      * </p><p>
525      * Refer to the class documentation for details about live video routes.
526      * </p>
527      *
528      * @see android.app.Presentation
529      */
530     public static final String FEATURE_LIVE_VIDEO = "android.media.route.feature.LIVE_VIDEO";
531 
532     /**
533      * Route feature: Local playback.
534      * @hide
535      */
536     public static final String FEATURE_LOCAL_PLAYBACK =
537             "android.media.route.feature.LOCAL_PLAYBACK";
538 
539     /**
540      * Route feature: Remote playback.
541      * <p>
542      * A route that supports remote playback routing will allow an application to send
543      * requests to play content remotely to supported destinations.
544      * A route may only support {@link #FEATURE_REMOTE_AUDIO_PLAYBACK audio playback} or
545      * {@link #FEATURE_REMOTE_VIDEO_PLAYBACK video playback}.
546      * </p><p>
547      * Remote playback routes destinations operate independently of the local device.
548      * When a remote playback route is selected, the application can control the content
549      * playing on the destination using {@link MediaRouter2.RoutingController#getControlHints()}.
550      * The application may also receive status updates from the route regarding remote playback.
551      * </p><p>
552      * Refer to the class documentation for details about remote playback routes.
553      * </p>
554      * @see #FEATURE_REMOTE_AUDIO_PLAYBACK
555      * @see #FEATURE_REMOTE_VIDEO_PLAYBACK
556      */
557     public static final String FEATURE_REMOTE_PLAYBACK =
558             "android.media.route.feature.REMOTE_PLAYBACK";
559 
560     /**
561      * Route feature: Remote audio playback.
562      * <p>
563      * A route that supports remote audio playback routing will allow an application to send
564      * requests to play audio content remotely to supported destinations.
565      *
566      * @see #FEATURE_REMOTE_PLAYBACK
567      * @see #FEATURE_REMOTE_VIDEO_PLAYBACK
568      */
569     public static final String FEATURE_REMOTE_AUDIO_PLAYBACK =
570             "android.media.route.feature.REMOTE_AUDIO_PLAYBACK";
571 
572     /**
573      * Route feature: Remote video playback.
574      * <p>
575      * A route that supports remote video playback routing will allow an application to send
576      * requests to play video content remotely to supported destinations.
577      *
578      * @see #FEATURE_REMOTE_PLAYBACK
579      * @see #FEATURE_REMOTE_AUDIO_PLAYBACK
580      */
581     public static final String FEATURE_REMOTE_VIDEO_PLAYBACK =
582             "android.media.route.feature.REMOTE_VIDEO_PLAYBACK";
583 
584     /**
585      * Route feature: Remote group playback.
586      * <p>
587      * @hide
588      */
589     public static final String FEATURE_REMOTE_GROUP_PLAYBACK =
590             "android.media.route.feature.REMOTE_GROUP_PLAYBACK";
591 
592     /** Indicates the route is always suitable for media playback. */
593     @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
594     public static final int SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER = 0;
595 
596     /**
597      * Indicates that the route is suitable for media playback only after explicit user selection.
598      */
599     @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
600     public static final int SUITABILITY_STATUS_SUITABLE_FOR_MANUAL_TRANSFER = 1;
601 
602     /** Indicates that the route is never suitable for media playback. */
603     @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
604     public static final int SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER = 2;
605 
606     /**
607      * Route suitability status.
608      *
609      * <p>Signals whether the route is suitable to play media.
610      *
611      * @hide
612      */
613     @IntDef(
614             value = {
615                 SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER,
616                 SUITABILITY_STATUS_SUITABLE_FOR_MANUAL_TRANSFER,
617                 SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER
618             })
619     @Retention(RetentionPolicy.SOURCE)
620     @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
621     public @interface SuitabilityStatus {}
622 
623     private final String mId;
624     private final CharSequence mName;
625     private final List<String> mFeatures;
626     @Type
627     private final int mType;
628     @RoutingType private final int mRoutingTypeFlags;
629     private final boolean mIsSystem;
630     private final Uri mIconUri;
631     private final CharSequence mDescription;
632     @ConnectionState
633     private final int mConnectionState;
634     private final String mClientPackageName;
635     private final String mProviderPackageName;
636     @PlaybackVolume private final int mVolumeHandling;
637     private final int mVolumeMax;
638     private final int mVolume;
639     private final String mAddress;
640     private final Set<String> mDeduplicationIds;
641     private final Bundle mExtras;
642     private final String mProviderId;
643     private final boolean mIsVisibilityRestricted;
644     private final Set<String> mAllowedPackages;
645     private final List<Set<String>> mRequiredPermissions;
646     @SuitabilityStatus private final int mSuitabilityStatus;
647 
MediaRoute2Info(@onNull Builder builder)648     MediaRoute2Info(@NonNull Builder builder) {
649         mId = builder.mId;
650         mName = builder.mName;
651         mFeatures = builder.mFeatures;
652         mType = builder.mType;
653         mRoutingTypeFlags = builder.mRoutingTypeFlags;
654         mIsSystem = builder.mIsSystem;
655         mIconUri = builder.mIconUri;
656         mDescription = builder.mDescription;
657         mConnectionState = builder.mConnectionState;
658         mClientPackageName = builder.mClientPackageName;
659         mProviderPackageName = builder.mProviderPackageName;
660         mVolumeHandling = builder.mVolumeHandling;
661         mVolumeMax = builder.mVolumeMax;
662         mVolume = builder.mVolume;
663         mAddress = builder.mAddress;
664         mDeduplicationIds = builder.mDeduplicationIds;
665         mExtras = builder.mExtras;
666         mProviderId = builder.mProviderId;
667         mIsVisibilityRestricted = builder.mIsVisibilityRestricted;
668         mAllowedPackages = builder.mAllowedPackages;
669         mSuitabilityStatus = builder.mSuitabilityStatus;
670         mRequiredPermissions = List.copyOf(builder.mRequiredPermissions);
671     }
672 
MediaRoute2Info(@onNull Parcel in)673     MediaRoute2Info(@NonNull Parcel in) {
674         mId = in.readString();
675         Preconditions.checkArgument(!TextUtils.isEmpty(mId));
676         mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
677         mFeatures = in.createStringArrayList();
678         mType = in.readInt();
679         mRoutingTypeFlags = validateRoutingTypeFlags(in.readInt());
680         mIsSystem = in.readBoolean();
681         mIconUri = in.readParcelable(null, android.net.Uri.class);
682         mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
683         mConnectionState = in.readInt();
684         mClientPackageName = in.readString();
685         mProviderPackageName = in.readString();
686         mVolumeHandling = in.readInt();
687         mVolumeMax = in.readInt();
688         mVolume = in.readInt();
689         mAddress = in.readString();
690         mDeduplicationIds = Set.of(in.readStringArray());
691         mExtras = in.readBundle();
692         mProviderId = in.readString();
693         mIsVisibilityRestricted = in.readBoolean();
694         mAllowedPackages = Set.of(in.createString8Array());
695         ArrayList<Set<String>> requiredPermissions = new ArrayList<>();
696         int numRequiredPermissionSets = in.readInt();
697         for (int i = 0; i < numRequiredPermissionSets; i++) {
698             requiredPermissions.add(Set.of(in.createString8Array()));
699         }
700         mRequiredPermissions = List.copyOf(requiredPermissions); // Use copyOf to make it immutable.
701         mSuitabilityStatus = in.readInt();
702     }
703 
704     /**
705      * Gets the id of the route. The routes which are given by {@link MediaRouter2} will have
706      * unique IDs.
707      * <p>
708      * In order to ensure uniqueness in {@link MediaRouter2} side, the value of this method
709      * can be different from what was set in {@link MediaRoute2ProviderService}.
710      *
711      * @see Builder#Builder(String, CharSequence)
712      */
713     @NonNull
getId()714     public String getId() {
715         if (!TextUtils.isEmpty(mProviderId)) {
716             return toUniqueId(mProviderId, mId);
717         } else {
718             return mId;
719         }
720     }
721 
722     /**
723      * Gets the user-visible name of the route.
724      */
725     @NonNull
getName()726     public CharSequence getName() {
727         return mName;
728     }
729 
730     /**
731      * Gets the supported features of the route.
732      */
733     @NonNull
getFeatures()734     public List<String> getFeatures() {
735         return mFeatures;
736     }
737 
738     /**
739      * Returns the type of this route.
740      */
741     @Type
getType()742     public int getType() {
743         return mType;
744     }
745 
746     /** Returns the flags that indicate the routing types supported by this route. */
747     @RoutingType
748     @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
getSupportedRoutingTypes()749     public int getSupportedRoutingTypes() {
750         return mRoutingTypeFlags;
751     }
752 
753     /**
754      * Returns whether the route is a system route or not.
755      * <p>
756      * System routes are media routes directly controlled by the system
757      * such as phone speaker, wired headset, and Bluetooth devices.
758      * </p>
759      */
isSystemRoute()760     public boolean isSystemRoute() {
761         return mIsSystem;
762     }
763 
764     /**
765      * Gets the URI of the icon representing this route.
766      * <p>
767      * This icon will be used in picker UIs if available.
768      *
769      * @return The URI of the icon representing this route, or null if none.
770      */
771     @Nullable
getIconUri()772     public Uri getIconUri() {
773         return mIconUri;
774     }
775 
776     /**
777      * Gets the user-visible description of the route.
778      */
779     @Nullable
getDescription()780     public CharSequence getDescription() {
781         return mDescription;
782     }
783 
784     /**
785      * Gets the connection state of the route.
786      *
787      * @return The connection state of this route: {@link #CONNECTION_STATE_DISCONNECTED},
788      * {@link #CONNECTION_STATE_CONNECTING}, or {@link #CONNECTION_STATE_CONNECTED}.
789      */
790     @ConnectionState
getConnectionState()791     public int getConnectionState() {
792         return mConnectionState;
793     }
794 
795     /**
796      * Gets the package name of the app using the route.
797      * Returns null if no apps are using this route.
798      */
799     @Nullable
getClientPackageName()800     public String getClientPackageName() {
801         return mClientPackageName;
802     }
803 
804     /**
805      * Gets the package name of the {@link MediaRoute2ProviderService provider} that published the
806      * route, or null if it has not yet been populated.
807      *
808      * <p>The package name of the route provider is populated by the system as part of {@link
809      * MediaRoute2ProviderService#notifyRoutes(java.util.Collection)}. As a result, it's expectable
810      * that a {@link MediaRoute2Info} instance that hasn't yet been published will have a null
811      * provider package name. Otherwise, routes obtained via {@link MediaRouter2} should have a
812      * populated provider package name.
813      */
814     @FlaggedApi(FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME)
815     @Nullable
getProviderPackageName()816     public String getProviderPackageName() {
817         return mProviderPackageName;
818     }
819 
820     /**
821      * Gets information about how volume is handled on the route.
822      *
823      * @return {@link #PLAYBACK_VOLUME_FIXED} or {@link #PLAYBACK_VOLUME_VARIABLE}
824      */
825     @PlaybackVolume
getVolumeHandling()826     public int getVolumeHandling() {
827         return mVolumeHandling;
828     }
829 
830     /**
831      * Gets the maximum volume of the route.
832      */
getVolumeMax()833     public int getVolumeMax() {
834         return mVolumeMax;
835     }
836 
837     /**
838      * Gets the current volume of the route. This may be invalid if the route is not selected.
839      */
getVolume()840     public int getVolume() {
841         return mVolume;
842     }
843 
844     /**
845      * Gets the hardware address of the route if available.
846      * @hide
847      */
848     @Nullable
getAddress()849     public String getAddress() {
850         return mAddress;
851     }
852 
853     /**
854      * Gets the deduplication IDs associated to the route.
855      *
856      * <p>Two routes with a matching deduplication ID originate from the same receiver device.
857      */
858     @NonNull
getDeduplicationIds()859     public Set<String> getDeduplicationIds() {
860         return mDeduplicationIds;
861     }
862 
863     /**
864      * Gets an optional bundle with extra data.
865      */
866     @Nullable
getExtras()867     public Bundle getExtras() {
868         return mExtras == null ? null : new Bundle(mExtras);
869     }
870 
871     /**
872      * Gets the original id set by {@link Builder#Builder(String, CharSequence)}.
873      * @hide
874      */
875     @NonNull
876     @TestApi
getOriginalId()877     public String getOriginalId() {
878         return mId;
879     }
880 
881     /**
882      * Gets the provider id of the route. It is assigned automatically by
883      * {@link com.android.server.media.MediaRouterService}.
884      *
885      * @return provider id of the route or null if it's not set.
886      * @hide
887      */
888     @Nullable
getProviderId()889     public String getProviderId() {
890         return mProviderId;
891     }
892 
893     /**
894      * Returns if the route has at least one of the specified route features.
895      *
896      * @param features the list of route features to consider
897      * @return {@code true} if the route has at least one feature in the list
898      * @hide
899      */
hasAnyFeatures(@onNull Collection<String> features)900     public boolean hasAnyFeatures(@NonNull Collection<String> features) {
901         Objects.requireNonNull(features, "features must not be null");
902         for (String feature : features) {
903             if (getFeatures().contains(feature)) {
904                 return true;
905             }
906         }
907         return false;
908     }
909 
910     /**
911      * Returns if the route has all the specified route features.
912      *
913      * @hide
914      */
hasAllFeatures(@onNull Collection<String> features)915     public boolean hasAllFeatures(@NonNull Collection<String> features) {
916         Objects.requireNonNull(features, "features must not be null");
917         for (String feature : features) {
918             if (!getFeatures().contains(feature)) {
919                 return false;
920             }
921         }
922         return true;
923     }
924 
925     /**
926      * Returns whether this route supports routing of the system media.
927      *
928      * @hide
929      */
supportsSystemMediaRouting()930     public boolean supportsSystemMediaRouting() {
931         return (mRoutingTypeFlags
932                         & (FLAG_ROUTING_TYPE_SYSTEM_VIDEO | FLAG_ROUTING_TYPE_SYSTEM_AUDIO))
933                 != 0;
934     }
935 
936     /**
937      * Returns whether this route supports {@link #FLAG_ROUTING_TYPE_REMOTE remote routing}.
938      *
939      * @hide
940      */
supportsRemoteRouting()941     public boolean supportsRemoteRouting() {
942         return (mRoutingTypeFlags & MediaRoute2Info.FLAG_ROUTING_TYPE_REMOTE) != 0;
943     }
944 
945     /**
946      * Returns true if the route info has all of the required field.
947      * A route is valid if and only if it is obtained from
948      * {@link com.android.server.media.MediaRouterService}.
949      * @hide
950      */
isValid()951     public boolean isValid() {
952         if (TextUtils.isEmpty(getId()) || TextUtils.isEmpty(getName())
953                 || TextUtils.isEmpty(getProviderId())) {
954             return false;
955         }
956         return true;
957     }
958 
959     /**
960      * Returns whether this route is visible to the package with the given name.
961      *
962      * @hide
963      */
isVisibleTo(@onNull String packageName)964     public boolean isVisibleTo(@NonNull String packageName) {
965         return !mIsVisibilityRestricted
966                 || TextUtils.equals(getProviderPackageName(), packageName)
967                 || mAllowedPackages.contains(packageName);
968     }
969 
970     /**
971      * @return a list of permission sets - all the permissions in at least one of these sets must be
972      * held to see this route.
973      */
974     @NonNull
975     @FlaggedApi(FLAG_ENABLE_ROUTE_VISIBILITY_CONTROL_API)
getRequiredPermissions()976     public List<Set<String>> getRequiredPermissions() {
977         return mRequiredPermissions;
978     }
979 
980     /**
981      * Returns whether this route's type can only be published by the system route provider.
982      *
983      * @see #isSystemRoute()
984      * @hide
985      */
986     // The default case catches all other types.
987     @SuppressLint("SwitchIntDef")
isSystemRouteType()988     public boolean isSystemRouteType() {
989         return switch (mType) {
990             case TYPE_BUILTIN_SPEAKER,
991                             TYPE_AUX_LINE,
992                             TYPE_BLUETOOTH_A2DP,
993                             TYPE_DOCK,
994                             TYPE_BLE_HEADSET,
995                             TYPE_HEARING_AID,
996                             TYPE_HDMI,
997                             TYPE_HDMI_ARC,
998                             TYPE_HDMI_EARC,
999                             TYPE_LINE_DIGITAL,
1000                             TYPE_LINE_ANALOG,
1001                             TYPE_USB_ACCESSORY,
1002                             TYPE_USB_DEVICE,
1003                             TYPE_USB_HEADSET,
1004                             TYPE_WIRED_HEADPHONES,
1005                             TYPE_WIRED_HEADSET ->
1006                     true;
1007             default -> false;
1008         };
1009     }
1010 
1011     /** Returns the route suitability status. */
1012     @SuitabilityStatus
1013     @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
getSuitabilityStatus()1014     public int getSuitabilityStatus() {
1015         return mSuitabilityStatus;
1016     }
1017 
1018     /**
1019      * Dumps the current state of the object to the given {@code pw} as a human-readable string.
1020      *
1021      * <p> Used in the context of dumpsys. </p>
1022      *
1023      * @hide
1024      */
dump(@onNull PrintWriter pw, @NonNull String prefix)1025     public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
1026         pw.println(prefix + "MediaRoute2Info");
1027 
1028         String indent = prefix + "  ";
1029 
1030         pw.println(indent + "mId=" + mId);
1031         pw.println(indent + "mName=" + mName);
1032         pw.println(indent + "mFeatures=" + mFeatures);
1033         pw.println(indent + "mType=" + getDeviceTypeString(mType));
1034         pw.println(indent + "mRoutingTypeFlags=" + getRoutingTypeFlagsString(mRoutingTypeFlags));
1035         pw.println(indent + "mIsSystem=" + mIsSystem);
1036         pw.println(indent + "mIconUri=" + mIconUri);
1037         pw.println(indent + "mDescription=" + mDescription);
1038         pw.println(indent + "mConnectionState=" + mConnectionState);
1039         pw.println(indent + "mClientPackageName=" + mClientPackageName);
1040         pw.println(indent + "mProviderPackageName=" + mProviderPackageName);
1041 
1042         dumpVolume(pw, indent);
1043 
1044         pw.println(indent + "mAddress=" + mAddress);
1045         pw.println(indent + "mDeduplicationIds=" + mDeduplicationIds);
1046         pw.println(indent + "mExtras=" + mExtras);
1047         pw.println(indent + "mProviderId=" + mProviderId);
1048         pw.println(indent + "mIsVisibilityRestricted=" + mIsVisibilityRestricted);
1049         pw.println(indent + "mAllowedPackages=" + mAllowedPackages);
1050         pw.println(indent + "mSuitabilityStatus=" + mSuitabilityStatus);
1051         pw.println(indent + "mRequiredPermissions=" + mRequiredPermissions);
1052     }
1053 
dumpVolume(@onNull PrintWriter pw, @NonNull String prefix)1054     private void dumpVolume(@NonNull PrintWriter pw, @NonNull String prefix) {
1055         pw.println(prefix + getVolumeString(mVolume, mVolumeMax, mVolumeHandling));
1056     }
1057 
1058     @Override
equals(Object obj)1059     public boolean equals(Object obj) {
1060         if (this == obj) {
1061             return true;
1062         }
1063         if (!(obj instanceof MediaRoute2Info)) {
1064             return false;
1065         }
1066         MediaRoute2Info other = (MediaRoute2Info) obj;
1067 
1068         // Note: mExtras is not included.
1069         return Objects.equals(mId, other.mId)
1070                 && Objects.equals(mName, other.mName)
1071                 && Objects.equals(mFeatures, other.mFeatures)
1072                 && (mType == other.mType)
1073                 && (mRoutingTypeFlags == other.mRoutingTypeFlags)
1074                 && (mIsSystem == other.mIsSystem)
1075                 && Objects.equals(mIconUri, other.mIconUri)
1076                 && Objects.equals(mDescription, other.mDescription)
1077                 && (mConnectionState == other.mConnectionState)
1078                 && Objects.equals(mClientPackageName, other.mClientPackageName)
1079                 && Objects.equals(mProviderPackageName, other.mProviderPackageName)
1080                 && (mVolumeHandling == other.mVolumeHandling)
1081                 && (mVolumeMax == other.mVolumeMax)
1082                 && (mVolume == other.mVolume)
1083                 && Objects.equals(mAddress, other.mAddress)
1084                 && Objects.equals(mDeduplicationIds, other.mDeduplicationIds)
1085                 && Objects.equals(mProviderId, other.mProviderId)
1086                 && (mIsVisibilityRestricted == other.mIsVisibilityRestricted)
1087                 && Objects.equals(mAllowedPackages, other.mAllowedPackages)
1088                 && Objects.equals(mRequiredPermissions, other.mRequiredPermissions)
1089                 && mSuitabilityStatus == other.mSuitabilityStatus;
1090     }
1091 
1092     @Override
hashCode()1093     public int hashCode() {
1094         // Note: mExtras is not included.
1095         return Objects.hash(
1096                 mId,
1097                 mName,
1098                 mFeatures,
1099                 mType,
1100                 mRoutingTypeFlags,
1101                 mIsSystem,
1102                 mIconUri,
1103                 mDescription,
1104                 mConnectionState,
1105                 mClientPackageName,
1106                 mProviderPackageName,
1107                 mVolumeHandling,
1108                 mVolumeMax,
1109                 mVolume,
1110                 mAddress,
1111                 mDeduplicationIds,
1112                 mProviderId,
1113                 mIsVisibilityRestricted,
1114                 mAllowedPackages,
1115                 mRequiredPermissions,
1116                 mSuitabilityStatus);
1117     }
1118 
1119     @Override
toString()1120     public String toString() {
1121         // Note: mExtras is not printed here.
1122         return new StringBuilder()
1123                 .append("MediaRoute2Info{ ")
1124                 .append("id=")
1125                 .append(getId())
1126                 .append(", name=")
1127                 .append(getName())
1128                 .append(", type=")
1129                 .append(getDeviceTypeString(getType()))
1130                 .append(", routingTypes=")
1131                 .append(getRoutingTypeFlagsString(getSupportedRoutingTypes()))
1132                 .append(", isSystem=")
1133                 .append(isSystemRoute())
1134                 .append(", features=")
1135                 .append(getFeatures())
1136                 .append(", iconUri=")
1137                 .append(getIconUri())
1138                 .append(", description=")
1139                 .append(getDescription())
1140                 .append(", connectionState=")
1141                 .append(getConnectionState())
1142                 .append(", clientPackageName=")
1143                 .append(getClientPackageName())
1144                 .append(", ")
1145                 .append(getVolumeString(mVolume, mVolumeMax, mVolumeHandling))
1146                 .append(", address=")
1147                 .append(getAddress())
1148                 .append(", deduplicationIds=")
1149                 .append(String.join(",", getDeduplicationIds()))
1150                 .append(", providerId=")
1151                 .append(getProviderId())
1152                 .append(", isVisibilityRestricted=")
1153                 .append(mIsVisibilityRestricted)
1154                 .append(", allowedPackages=")
1155                 .append(String.join(",", mAllowedPackages))
1156                 .append(", mRequiredPermissions=")
1157                 .append(mRequiredPermissions.stream().map(set -> String.join(",", set)).collect(
1158                                 Collectors.joining("),(", "(", ")")))
1159                 .append(", suitabilityStatus=")
1160                 .append(mSuitabilityStatus)
1161                 .append(" }")
1162                 .toString();
1163     }
1164 
1165     @Override
describeContents()1166     public int describeContents() {
1167         return 0;
1168     }
1169 
1170     @Override
writeToParcel(@onNull Parcel dest, int flags)1171     public void writeToParcel(@NonNull Parcel dest, int flags) {
1172         dest.writeString(mId);
1173         TextUtils.writeToParcel(mName, dest, flags);
1174         dest.writeStringList(mFeatures);
1175         dest.writeInt(mType);
1176         dest.writeInt(mRoutingTypeFlags);
1177         dest.writeBoolean(mIsSystem);
1178         dest.writeParcelable(mIconUri, flags);
1179         TextUtils.writeToParcel(mDescription, dest, flags);
1180         dest.writeInt(mConnectionState);
1181         dest.writeString(mClientPackageName);
1182         dest.writeString(mProviderPackageName);
1183         dest.writeInt(mVolumeHandling);
1184         dest.writeInt(mVolumeMax);
1185         dest.writeInt(mVolume);
1186         dest.writeString(mAddress);
1187         dest.writeStringArray(mDeduplicationIds.toArray(new String[mDeduplicationIds.size()]));
1188         dest.writeBundle(mExtras);
1189         dest.writeString(mProviderId);
1190         dest.writeBoolean(mIsVisibilityRestricted);
1191         dest.writeString8Array(mAllowedPackages.toArray(new String[0]));
1192         dest.writeInt(mRequiredPermissions.size());
1193         for (Set<String> permissionSet : mRequiredPermissions) {
1194             dest.writeString8Array(permissionSet.toArray(new String[0]));
1195         }
1196         dest.writeInt(mSuitabilityStatus);
1197     }
1198 
1199     /**
1200      * Returns a human readable string describing the given volume values.
1201      *
1202      * @param volume The current volume.
1203      * @param maxVolume The maximum volume.
1204      * @param volumeHandling The {@link PlaybackVolume}.
1205      */
getVolumeString( int volume, int maxVolume, @PlaybackVolume int volumeHandling)1206     /* package */ static String getVolumeString(
1207             int volume, int maxVolume, @PlaybackVolume int volumeHandling) {
1208         String volumeHandlingName;
1209         switch (volumeHandling) {
1210             case PLAYBACK_VOLUME_FIXED:
1211                 volumeHandlingName = "FIXED";
1212                 break;
1213             case PLAYBACK_VOLUME_VARIABLE:
1214                 volumeHandlingName = "VARIABLE";
1215                 break;
1216             default:
1217                 volumeHandlingName = "UNKNOWN";
1218                 break;
1219         }
1220         return String.format(
1221                 Locale.US,
1222                 "volume(current=%d, max=%d, handling=%s(%d))",
1223                 volume,
1224                 maxVolume,
1225                 volumeHandlingName,
1226                 volumeHandling);
1227     }
1228 
getDeviceTypeString(@ype int deviceType)1229     private static String getDeviceTypeString(@Type int deviceType) {
1230         switch (deviceType) {
1231             case TYPE_BUILTIN_SPEAKER:
1232                 return "BUILTIN_SPEAKER";
1233             case TYPE_WIRED_HEADSET:
1234                 return "WIRED_HEADSET";
1235             case TYPE_WIRED_HEADPHONES:
1236                 return "WIRED_HEADPHONES";
1237             case TYPE_BLUETOOTH_A2DP:
1238                 return "BLUETOOTH_A2DP";
1239             case TYPE_HDMI:
1240                 return "HDMI";
1241             case TYPE_HDMI_ARC:
1242                 return "HDMI_ARC";
1243             case TYPE_HDMI_EARC:
1244                 return "HDMI_EARC";
1245             case TYPE_LINE_DIGITAL:
1246                 return "LINE_DIGITAL";
1247             case TYPE_LINE_ANALOG:
1248                 return "LINE_ANALOG";
1249             case TYPE_AUX_LINE:
1250                 return "AUX_LINE";
1251             case TYPE_DOCK:
1252                 return "DOCK";
1253             case TYPE_USB_DEVICE:
1254                 return "USB_DEVICE";
1255             case TYPE_USB_ACCESSORY:
1256                 return "USB_ACCESSORY";
1257             case TYPE_USB_HEADSET:
1258                 return "USB_HEADSET";
1259             case TYPE_HEARING_AID:
1260                 return "HEARING_AID";
1261             case TYPE_REMOTE_TV:
1262                 return "REMOTE_TV";
1263             case TYPE_REMOTE_SPEAKER:
1264                 return "REMOTE_SPEAKER";
1265             case TYPE_REMOTE_AUDIO_VIDEO_RECEIVER:
1266                 return "REMOTE_AUDIO_VIDEO_RECEIVER";
1267             case TYPE_REMOTE_TABLET:
1268                 return "REMOTE_TABLET";
1269             case TYPE_REMOTE_TABLET_DOCKED:
1270                 return "REMOTE_TABLET_DOCKED";
1271             case TYPE_REMOTE_COMPUTER:
1272                 return "REMOTE_COMPUTER";
1273             case TYPE_REMOTE_GAME_CONSOLE:
1274                 return "REMOTE_GAME_CONSOLE";
1275             case TYPE_REMOTE_CAR:
1276                 return "REMOTE_CAR";
1277             case TYPE_REMOTE_SMARTWATCH:
1278                 return "REMOTE_SMARTWATCH";
1279             case TYPE_REMOTE_SMARTPHONE:
1280                 return "REMOTE_SMARTPHONE";
1281             case TYPE_GROUP:
1282                 return "GROUP";
1283             case TYPE_UNKNOWN:
1284             default:
1285                 return TextUtils.formatSimple("UNKNOWN(%d)", deviceType);
1286         }
1287     }
1288 
1289     /** Returns a human-readable representation of the given {@code routingTypeFlags}. */
getRoutingTypeFlagsString(@outingType int routingTypeFlags)1290     private static String getRoutingTypeFlagsString(@RoutingType int routingTypeFlags) {
1291         List<String> typeStrings = new ArrayList<>();
1292         if ((routingTypeFlags & FLAG_ROUTING_TYPE_SYSTEM_AUDIO) != 0) {
1293             typeStrings.add("SYSTEM_AUDIO");
1294         }
1295         if ((routingTypeFlags & FLAG_ROUTING_TYPE_SYSTEM_VIDEO) != 0) {
1296             typeStrings.add("SYSTEM_VIDEO");
1297         }
1298         if ((routingTypeFlags & FLAG_ROUTING_TYPE_REMOTE) != 0) {
1299             typeStrings.add("REMOTE");
1300         }
1301         return String.join(/* delimiter= */ "|", typeStrings);
1302     }
1303 
1304     /**
1305      * Throws an {@link IllegalArgumentException} if the provided {@code routingTypeFlags} are not
1306      * valid. Otherwise, returns the provided value.
1307      */
validateRoutingTypeFlags(@outingType int routingTypeFlags)1308     private static int validateRoutingTypeFlags(@RoutingType int routingTypeFlags) {
1309         if (routingTypeFlags == 0 || (routingTypeFlags & ~FLAG_ROUTING_TYPE_ALL) != 0) {
1310             throw new IllegalArgumentException(
1311                     "Invalid routing type flags: " + Integer.toHexString(routingTypeFlags));
1312         } else {
1313             return routingTypeFlags;
1314         }
1315     }
1316 
1317     /**
1318      * Builder for {@link MediaRoute2Info media route info}.
1319      */
1320     public static final class Builder {
1321         private final String mId;
1322         private final CharSequence mName;
1323         private final List<String> mFeatures;
1324 
1325         @Type
1326         private int mType = TYPE_UNKNOWN;
1327         @RoutingType private int mRoutingTypeFlags = FLAG_ROUTING_TYPE_REMOTE;
1328         private boolean mIsSystem;
1329         private Uri mIconUri;
1330         private CharSequence mDescription;
1331         @ConnectionState
1332         private int mConnectionState;
1333         private String mClientPackageName;
1334         private String mProviderPackageName;
1335         @PlaybackVolume private int mVolumeHandling = PLAYBACK_VOLUME_FIXED;
1336         private int mVolumeMax;
1337         private int mVolume;
1338         private String mAddress;
1339         private Set<String> mDeduplicationIds;
1340         private Bundle mExtras;
1341         private String mProviderId;
1342         private boolean mIsVisibilityRestricted;
1343         private Set<String> mAllowedPackages;
1344         private List<Set<String>> mRequiredPermissions;
1345         @SuitabilityStatus private int mSuitabilityStatus;
1346 
1347         /**
1348          * Constructor for builder to create {@link MediaRoute2Info}.
1349          * <p>
1350          * In order to ensure ID uniqueness, the {@link MediaRoute2Info#getId() ID} of a route info
1351          * obtained from {@link MediaRouter2} can be different from what was set in
1352          * {@link MediaRoute2ProviderService}.
1353          * </p>
1354          * @param id The ID of the route. Must not be empty.
1355          * @param name The user-visible name of the route.
1356          */
Builder(@onNull String id, @NonNull CharSequence name)1357         public Builder(@NonNull String id, @NonNull CharSequence name) {
1358             if (TextUtils.isEmpty(id)) {
1359                 throw new IllegalArgumentException("id must not be empty");
1360             }
1361             if (TextUtils.isEmpty(name)) {
1362                 throw new IllegalArgumentException("name must not be empty");
1363             }
1364             mId = id;
1365             mName = name;
1366             mFeatures = new ArrayList<>();
1367             mDeduplicationIds = Set.of();
1368             mAllowedPackages = Set.of();
1369             mSuitabilityStatus = SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER;
1370             mRequiredPermissions = List.of();
1371         }
1372 
1373         /**
1374          * Constructor for builder to create {@link MediaRoute2Info} with existing
1375          * {@link MediaRoute2Info} instance.
1376          *
1377          * @param routeInfo the existing instance to copy data from.
1378          */
Builder(@onNull MediaRoute2Info routeInfo)1379         public Builder(@NonNull MediaRoute2Info routeInfo) {
1380             this(routeInfo.mId, routeInfo);
1381         }
1382 
1383         /**
1384          * Constructor for builder to create {@link MediaRoute2Info} with existing
1385          * {@link MediaRoute2Info} instance and replace ID with the given {@code id}.
1386          *
1387          * @param id The ID of the new route. Must not be empty.
1388          * @param routeInfo the existing instance to copy data from.
1389          * @hide
1390          */
Builder(@onNull String id, @NonNull MediaRoute2Info routeInfo)1391         public Builder(@NonNull String id, @NonNull MediaRoute2Info routeInfo) {
1392             if (TextUtils.isEmpty(id)) {
1393                 throw new IllegalArgumentException("id must not be empty");
1394             }
1395             Objects.requireNonNull(routeInfo, "routeInfo must not be null");
1396 
1397             mId = id;
1398             mName = routeInfo.mName;
1399             mFeatures = new ArrayList<>(routeInfo.mFeatures);
1400             mType = routeInfo.mType;
1401             mRoutingTypeFlags = routeInfo.mRoutingTypeFlags;
1402             mIsSystem = routeInfo.mIsSystem;
1403             mIconUri = routeInfo.mIconUri;
1404             mDescription = routeInfo.mDescription;
1405             mConnectionState = routeInfo.mConnectionState;
1406             mClientPackageName = routeInfo.mClientPackageName;
1407             mProviderPackageName = routeInfo.mProviderPackageName;
1408             mVolumeHandling = routeInfo.mVolumeHandling;
1409             mVolumeMax = routeInfo.mVolumeMax;
1410             mVolume = routeInfo.mVolume;
1411             mAddress = routeInfo.mAddress;
1412             mDeduplicationIds = Set.copyOf(routeInfo.mDeduplicationIds);
1413             if (routeInfo.mExtras != null) {
1414                 mExtras = new Bundle(routeInfo.mExtras);
1415             }
1416             mProviderId = routeInfo.mProviderId;
1417             mIsVisibilityRestricted = routeInfo.mIsVisibilityRestricted;
1418             mAllowedPackages = routeInfo.mAllowedPackages;
1419             mSuitabilityStatus = routeInfo.mSuitabilityStatus;
1420             mRequiredPermissions = routeInfo.mRequiredPermissions;
1421         }
1422 
1423         /**
1424          * Adds a feature for the route.
1425          * @param feature a feature that the route has. May be one of predefined features
1426          *                such as {@link #FEATURE_LIVE_AUDIO}, {@link #FEATURE_LIVE_VIDEO} or
1427          *                {@link #FEATURE_REMOTE_PLAYBACK} or a custom feature defined by
1428          *                a provider.
1429          *
1430          * @see #addFeatures(Collection)
1431          */
1432         @NonNull
addFeature(@onNull String feature)1433         public Builder addFeature(@NonNull String feature) {
1434             if (TextUtils.isEmpty(feature)) {
1435                 throw new IllegalArgumentException("feature must not be null or empty");
1436             }
1437             mFeatures.add(feature);
1438             return this;
1439         }
1440 
1441         /**
1442          * Adds features for the route. A route must support at least one route type.
1443          * @param features features that the route has. May include predefined features
1444          *                such as {@link #FEATURE_LIVE_AUDIO}, {@link #FEATURE_LIVE_VIDEO} or
1445          *                {@link #FEATURE_REMOTE_PLAYBACK} or custom features defined by
1446          *                a provider.
1447          *
1448          * @see #addFeature(String)
1449          */
1450         @NonNull
addFeatures(@onNull Collection<String> features)1451         public Builder addFeatures(@NonNull Collection<String> features) {
1452             Objects.requireNonNull(features, "features must not be null");
1453             for (String feature : features) {
1454                 addFeature(feature);
1455             }
1456             return this;
1457         }
1458 
1459         /**
1460          * Clears the features of the route. A route must support at least one route type.
1461          */
1462         @NonNull
clearFeatures()1463         public Builder clearFeatures() {
1464             mFeatures.clear();
1465             return this;
1466         }
1467 
1468         /**
1469          * Sets the route's type.
1470          *
1471          * @see MediaRoute2Info#getType()
1472          */
1473         @NonNull
setType(@ype int type)1474         public Builder setType(@Type int type) {
1475             mType = type;
1476             return this;
1477         }
1478 
1479         /**
1480          * Sets the routing types that this route supports.
1481          *
1482          * @see MediaRoute2Info#getSupportedRoutingTypes()
1483          */
1484         @NonNull
1485         @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
setSupportedRoutingTypes(@outingType int routingTypeFlags)1486         public Builder setSupportedRoutingTypes(@RoutingType int routingTypeFlags) {
1487             mRoutingTypeFlags = validateRoutingTypeFlags(routingTypeFlags);
1488             return this;
1489         }
1490 
1491         /**
1492          * Sets whether the route is a system route or not.
1493          * @hide
1494          */
1495         @NonNull
setSystemRoute(boolean isSystem)1496         public Builder setSystemRoute(boolean isSystem) {
1497             mIsSystem = isSystem;
1498             return this;
1499         }
1500 
1501         /**
1502          * Sets the URI of the icon representing this route.
1503          * <p>
1504          * This icon will be used in picker UIs if available.
1505          * </p><p>
1506          * The URI must be one of the following formats:
1507          * <ul>
1508          * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
1509          * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
1510          * </li>
1511          * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
1512          * </ul>
1513          * </p>
1514          */
1515         @NonNull
setIconUri(@ullable Uri iconUri)1516         public Builder setIconUri(@Nullable Uri iconUri) {
1517             mIconUri = iconUri;
1518             return this;
1519         }
1520 
1521         /**
1522          * Sets the user-visible description of the route.
1523          */
1524         @NonNull
setDescription(@ullable CharSequence description)1525         public Builder setDescription(@Nullable CharSequence description) {
1526             mDescription = description;
1527             return this;
1528         }
1529 
1530         /**
1531         * Sets the route's connection state.
1532         *
1533         * {@link #CONNECTION_STATE_DISCONNECTED},
1534         * {@link #CONNECTION_STATE_CONNECTING}, or
1535         * {@link #CONNECTION_STATE_CONNECTED}.
1536         */
1537         @NonNull
setConnectionState(@onnectionState int connectionState)1538         public Builder setConnectionState(@ConnectionState int connectionState) {
1539             mConnectionState = connectionState;
1540             return this;
1541         }
1542 
1543         /**
1544          * Sets the package name of the app using the route.
1545          */
1546         @NonNull
setClientPackageName(@ullable String packageName)1547         public Builder setClientPackageName(@Nullable String packageName) {
1548             mClientPackageName = packageName;
1549             return this;
1550         }
1551 
1552         /**
1553          * Sets the package name of the route.
1554          *
1555          * @hide
1556          */
1557         // It is set by the MediaRouterService.
1558         @NonNull
setProviderPackageName(@onNull String providerPackageName)1559         public Builder setProviderPackageName(@NonNull String providerPackageName) {
1560             mProviderPackageName = providerPackageName;
1561             return this;
1562         }
1563 
1564         /**
1565          * Sets the route's volume handling.
1566          */
1567         @NonNull
setVolumeHandling(@laybackVolume int volumeHandling)1568         public Builder setVolumeHandling(@PlaybackVolume int volumeHandling) {
1569             mVolumeHandling = volumeHandling;
1570             return this;
1571         }
1572 
1573         /**
1574          * Sets the route's maximum volume, or 0 if unknown.
1575          */
1576         @NonNull
setVolumeMax(int volumeMax)1577         public Builder setVolumeMax(int volumeMax) {
1578             mVolumeMax = volumeMax;
1579             return this;
1580         }
1581 
1582         /**
1583          * Sets the route's current volume, or 0 if unknown.
1584          */
1585         @NonNull
setVolume(int volume)1586         public Builder setVolume(int volume) {
1587             mVolume = volume;
1588             return this;
1589         }
1590 
1591         /**
1592          * Sets the hardware address of the route.
1593          * @hide
1594          */
1595         @NonNull
setAddress(String address)1596         public Builder setAddress(String address) {
1597             mAddress = address;
1598             return this;
1599         }
1600 
1601         /**
1602          * Sets the {@link MediaRoute2Info#getDeduplicationIds() deduplication IDs} of the route.
1603          */
1604         @NonNull
setDeduplicationIds(@onNull Set<String> id)1605         public Builder setDeduplicationIds(@NonNull Set<String> id) {
1606             mDeduplicationIds = Set.copyOf(id);
1607             return this;
1608         }
1609 
1610         /**
1611          * Sets a bundle of extras for the route.
1612          * <p>
1613          * Note: The extras will not affect the result of {@link MediaRoute2Info#equals(Object)}.
1614          */
1615         @NonNull
setExtras(@ullable Bundle extras)1616         public Builder setExtras(@Nullable Bundle extras) {
1617             if (extras == null) {
1618                 mExtras = null;
1619                 return this;
1620             }
1621             mExtras = new Bundle(extras);
1622             return this;
1623         }
1624 
1625         /**
1626          * Sets the provider id of the route.
1627          * @hide
1628          */
1629         @NonNull
setProviderId(@onNull String providerId)1630         public Builder setProviderId(@NonNull String providerId) {
1631             if (TextUtils.isEmpty(providerId)) {
1632                 throw new IllegalArgumentException("providerId must not be null or empty");
1633             }
1634             mProviderId = providerId;
1635             return this;
1636         }
1637 
1638         /**
1639          * Sets the visibility of this route to public.
1640          *
1641          * <p>By default, unless you call {@link #setVisibilityRestricted}, the new route will be
1642          * public.
1643          *
1644          * <p>Public routes are visible to any application with a matching {@link
1645          * RouteDiscoveryPreference#getPreferredFeatures feature}.
1646          *
1647          * <p>Calls to this method override previous calls to {@link #setVisibilityPublic} and
1648          * {@link #setVisibilityRestricted}.
1649          */
1650         @NonNull
setVisibilityPublic()1651         public Builder setVisibilityPublic() {
1652             mIsVisibilityRestricted = false;
1653             mAllowedPackages = Set.of();
1654             mRequiredPermissions = List.of();
1655             return this;
1656         }
1657 
1658         /**
1659          * Sets the visibility of this route to restricted.
1660          *
1661          * <p>Routes with restricted visibility are only visible to its publisher application and
1662          * applications whose package name is included in the provided {@code allowedPackages} set
1663          * with a matching {@link RouteDiscoveryPreference#getPreferredFeatures feature}.
1664          *
1665          * <p>Calls to this method override previous calls to {@link #setVisibilityPublic} and
1666          * {@link #setVisibilityRestricted}.
1667          *
1668          * @see #setVisibilityPublic
1669          * @param allowedPackages set of package names which are allowed to see this route.
1670          */
1671         @NonNull
setVisibilityRestricted(@onNull Set<String> allowedPackages)1672         public Builder setVisibilityRestricted(@NonNull Set<String> allowedPackages) {
1673             mIsVisibilityRestricted = true;
1674             mAllowedPackages = Set.copyOf(allowedPackages);
1675             return this;
1676         }
1677 
1678         /**
1679          * Limits the visibility of this route to holders of a set of permissions.
1680          *
1681          * <p>Calls to this method override any previous calls of
1682          * {@link #setRequiredPermissions(Set)} or {@link #setRequiredPermissions(List)}.
1683          *
1684          * @param requiredPermissions the list of all permissions which must be held in order to
1685          *                            see this route.
1686          */
1687         @NonNull
1688         @FlaggedApi(FLAG_ENABLE_ROUTE_VISIBILITY_CONTROL_API)
setRequiredPermissions(@onNull Set<String> requiredPermissions)1689         public Builder setRequiredPermissions(@NonNull Set<String> requiredPermissions) {
1690             return setRequiredPermissions(List.of(requiredPermissions));
1691         }
1692 
1693         /**
1694          * Limits the visibility of this route to holders of one of a set of permissions.
1695          *
1696          * <p>Calls to this method override any previous calls of
1697          * {@link #setRequiredPermissions(Set)} or {@link #setRequiredPermissions(List)}.
1698          *
1699          * @param requiresOneOf a list of Sets of permissions. Holding all permissions in at least
1700          *                      one of the Sets is required for the route to be visible.
1701          */
1702         @NonNull
1703         @FlaggedApi(FLAG_ENABLE_ROUTE_VISIBILITY_CONTROL_API)
setRequiredPermissions(@onNull List<Set<String>> requiresOneOf)1704         public Builder setRequiredPermissions(@NonNull List<Set<String>> requiresOneOf) {
1705             mRequiredPermissions = List.copyOf(requiresOneOf);
1706             return this;
1707         }
1708 
1709         /**
1710          * Sets route suitability status.
1711          *
1712          * <p>The default value is {@link
1713          * MediaRoute2Info#SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER}.
1714          *
1715          * <p> Apps are not supposed to set {@link
1716          * MediaRoute2Info#SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER}. Publishing a non-system
1717          * route with such status throws {@link SecurityException}.
1718          */
1719         @NonNull
1720         @FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
setSuitabilityStatus(@uitabilityStatus int suitabilityStatus)1721         public Builder setSuitabilityStatus(@SuitabilityStatus int suitabilityStatus) {
1722             mSuitabilityStatus = suitabilityStatus;
1723             return this;
1724         }
1725 
1726         /**
1727          * Builds the {@link MediaRoute2Info media route info}.
1728          *
1729          * @throws IllegalArgumentException if no features are added.
1730          */
1731         @NonNull
build()1732         public MediaRoute2Info build() {
1733             if (mFeatures.isEmpty()) {
1734                 throw new IllegalArgumentException("features must not be empty!");
1735             }
1736             return new MediaRoute2Info(this);
1737         }
1738     }
1739 }
1740