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 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.TestApi; 25 import android.net.Uri; 26 import android.os.Bundle; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 import android.text.TextUtils; 30 31 import com.android.internal.util.Preconditions; 32 33 import java.io.PrintWriter; 34 import java.lang.annotation.Retention; 35 import java.lang.annotation.RetentionPolicy; 36 import java.util.ArrayList; 37 import java.util.Collection; 38 import java.util.List; 39 import java.util.Locale; 40 import java.util.Objects; 41 import java.util.Set; 42 43 /** 44 * Describes the properties of a route. 45 */ 46 public final class MediaRoute2Info implements Parcelable { 47 @NonNull 48 public static final Creator<MediaRoute2Info> CREATOR = new Creator<MediaRoute2Info>() { 49 @Override 50 public MediaRoute2Info createFromParcel(Parcel in) { 51 return new MediaRoute2Info(in); 52 } 53 54 @Override 55 public MediaRoute2Info[] newArray(int size) { 56 return new MediaRoute2Info[size]; 57 } 58 }; 59 60 /** 61 * The {@link #getOriginalId() original id} of the route that represents the built-in media 62 * route. 63 * 64 * <p>A route with this id will only be visible to apps with permission to do system routing, 65 * which means having {@link android.Manifest.permission#BLUETOOTH_CONNECT} and {@link 66 * android.Manifest.permission#BLUETOOTH_SCAN}, or {@link 67 * android.Manifest.permission#MODIFY_AUDIO_ROUTING}. 68 * 69 * @hide 70 */ 71 public static final String ROUTE_ID_DEVICE = "DEVICE_ROUTE"; 72 73 /** 74 * The {@link #getOriginalId() original id} of the route that represents the default system 75 * media route. 76 * 77 * <p>A route with this id will be visible to apps with no permission over system routing. See 78 * {@link #ROUTE_ID_DEVICE} for details. 79 * 80 * @hide 81 */ 82 public static final String ROUTE_ID_DEFAULT = "DEFAULT_ROUTE"; 83 84 /** @hide */ 85 @IntDef({CONNECTION_STATE_DISCONNECTED, CONNECTION_STATE_CONNECTING, 86 CONNECTION_STATE_CONNECTED}) 87 @Retention(RetentionPolicy.SOURCE) 88 public @interface ConnectionState {} 89 90 /** 91 * The default connection state indicating the route is disconnected. 92 * 93 * @see #getConnectionState 94 */ 95 public static final int CONNECTION_STATE_DISCONNECTED = 0; 96 97 /** 98 * A connection state indicating the route is in the process of connecting and is not yet 99 * ready for use. 100 * 101 * @see #getConnectionState 102 */ 103 public static final int CONNECTION_STATE_CONNECTING = 1; 104 105 /** 106 * A connection state indicating the route is connected. 107 * 108 * @see #getConnectionState 109 */ 110 public static final int CONNECTION_STATE_CONNECTED = 2; 111 112 /** @hide */ 113 @IntDef({PLAYBACK_VOLUME_FIXED, PLAYBACK_VOLUME_VARIABLE}) 114 @Retention(RetentionPolicy.SOURCE) 115 public @interface PlaybackVolume {} 116 117 /** 118 * Playback information indicating the playback volume is fixed, i.e. it cannot be 119 * controlled from this object. An example of fixed playback volume is a remote player, 120 * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 121 * than attenuate at the source. 122 * 123 * @see #getVolumeHandling() 124 */ 125 public static final int PLAYBACK_VOLUME_FIXED = 0; 126 /** 127 * Playback information indicating the playback volume is variable and can be controlled 128 * from this object. 129 * 130 * @see #getVolumeHandling() 131 */ 132 public static final int PLAYBACK_VOLUME_VARIABLE = 1; 133 134 /** @hide */ 135 @IntDef( 136 prefix = {"TYPE_"}, 137 value = { 138 TYPE_UNKNOWN, 139 TYPE_BUILTIN_SPEAKER, 140 TYPE_WIRED_HEADSET, 141 TYPE_WIRED_HEADPHONES, 142 TYPE_BLUETOOTH_A2DP, 143 TYPE_HDMI, 144 TYPE_USB_DEVICE, 145 TYPE_USB_ACCESSORY, 146 TYPE_DOCK, 147 TYPE_USB_HEADSET, 148 TYPE_HEARING_AID, 149 TYPE_BLE_HEADSET, 150 TYPE_REMOTE_TV, 151 TYPE_REMOTE_SPEAKER, 152 TYPE_REMOTE_AUDIO_VIDEO_RECEIVER, 153 TYPE_REMOTE_TABLET, 154 TYPE_REMOTE_TABLET_DOCKED, 155 TYPE_REMOTE_COMPUTER, 156 TYPE_REMOTE_GAME_CONSOLE, 157 TYPE_REMOTE_CAR, 158 TYPE_REMOTE_SMARTWATCH, 159 TYPE_REMOTE_SMARTPHONE, 160 TYPE_GROUP 161 }) 162 @Retention(RetentionPolicy.SOURCE) 163 public @interface Type {} 164 165 /** 166 * Indicates the route's type is unknown or undefined. 167 * 168 * @see #getType 169 */ 170 public static final int TYPE_UNKNOWN = 0; 171 172 /** 173 * Indicates the route is the speaker system (i.e. a mono speaker or stereo speakers) built into 174 * the device. 175 * 176 * @see #getType 177 */ 178 public static final int TYPE_BUILTIN_SPEAKER = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; 179 180 /** 181 * Indicates the route is a headset, which is the combination of a headphones and a microphone. 182 * 183 * @see #getType 184 */ 185 public static final int TYPE_WIRED_HEADSET = AudioDeviceInfo.TYPE_WIRED_HEADSET; 186 187 /** 188 * Indicates the route is a pair of wired headphones. 189 * 190 * @see #getType 191 */ 192 public static final int TYPE_WIRED_HEADPHONES = AudioDeviceInfo.TYPE_WIRED_HEADPHONES; 193 194 /** 195 * Indicates the route is a bluetooth device, such as a bluetooth speaker or headphones. 196 * 197 * @see #getType 198 */ 199 public static final int TYPE_BLUETOOTH_A2DP = AudioDeviceInfo.TYPE_BLUETOOTH_A2DP; 200 201 /** 202 * Indicates the route is an HDMI connection. 203 * 204 * @see #getType 205 */ 206 public static final int TYPE_HDMI = AudioDeviceInfo.TYPE_HDMI; 207 208 /** 209 * Indicates the route is a USB audio device. 210 * 211 * @see #getType 212 */ 213 public static final int TYPE_USB_DEVICE = AudioDeviceInfo.TYPE_USB_DEVICE; 214 215 /** 216 * Indicates the route is a USB audio device in accessory mode. 217 * 218 * @see #getType 219 */ 220 public static final int TYPE_USB_ACCESSORY = AudioDeviceInfo.TYPE_USB_ACCESSORY; 221 222 /** 223 * Indicates the route is the audio device associated with a dock. 224 * 225 * @see #getType 226 */ 227 public static final int TYPE_DOCK = AudioDeviceInfo.TYPE_DOCK; 228 229 /** 230 * Indicates the route is a USB audio headset. 231 * 232 * @see #getType 233 */ 234 public static final int TYPE_USB_HEADSET = AudioDeviceInfo.TYPE_USB_HEADSET; 235 236 /** 237 * Indicates the route is a hearing aid. 238 * 239 * @see #getType 240 */ 241 public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID; 242 243 /** 244 * Indicates the route is a Bluetooth Low Energy (BLE) HEADSET. 245 * 246 * @see #getType 247 */ 248 public static final int TYPE_BLE_HEADSET = AudioDeviceInfo.TYPE_BLE_HEADSET; 249 250 /** 251 * Indicates the route is a remote TV. 252 * 253 * <p>A remote device uses a routing protocol managed by the application, as opposed to the 254 * routing being done by the system. 255 * 256 * @see #getType 257 */ 258 public static final int TYPE_REMOTE_TV = 1001; 259 260 /** 261 * Indicates the route is a remote speaker. 262 * 263 * <p>A remote device uses a routing protocol managed by the application, as opposed to the 264 * routing being done by the system. 265 * 266 * @see #getType 267 */ 268 public static final int TYPE_REMOTE_SPEAKER = 1002; 269 270 /** 271 * Indicates the route is a remote Audio/Video Receiver (AVR). 272 * 273 * <p>A remote device uses a routing protocol managed by the application, as opposed to the 274 * routing being done by the system. 275 * 276 * @see #getType 277 */ 278 public static final int TYPE_REMOTE_AUDIO_VIDEO_RECEIVER = 1003; 279 280 /** 281 * Indicates the route is a remote tablet. 282 * 283 * <p>A remote device uses a routing protocol managed by the application, as opposed to the 284 * routing being done by the system. 285 * 286 * @see #getType 287 * @hide 288 */ 289 public static final int TYPE_REMOTE_TABLET = 1004; 290 291 /** 292 * Indicates the route is a remote docked tablet. 293 * 294 * <p>A remote device uses a routing protocol managed by the application, as opposed to the 295 * routing being done by the system. 296 * 297 * @see #getType 298 * @hide 299 */ 300 public static final int TYPE_REMOTE_TABLET_DOCKED = 1005; 301 302 /** 303 * Indicates the route is a remote computer. 304 * 305 * <p>A remote device uses a routing protocol managed by the application, as opposed to the 306 * routing being done by the system. 307 * 308 * @see #getType 309 * @hide 310 */ 311 public static final int TYPE_REMOTE_COMPUTER = 1006; 312 313 /** 314 * Indicates the route is a remote gaming console. 315 * 316 * <p>A remote device uses a routing protocol managed by the application, as opposed to the 317 * routing being done by the system. 318 * 319 * @see #getType 320 * @hide 321 */ 322 public static final int TYPE_REMOTE_GAME_CONSOLE = 1007; 323 324 /** 325 * Indicates the route is a remote car. 326 * 327 * <p>A remote device uses a routing protocol managed by the application, as opposed to the 328 * routing being done by the system. 329 * 330 * @see #getType 331 * @hide 332 */ 333 public static final int TYPE_REMOTE_CAR = 1008; 334 335 /** 336 * Indicates the route is a remote smartwatch. 337 * 338 * <p>A remote device uses a routing protocol managed by the application, as opposed to the 339 * routing being done by the system. 340 * 341 * @see #getType 342 * @hide 343 */ 344 public static final int TYPE_REMOTE_SMARTWATCH = 1009; 345 346 /** 347 * Indicates the route is a remote smartphone. 348 * 349 * <p>A remote device uses a routing protocol managed by the application, as opposed to the 350 * routing being done by the system. 351 * 352 * @see #getType 353 * @hide 354 */ 355 public static final int TYPE_REMOTE_SMARTPHONE = 1010; 356 357 /** 358 * Indicates the route is a group of devices. 359 * 360 * @see #getType 361 */ 362 public static final int TYPE_GROUP = 2000; 363 364 /** 365 * Route feature: Live audio. 366 * <p> 367 * A route that supports live audio routing will allow the media audio stream 368 * to be sent to supported destinations. This can include internal speakers or 369 * audio jacks on the device itself, A2DP devices, and more. 370 * </p><p> 371 * When a live audio route is selected, audio routing is transparent to the application. 372 * All audio played on the media stream will be routed to the selected destination. 373 * </p><p> 374 * Refer to the class documentation for details about live audio routes. 375 * </p> 376 */ 377 public static final String FEATURE_LIVE_AUDIO = "android.media.route.feature.LIVE_AUDIO"; 378 379 /** 380 * Route feature: Live video. 381 * <p> 382 * A route that supports live video routing will allow a mirrored version 383 * of the device's primary display or a customized 384 * {@link android.app.Presentation Presentation} to be sent to supported 385 * destinations. 386 * </p><p> 387 * When a live video route is selected, audio and video routing is transparent 388 * to the application. By default, audio and video is routed to the selected 389 * destination. For certain live video routes, the application may also use a 390 * {@link android.app.Presentation Presentation} to replace the mirrored view 391 * on the external display with different content. 392 * </p><p> 393 * Refer to the class documentation for details about live video routes. 394 * </p> 395 * 396 * @see android.app.Presentation 397 */ 398 public static final String FEATURE_LIVE_VIDEO = "android.media.route.feature.LIVE_VIDEO"; 399 400 /** 401 * Route feature: Local playback. 402 * @hide 403 */ 404 public static final String FEATURE_LOCAL_PLAYBACK = 405 "android.media.route.feature.LOCAL_PLAYBACK"; 406 407 /** 408 * Route feature: Remote playback. 409 * <p> 410 * A route that supports remote playback routing will allow an application to send 411 * requests to play content remotely to supported destinations. 412 * A route may only support {@link #FEATURE_REMOTE_AUDIO_PLAYBACK audio playback} or 413 * {@link #FEATURE_REMOTE_VIDEO_PLAYBACK video playback}. 414 * </p><p> 415 * Remote playback routes destinations operate independently of the local device. 416 * When a remote playback route is selected, the application can control the content 417 * playing on the destination using {@link MediaRouter2.RoutingController#getControlHints()}. 418 * The application may also receive status updates from the route regarding remote playback. 419 * </p><p> 420 * Refer to the class documentation for details about remote playback routes. 421 * </p> 422 * @see #FEATURE_REMOTE_AUDIO_PLAYBACK 423 * @see #FEATURE_REMOTE_VIDEO_PLAYBACK 424 */ 425 public static final String FEATURE_REMOTE_PLAYBACK = 426 "android.media.route.feature.REMOTE_PLAYBACK"; 427 428 /** 429 * Route feature: Remote audio playback. 430 * <p> 431 * A route that supports remote audio playback routing will allow an application to send 432 * requests to play audio content remotely to supported destinations. 433 * 434 * @see #FEATURE_REMOTE_PLAYBACK 435 * @see #FEATURE_REMOTE_VIDEO_PLAYBACK 436 */ 437 public static final String FEATURE_REMOTE_AUDIO_PLAYBACK = 438 "android.media.route.feature.REMOTE_AUDIO_PLAYBACK"; 439 440 /** 441 * Route feature: Remote video playback. 442 * <p> 443 * A route that supports remote video playback routing will allow an application to send 444 * requests to play video content remotely to supported destinations. 445 * 446 * @see #FEATURE_REMOTE_PLAYBACK 447 * @see #FEATURE_REMOTE_AUDIO_PLAYBACK 448 */ 449 public static final String FEATURE_REMOTE_VIDEO_PLAYBACK = 450 "android.media.route.feature.REMOTE_VIDEO_PLAYBACK"; 451 452 /** 453 * Route feature: Remote group playback. 454 * <p> 455 * @hide 456 */ 457 public static final String FEATURE_REMOTE_GROUP_PLAYBACK = 458 "android.media.route.feature.REMOTE_GROUP_PLAYBACK"; 459 460 final String mId; 461 final CharSequence mName; 462 final List<String> mFeatures; 463 @Type 464 final int mType; 465 final boolean mIsSystem; 466 final Uri mIconUri; 467 final CharSequence mDescription; 468 @ConnectionState 469 final int mConnectionState; 470 final String mClientPackageName; 471 final String mPackageName; 472 final int mVolumeHandling; 473 final int mVolumeMax; 474 final int mVolume; 475 final String mAddress; 476 final Set<String> mDeduplicationIds; 477 final Bundle mExtras; 478 final String mProviderId; 479 final boolean mIsVisibilityRestricted; 480 final Set<String> mAllowedPackages; 481 MediaRoute2Info(@onNull Builder builder)482 MediaRoute2Info(@NonNull Builder builder) { 483 mId = builder.mId; 484 mName = builder.mName; 485 mFeatures = builder.mFeatures; 486 mType = builder.mType; 487 mIsSystem = builder.mIsSystem; 488 mIconUri = builder.mIconUri; 489 mDescription = builder.mDescription; 490 mConnectionState = builder.mConnectionState; 491 mClientPackageName = builder.mClientPackageName; 492 mPackageName = builder.mPackageName; 493 mVolumeHandling = builder.mVolumeHandling; 494 mVolumeMax = builder.mVolumeMax; 495 mVolume = builder.mVolume; 496 mAddress = builder.mAddress; 497 mDeduplicationIds = builder.mDeduplicationIds; 498 mExtras = builder.mExtras; 499 mProviderId = builder.mProviderId; 500 mIsVisibilityRestricted = builder.mIsVisibilityRestricted; 501 mAllowedPackages = builder.mAllowedPackages; 502 } 503 MediaRoute2Info(@onNull Parcel in)504 MediaRoute2Info(@NonNull Parcel in) { 505 mId = in.readString(); 506 Preconditions.checkArgument(!TextUtils.isEmpty(mId)); 507 mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 508 mFeatures = in.createStringArrayList(); 509 mType = in.readInt(); 510 mIsSystem = in.readBoolean(); 511 mIconUri = in.readParcelable(null, android.net.Uri.class); 512 mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 513 mConnectionState = in.readInt(); 514 mClientPackageName = in.readString(); 515 mPackageName = in.readString(); 516 mVolumeHandling = in.readInt(); 517 mVolumeMax = in.readInt(); 518 mVolume = in.readInt(); 519 mAddress = in.readString(); 520 mDeduplicationIds = Set.of(in.readStringArray()); 521 mExtras = in.readBundle(); 522 mProviderId = in.readString(); 523 mIsVisibilityRestricted = in.readBoolean(); 524 mAllowedPackages = Set.of(in.createString8Array()); 525 } 526 527 /** 528 * Gets the id of the route. The routes which are given by {@link MediaRouter2} will have 529 * unique IDs. 530 * <p> 531 * In order to ensure uniqueness in {@link MediaRouter2} side, the value of this method 532 * can be different from what was set in {@link MediaRoute2ProviderService}. 533 * 534 * @see Builder#Builder(String, CharSequence) 535 */ 536 @NonNull getId()537 public String getId() { 538 if (!TextUtils.isEmpty(mProviderId)) { 539 return toUniqueId(mProviderId, mId); 540 } else { 541 return mId; 542 } 543 } 544 545 /** 546 * Gets the user-visible name of the route. 547 */ 548 @NonNull getName()549 public CharSequence getName() { 550 return mName; 551 } 552 553 /** 554 * Gets the supported features of the route. 555 */ 556 @NonNull getFeatures()557 public List<String> getFeatures() { 558 return mFeatures; 559 } 560 561 /** 562 * Returns the type of this route. 563 */ 564 @Type getType()565 public int getType() { 566 return mType; 567 } 568 569 /** 570 * Returns whether the route is a system route or not. 571 * <p> 572 * System routes are media routes directly controlled by the system 573 * such as phone speaker, wired headset, and Bluetooth devices. 574 * </p> 575 */ isSystemRoute()576 public boolean isSystemRoute() { 577 return mIsSystem; 578 } 579 580 /** 581 * Gets the URI of the icon representing this route. 582 * <p> 583 * This icon will be used in picker UIs if available. 584 * 585 * @return The URI of the icon representing this route, or null if none. 586 */ 587 @Nullable getIconUri()588 public Uri getIconUri() { 589 return mIconUri; 590 } 591 592 /** 593 * Gets the user-visible description of the route. 594 */ 595 @Nullable getDescription()596 public CharSequence getDescription() { 597 return mDescription; 598 } 599 600 /** 601 * Gets the connection state of the route. 602 * 603 * @return The connection state of this route: {@link #CONNECTION_STATE_DISCONNECTED}, 604 * {@link #CONNECTION_STATE_CONNECTING}, or {@link #CONNECTION_STATE_CONNECTED}. 605 */ 606 @ConnectionState getConnectionState()607 public int getConnectionState() { 608 return mConnectionState; 609 } 610 611 /** 612 * Gets the package name of the app using the route. 613 * Returns null if no apps are using this route. 614 */ 615 @Nullable getClientPackageName()616 public String getClientPackageName() { 617 return mClientPackageName; 618 } 619 620 /** 621 * Gets the package name of the provider that published the route. 622 * <p> 623 * It is set by the system service. 624 * @hide 625 */ 626 @Nullable getPackageName()627 public String getPackageName() { 628 return mPackageName; 629 } 630 631 /** 632 * Gets information about how volume is handled on the route. 633 * 634 * @return {@link #PLAYBACK_VOLUME_FIXED} or {@link #PLAYBACK_VOLUME_VARIABLE} 635 */ 636 @PlaybackVolume getVolumeHandling()637 public int getVolumeHandling() { 638 return mVolumeHandling; 639 } 640 641 /** 642 * Gets the maximum volume of the route. 643 */ getVolumeMax()644 public int getVolumeMax() { 645 return mVolumeMax; 646 } 647 648 /** 649 * Gets the current volume of the route. This may be invalid if the route is not selected. 650 */ getVolume()651 public int getVolume() { 652 return mVolume; 653 } 654 655 /** 656 * Gets the hardware address of the route if available. 657 * @hide 658 */ 659 @Nullable getAddress()660 public String getAddress() { 661 return mAddress; 662 } 663 664 /** 665 * Gets the deduplication IDs associated to the route. 666 * 667 * <p>Two routes with a matching deduplication ID originate from the same receiver device. 668 */ 669 @NonNull getDeduplicationIds()670 public Set<String> getDeduplicationIds() { 671 return mDeduplicationIds; 672 } 673 674 /** 675 * Gets an optional bundle with extra data. 676 */ 677 @Nullable getExtras()678 public Bundle getExtras() { 679 return mExtras == null ? null : new Bundle(mExtras); 680 } 681 682 /** 683 * Gets the original id set by {@link Builder#Builder(String, CharSequence)}. 684 * @hide 685 */ 686 @NonNull 687 @TestApi getOriginalId()688 public String getOriginalId() { 689 return mId; 690 } 691 692 /** 693 * Gets the provider id of the route. It is assigned automatically by 694 * {@link com.android.server.media.MediaRouterService}. 695 * 696 * @return provider id of the route or null if it's not set. 697 * @hide 698 */ 699 @Nullable getProviderId()700 public String getProviderId() { 701 return mProviderId; 702 } 703 704 /** 705 * Returns if the route has at least one of the specified route features. 706 * 707 * @param features the list of route features to consider 708 * @return {@code true} if the route has at least one feature in the list 709 * @hide 710 */ hasAnyFeatures(@onNull Collection<String> features)711 public boolean hasAnyFeatures(@NonNull Collection<String> features) { 712 Objects.requireNonNull(features, "features must not be null"); 713 for (String feature : features) { 714 if (getFeatures().contains(feature)) { 715 return true; 716 } 717 } 718 return false; 719 } 720 721 /** 722 * Returns if the route has all the specified route features. 723 * 724 * @hide 725 */ hasAllFeatures(@onNull Collection<String> features)726 public boolean hasAllFeatures(@NonNull Collection<String> features) { 727 Objects.requireNonNull(features, "features must not be null"); 728 for (String feature : features) { 729 if (!getFeatures().contains(feature)) { 730 return false; 731 } 732 } 733 return true; 734 } 735 736 /** 737 * Returns true if the route info has all of the required field. 738 * A route is valid if and only if it is obtained from 739 * {@link com.android.server.media.MediaRouterService}. 740 * @hide 741 */ isValid()742 public boolean isValid() { 743 if (TextUtils.isEmpty(getId()) || TextUtils.isEmpty(getName()) 744 || TextUtils.isEmpty(getProviderId())) { 745 return false; 746 } 747 return true; 748 } 749 750 /** 751 * Returns whether this route is visible to the package with the given name. 752 * @hide 753 */ isVisibleTo(String packageName)754 public boolean isVisibleTo(String packageName) { 755 return !mIsVisibilityRestricted || getPackageName().equals(packageName) 756 || mAllowedPackages.contains(packageName); 757 } 758 759 /** 760 * Dumps the current state of the object to the given {@code pw} as a human-readable string. 761 * 762 * <p> Used in the context of dumpsys. </p> 763 * 764 * @hide 765 */ dump(@onNull PrintWriter pw, @NonNull String prefix)766 public void dump(@NonNull PrintWriter pw, @NonNull String prefix) { 767 pw.println(prefix + "MediaRoute2Info"); 768 769 String indent = prefix + " "; 770 771 pw.println(indent + "mId=" + mId); 772 pw.println(indent + "mName=" + mName); 773 pw.println(indent + "mFeatures=" + mFeatures); 774 pw.println(indent + "mType=" + getDeviceTypeString(mType)); 775 pw.println(indent + "mIsSystem=" + mIsSystem); 776 pw.println(indent + "mIconUri=" + mIconUri); 777 pw.println(indent + "mDescription=" + mDescription); 778 pw.println(indent + "mConnectionState=" + mConnectionState); 779 pw.println(indent + "mClientPackageName=" + mClientPackageName); 780 pw.println(indent + "mPackageName=" + mPackageName); 781 782 dumpVolume(pw, indent); 783 784 pw.println(indent + "mAddress=" + mAddress); 785 pw.println(indent + "mDeduplicationIds=" + mDeduplicationIds); 786 pw.println(indent + "mExtras=" + mExtras); 787 pw.println(indent + "mProviderId=" + mProviderId); 788 pw.println(indent + "mIsVisibilityRestricted=" + mIsVisibilityRestricted); 789 pw.println(indent + "mAllowedPackages=" + mAllowedPackages); 790 } 791 dumpVolume(@onNull PrintWriter pw, @NonNull String prefix)792 private void dumpVolume(@NonNull PrintWriter pw, @NonNull String prefix) { 793 String volumeHandlingName; 794 795 switch (mVolumeHandling) { 796 case PLAYBACK_VOLUME_FIXED: 797 volumeHandlingName = "FIXED"; 798 break; 799 case PLAYBACK_VOLUME_VARIABLE: 800 volumeHandlingName = "VARIABLE"; 801 break; 802 default: 803 volumeHandlingName = "UNKNOWN"; 804 break; 805 } 806 807 String volume = String.format(Locale.US, 808 "volume(current=%d, max=%d, handling=%s(%d))", 809 mVolume, mVolumeMax, volumeHandlingName, mVolumeHandling); 810 811 pw.println(prefix + volume); 812 } 813 814 @Override equals(Object obj)815 public boolean equals(Object obj) { 816 if (this == obj) { 817 return true; 818 } 819 if (!(obj instanceof MediaRoute2Info)) { 820 return false; 821 } 822 MediaRoute2Info other = (MediaRoute2Info) obj; 823 824 // Note: mExtras is not included. 825 return Objects.equals(mId, other.mId) 826 && Objects.equals(mName, other.mName) 827 && Objects.equals(mFeatures, other.mFeatures) 828 && (mType == other.mType) 829 && (mIsSystem == other.mIsSystem) 830 && Objects.equals(mIconUri, other.mIconUri) 831 && Objects.equals(mDescription, other.mDescription) 832 && (mConnectionState == other.mConnectionState) 833 && Objects.equals(mClientPackageName, other.mClientPackageName) 834 && Objects.equals(mPackageName, other.mPackageName) 835 && (mVolumeHandling == other.mVolumeHandling) 836 && (mVolumeMax == other.mVolumeMax) 837 && (mVolume == other.mVolume) 838 && Objects.equals(mAddress, other.mAddress) 839 && Objects.equals(mDeduplicationIds, other.mDeduplicationIds) 840 && Objects.equals(mProviderId, other.mProviderId) 841 && (mIsVisibilityRestricted == other.mIsVisibilityRestricted) 842 && Objects.equals(mAllowedPackages, other.mAllowedPackages); 843 } 844 845 @Override hashCode()846 public int hashCode() { 847 // Note: mExtras is not included. 848 return Objects.hash(mId, mName, mFeatures, mType, mIsSystem, mIconUri, mDescription, 849 mConnectionState, mClientPackageName, mPackageName, mVolumeHandling, mVolumeMax, 850 mVolume, mAddress, mDeduplicationIds, mProviderId, mIsVisibilityRestricted, 851 mAllowedPackages); 852 } 853 854 @Override toString()855 public String toString() { 856 // Note: mExtras is not printed here. 857 StringBuilder result = new StringBuilder() 858 .append("MediaRoute2Info{ ") 859 .append("id=").append(getId()) 860 .append(", name=").append(getName()) 861 .append(", features=").append(getFeatures()) 862 .append(", iconUri=").append(getIconUri()) 863 .append(", description=").append(getDescription()) 864 .append(", connectionState=").append(getConnectionState()) 865 .append(", clientPackageName=").append(getClientPackageName()) 866 .append(", volumeHandling=").append(getVolumeHandling()) 867 .append(", volumeMax=").append(getVolumeMax()) 868 .append(", volume=").append(getVolume()) 869 .append(", deduplicationIds=").append(String.join(",", getDeduplicationIds())) 870 .append(", providerId=").append(getProviderId()) 871 .append(", isVisibilityRestricted=").append(mIsVisibilityRestricted) 872 .append(", allowedPackages=").append(String.join(",", mAllowedPackages)) 873 .append(" }"); 874 return result.toString(); 875 } 876 877 @Override describeContents()878 public int describeContents() { 879 return 0; 880 } 881 882 @Override writeToParcel(@onNull Parcel dest, int flags)883 public void writeToParcel(@NonNull Parcel dest, int flags) { 884 dest.writeString(mId); 885 TextUtils.writeToParcel(mName, dest, flags); 886 dest.writeStringList(mFeatures); 887 dest.writeInt(mType); 888 dest.writeBoolean(mIsSystem); 889 dest.writeParcelable(mIconUri, flags); 890 TextUtils.writeToParcel(mDescription, dest, flags); 891 dest.writeInt(mConnectionState); 892 dest.writeString(mClientPackageName); 893 dest.writeString(mPackageName); 894 dest.writeInt(mVolumeHandling); 895 dest.writeInt(mVolumeMax); 896 dest.writeInt(mVolume); 897 dest.writeString(mAddress); 898 dest.writeStringArray(mDeduplicationIds.toArray(new String[mDeduplicationIds.size()])); 899 dest.writeBundle(mExtras); 900 dest.writeString(mProviderId); 901 dest.writeBoolean(mIsVisibilityRestricted); 902 dest.writeString8Array(mAllowedPackages.toArray(new String[0])); 903 } 904 getDeviceTypeString(@ype int deviceType)905 private static String getDeviceTypeString(@Type int deviceType) { 906 switch (deviceType) { 907 case TYPE_BUILTIN_SPEAKER: 908 return "BUILTIN_SPEAKER"; 909 case TYPE_WIRED_HEADSET: 910 return "WIRED_HEADSET"; 911 case TYPE_WIRED_HEADPHONES: 912 return "WIRED_HEADPHONES"; 913 case TYPE_BLUETOOTH_A2DP: 914 return "BLUETOOTH_A2DP"; 915 case TYPE_HDMI: 916 return "HDMI"; 917 case TYPE_DOCK: 918 return "DOCK"; 919 case TYPE_USB_DEVICE: 920 return "USB_DEVICE"; 921 case TYPE_USB_ACCESSORY: 922 return "USB_ACCESSORY"; 923 case TYPE_USB_HEADSET: 924 return "USB_HEADSET"; 925 case TYPE_HEARING_AID: 926 return "HEARING_AID"; 927 case TYPE_REMOTE_TV: 928 return "REMOTE_TV"; 929 case TYPE_REMOTE_SPEAKER: 930 return "REMOTE_SPEAKER"; 931 case TYPE_REMOTE_AUDIO_VIDEO_RECEIVER: 932 return "REMOTE_AUDIO_VIDEO_RECEIVER"; 933 case TYPE_REMOTE_TABLET: 934 return "REMOTE_TABLET"; 935 case TYPE_REMOTE_TABLET_DOCKED: 936 return "REMOTE_TABLET_DOCKED"; 937 case TYPE_REMOTE_COMPUTER: 938 return "REMOTE_COMPUTER"; 939 case TYPE_REMOTE_GAME_CONSOLE: 940 return "REMOTE_GAME_CONSOLE"; 941 case TYPE_REMOTE_CAR: 942 return "REMOTE_CAR"; 943 case TYPE_REMOTE_SMARTWATCH: 944 return "REMOTE_SMARTWATCH"; 945 case TYPE_REMOTE_SMARTPHONE: 946 return "REMOTE_SMARTPHONE"; 947 case TYPE_GROUP: 948 return "GROUP"; 949 case TYPE_UNKNOWN: 950 default: 951 return TextUtils.formatSimple("UNKNOWN(%d)", deviceType); 952 } 953 } 954 955 /** 956 * Builder for {@link MediaRoute2Info media route info}. 957 */ 958 public static final class Builder { 959 final String mId; 960 final CharSequence mName; 961 final List<String> mFeatures; 962 963 @Type 964 int mType = TYPE_UNKNOWN; 965 boolean mIsSystem; 966 Uri mIconUri; 967 CharSequence mDescription; 968 @ConnectionState 969 int mConnectionState; 970 String mClientPackageName; 971 String mPackageName; 972 int mVolumeHandling = PLAYBACK_VOLUME_FIXED; 973 int mVolumeMax; 974 int mVolume; 975 String mAddress; 976 Set<String> mDeduplicationIds; 977 Bundle mExtras; 978 String mProviderId; 979 boolean mIsVisibilityRestricted; 980 Set<String> mAllowedPackages; 981 982 /** 983 * Constructor for builder to create {@link MediaRoute2Info}. 984 * <p> 985 * In order to ensure ID uniqueness, the {@link MediaRoute2Info#getId() ID} of a route info 986 * obtained from {@link MediaRouter2} can be different from what was set in 987 * {@link MediaRoute2ProviderService}. 988 * </p> 989 * @param id The ID of the route. Must not be empty. 990 * @param name The user-visible name of the route. 991 */ Builder(@onNull String id, @NonNull CharSequence name)992 public Builder(@NonNull String id, @NonNull CharSequence name) { 993 if (TextUtils.isEmpty(id)) { 994 throw new IllegalArgumentException("id must not be empty"); 995 } 996 if (TextUtils.isEmpty(name)) { 997 throw new IllegalArgumentException("name must not be empty"); 998 } 999 mId = id; 1000 mName = name; 1001 mFeatures = new ArrayList<>(); 1002 mDeduplicationIds = Set.of(); 1003 mAllowedPackages = Set.of(); 1004 } 1005 1006 /** 1007 * Constructor for builder to create {@link MediaRoute2Info} with existing 1008 * {@link MediaRoute2Info} instance. 1009 * 1010 * @param routeInfo the existing instance to copy data from. 1011 */ Builder(@onNull MediaRoute2Info routeInfo)1012 public Builder(@NonNull MediaRoute2Info routeInfo) { 1013 this(routeInfo.mId, routeInfo); 1014 } 1015 1016 /** 1017 * Constructor for builder to create {@link MediaRoute2Info} with existing 1018 * {@link MediaRoute2Info} instance and replace ID with the given {@code id}. 1019 * 1020 * @param id The ID of the new route. Must not be empty. 1021 * @param routeInfo the existing instance to copy data from. 1022 * @hide 1023 */ Builder(@onNull String id, @NonNull MediaRoute2Info routeInfo)1024 public Builder(@NonNull String id, @NonNull MediaRoute2Info routeInfo) { 1025 if (TextUtils.isEmpty(id)) { 1026 throw new IllegalArgumentException("id must not be empty"); 1027 } 1028 Objects.requireNonNull(routeInfo, "routeInfo must not be null"); 1029 1030 mId = id; 1031 mName = routeInfo.mName; 1032 mFeatures = new ArrayList<>(routeInfo.mFeatures); 1033 mType = routeInfo.mType; 1034 mIsSystem = routeInfo.mIsSystem; 1035 mIconUri = routeInfo.mIconUri; 1036 mDescription = routeInfo.mDescription; 1037 mConnectionState = routeInfo.mConnectionState; 1038 mClientPackageName = routeInfo.mClientPackageName; 1039 mPackageName = routeInfo.mPackageName; 1040 mVolumeHandling = routeInfo.mVolumeHandling; 1041 mVolumeMax = routeInfo.mVolumeMax; 1042 mVolume = routeInfo.mVolume; 1043 mAddress = routeInfo.mAddress; 1044 mDeduplicationIds = Set.copyOf(routeInfo.mDeduplicationIds); 1045 if (routeInfo.mExtras != null) { 1046 mExtras = new Bundle(routeInfo.mExtras); 1047 } 1048 mProviderId = routeInfo.mProviderId; 1049 mIsVisibilityRestricted = routeInfo.mIsVisibilityRestricted; 1050 mAllowedPackages = routeInfo.mAllowedPackages; 1051 } 1052 1053 /** 1054 * Adds a feature for the route. 1055 * @param feature a feature that the route has. May be one of predefined features 1056 * such as {@link #FEATURE_LIVE_AUDIO}, {@link #FEATURE_LIVE_VIDEO} or 1057 * {@link #FEATURE_REMOTE_PLAYBACK} or a custom feature defined by 1058 * a provider. 1059 * 1060 * @see #addFeatures(Collection) 1061 */ 1062 @NonNull addFeature(@onNull String feature)1063 public Builder addFeature(@NonNull String feature) { 1064 if (TextUtils.isEmpty(feature)) { 1065 throw new IllegalArgumentException("feature must not be null or empty"); 1066 } 1067 mFeatures.add(feature); 1068 return this; 1069 } 1070 1071 /** 1072 * Adds features for the route. A route must support at least one route type. 1073 * @param features features that the route has. May include predefined features 1074 * such as {@link #FEATURE_LIVE_AUDIO}, {@link #FEATURE_LIVE_VIDEO} or 1075 * {@link #FEATURE_REMOTE_PLAYBACK} or custom features defined by 1076 * a provider. 1077 * 1078 * @see #addFeature(String) 1079 */ 1080 @NonNull addFeatures(@onNull Collection<String> features)1081 public Builder addFeatures(@NonNull Collection<String> features) { 1082 Objects.requireNonNull(features, "features must not be null"); 1083 for (String feature : features) { 1084 addFeature(feature); 1085 } 1086 return this; 1087 } 1088 1089 /** 1090 * Clears the features of the route. A route must support at least one route type. 1091 */ 1092 @NonNull clearFeatures()1093 public Builder clearFeatures() { 1094 mFeatures.clear(); 1095 return this; 1096 } 1097 1098 /** 1099 * Sets the route's type. 1100 * 1101 * @see MediaRoute2Info#getType() 1102 */ 1103 @NonNull setType(@ype int type)1104 public Builder setType(@Type int type) { 1105 mType = type; 1106 return this; 1107 } 1108 1109 /** 1110 * Sets whether the route is a system route or not. 1111 * @hide 1112 */ 1113 @NonNull setSystemRoute(boolean isSystem)1114 public Builder setSystemRoute(boolean isSystem) { 1115 mIsSystem = isSystem; 1116 return this; 1117 } 1118 1119 /** 1120 * Sets the URI of the icon representing this route. 1121 * <p> 1122 * This icon will be used in picker UIs if available. 1123 * </p><p> 1124 * The URI must be one of the following formats: 1125 * <ul> 1126 * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li> 1127 * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE}) 1128 * </li> 1129 * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li> 1130 * </ul> 1131 * </p> 1132 */ 1133 @NonNull setIconUri(@ullable Uri iconUri)1134 public Builder setIconUri(@Nullable Uri iconUri) { 1135 mIconUri = iconUri; 1136 return this; 1137 } 1138 1139 /** 1140 * Sets the user-visible description of the route. 1141 */ 1142 @NonNull setDescription(@ullable CharSequence description)1143 public Builder setDescription(@Nullable CharSequence description) { 1144 mDescription = description; 1145 return this; 1146 } 1147 1148 /** 1149 * Sets the route's connection state. 1150 * 1151 * {@link #CONNECTION_STATE_DISCONNECTED}, 1152 * {@link #CONNECTION_STATE_CONNECTING}, or 1153 * {@link #CONNECTION_STATE_CONNECTED}. 1154 */ 1155 @NonNull setConnectionState(@onnectionState int connectionState)1156 public Builder setConnectionState(@ConnectionState int connectionState) { 1157 mConnectionState = connectionState; 1158 return this; 1159 } 1160 1161 /** 1162 * Sets the package name of the app using the route. 1163 */ 1164 @NonNull setClientPackageName(@ullable String packageName)1165 public Builder setClientPackageName(@Nullable String packageName) { 1166 mClientPackageName = packageName; 1167 return this; 1168 } 1169 1170 /** 1171 * Sets the package name of the route. 1172 * @hide 1173 */ 1174 @NonNull setPackageName(@onNull String packageName)1175 public Builder setPackageName(@NonNull String packageName) { 1176 mPackageName = packageName; 1177 return this; 1178 } 1179 1180 /** 1181 * Sets the route's volume handling. 1182 */ 1183 @NonNull setVolumeHandling(@laybackVolume int volumeHandling)1184 public Builder setVolumeHandling(@PlaybackVolume int volumeHandling) { 1185 mVolumeHandling = volumeHandling; 1186 return this; 1187 } 1188 1189 /** 1190 * Sets the route's maximum volume, or 0 if unknown. 1191 */ 1192 @NonNull setVolumeMax(int volumeMax)1193 public Builder setVolumeMax(int volumeMax) { 1194 mVolumeMax = volumeMax; 1195 return this; 1196 } 1197 1198 /** 1199 * Sets the route's current volume, or 0 if unknown. 1200 */ 1201 @NonNull setVolume(int volume)1202 public Builder setVolume(int volume) { 1203 mVolume = volume; 1204 return this; 1205 } 1206 1207 /** 1208 * Sets the hardware address of the route. 1209 * @hide 1210 */ 1211 @NonNull setAddress(String address)1212 public Builder setAddress(String address) { 1213 mAddress = address; 1214 return this; 1215 } 1216 1217 /** 1218 * Sets the {@link MediaRoute2Info#getDeduplicationIds() deduplication IDs} of the route. 1219 */ 1220 @NonNull setDeduplicationIds(@onNull Set<String> id)1221 public Builder setDeduplicationIds(@NonNull Set<String> id) { 1222 mDeduplicationIds = Set.copyOf(id); 1223 return this; 1224 } 1225 1226 /** 1227 * Sets a bundle of extras for the route. 1228 * <p> 1229 * Note: The extras will not affect the result of {@link MediaRoute2Info#equals(Object)}. 1230 */ 1231 @NonNull setExtras(@ullable Bundle extras)1232 public Builder setExtras(@Nullable Bundle extras) { 1233 if (extras == null) { 1234 mExtras = null; 1235 return this; 1236 } 1237 mExtras = new Bundle(extras); 1238 return this; 1239 } 1240 1241 /** 1242 * Sets the provider id of the route. 1243 * @hide 1244 */ 1245 @NonNull setProviderId(@onNull String providerId)1246 public Builder setProviderId(@NonNull String providerId) { 1247 if (TextUtils.isEmpty(providerId)) { 1248 throw new IllegalArgumentException("providerId must not be null or empty"); 1249 } 1250 mProviderId = providerId; 1251 return this; 1252 } 1253 1254 /** 1255 * Sets the visibility of this route to public. 1256 * 1257 * <p>By default, unless you call {@link #setVisibilityRestricted}, the new route will be 1258 * public. 1259 * 1260 * <p>Public routes are visible to any application with a matching {@link 1261 * RouteDiscoveryPreference#getPreferredFeatures feature}. 1262 * 1263 * <p>Calls to this method override previous calls to {@link #setVisibilityPublic} and 1264 * {@link #setVisibilityRestricted}. 1265 */ 1266 @NonNull setVisibilityPublic()1267 public Builder setVisibilityPublic() { 1268 mIsVisibilityRestricted = false; 1269 mAllowedPackages = Set.of(); 1270 return this; 1271 } 1272 1273 /** 1274 * Sets the visibility of this route to restricted. 1275 * 1276 * <p>Routes with restricted visibility are only visible to its publisher application and 1277 * applications whose package name is included in the provided {@code allowedPackages} set 1278 * with a matching {@link RouteDiscoveryPreference#getPreferredFeatures feature}. 1279 * 1280 * <p>Calls to this method override previous calls to {@link #setVisibilityPublic} and 1281 * {@link #setVisibilityRestricted}. 1282 * 1283 * @see #setVisibilityPublic 1284 * @param allowedPackages set of package names which are allowed to see this route. 1285 */ 1286 @NonNull setVisibilityRestricted(@onNull Set<String> allowedPackages)1287 public Builder setVisibilityRestricted(@NonNull Set<String> allowedPackages) { 1288 mIsVisibilityRestricted = true; 1289 mAllowedPackages = Set.copyOf(allowedPackages); 1290 return this; 1291 } 1292 1293 /** 1294 * Builds the {@link MediaRoute2Info media route info}. 1295 * 1296 * @throws IllegalArgumentException if no features are added. 1297 */ 1298 @NonNull build()1299 public MediaRoute2Info build() { 1300 if (mFeatures.isEmpty()) { 1301 throw new IllegalArgumentException("features must not be empty!"); 1302 } 1303 return new MediaRoute2Info(this); 1304 } 1305 } 1306 } 1307