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.e. 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