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 java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 import java.util.ArrayList; 34 import java.util.Collection; 35 import java.util.List; 36 import java.util.Objects; 37 import java.util.Set; 38 39 /** 40 * Describes the properties of a route. 41 */ 42 public final class MediaRoute2Info implements Parcelable { 43 @NonNull 44 public static final Creator<MediaRoute2Info> CREATOR = new Creator<MediaRoute2Info>() { 45 @Override 46 public MediaRoute2Info createFromParcel(Parcel in) { 47 return new MediaRoute2Info(in); 48 } 49 50 @Override 51 public MediaRoute2Info[] newArray(int size) { 52 return new MediaRoute2Info[size]; 53 } 54 }; 55 56 /** @hide */ 57 @IntDef({CONNECTION_STATE_DISCONNECTED, CONNECTION_STATE_CONNECTING, 58 CONNECTION_STATE_CONNECTED}) 59 @Retention(RetentionPolicy.SOURCE) 60 public @interface ConnectionState {} 61 62 /** 63 * The default connection state indicating the route is disconnected. 64 * 65 * @see #getConnectionState 66 */ 67 public static final int CONNECTION_STATE_DISCONNECTED = 0; 68 69 /** 70 * A connection state indicating the route is in the process of connecting and is not yet 71 * ready for use. 72 * 73 * @see #getConnectionState 74 */ 75 public static final int CONNECTION_STATE_CONNECTING = 1; 76 77 /** 78 * A connection state indicating the route is connected. 79 * 80 * @see #getConnectionState 81 */ 82 public static final int CONNECTION_STATE_CONNECTED = 2; 83 84 /** @hide */ 85 @IntDef({PLAYBACK_VOLUME_FIXED, PLAYBACK_VOLUME_VARIABLE}) 86 @Retention(RetentionPolicy.SOURCE) 87 public @interface PlaybackVolume {} 88 89 /** 90 * Playback information indicating the playback volume is fixed, i.e. it cannot be 91 * controlled from this object. An example of fixed playback volume is a remote player, 92 * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 93 * than attenuate at the source. 94 * 95 * @see #getVolumeHandling() 96 */ 97 public static final int PLAYBACK_VOLUME_FIXED = 0; 98 /** 99 * Playback information indicating the playback volume is variable and can be controlled 100 * from this object. 101 * 102 * @see #getVolumeHandling() 103 */ 104 public static final int PLAYBACK_VOLUME_VARIABLE = 1; 105 106 /** @hide */ 107 @IntDef({ 108 TYPE_UNKNOWN, TYPE_BUILTIN_SPEAKER, TYPE_WIRED_HEADSET, 109 TYPE_WIRED_HEADPHONES, TYPE_BLUETOOTH_A2DP, TYPE_HDMI, TYPE_USB_DEVICE, 110 TYPE_USB_ACCESSORY, TYPE_DOCK, TYPE_USB_HEADSET, TYPE_HEARING_AID, TYPE_BLE_HEADSET, 111 TYPE_REMOTE_TV, TYPE_REMOTE_SPEAKER, TYPE_GROUP}) 112 @Retention(RetentionPolicy.SOURCE) 113 public @interface Type {} 114 115 /** 116 * The default route type indicating the type is unknown. 117 * 118 * @see #getType 119 * @hide 120 */ 121 public static final int TYPE_UNKNOWN = 0; 122 123 /** 124 * A route type describing the speaker system (i.e. a mono speaker or stereo speakers) built 125 * in a device. 126 * 127 * @see #getType 128 * @hide 129 */ 130 public static final int TYPE_BUILTIN_SPEAKER = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; 131 132 /** 133 * A route type describing a headset, which is the combination of a headphones and microphone. 134 * 135 * @see #getType 136 * @hide 137 */ 138 public static final int TYPE_WIRED_HEADSET = AudioDeviceInfo.TYPE_WIRED_HEADSET; 139 140 /** 141 * A route type describing a pair of wired headphones. 142 * 143 * @see #getType 144 * @hide 145 */ 146 public static final int TYPE_WIRED_HEADPHONES = AudioDeviceInfo.TYPE_WIRED_HEADPHONES; 147 148 /** 149 * A route type indicating the presentation of the media is happening 150 * on a bluetooth device such as a bluetooth speaker. 151 * 152 * @see #getType 153 * @hide 154 */ 155 public static final int TYPE_BLUETOOTH_A2DP = AudioDeviceInfo.TYPE_BLUETOOTH_A2DP; 156 157 /** 158 * A route type describing an HDMI connection. 159 * 160 * @see #getType 161 * @hide 162 */ 163 public static final int TYPE_HDMI = AudioDeviceInfo.TYPE_HDMI; 164 165 /** 166 * A route type describing a USB audio device. 167 * 168 * @see #getType 169 * @hide 170 */ 171 public static final int TYPE_USB_DEVICE = AudioDeviceInfo.TYPE_USB_DEVICE; 172 173 /** 174 * A route type describing a USB audio device in accessory mode. 175 * 176 * @see #getType 177 * @hide 178 */ 179 public static final int TYPE_USB_ACCESSORY = AudioDeviceInfo.TYPE_USB_ACCESSORY; 180 181 /** 182 * A route type describing the audio device associated with a dock. 183 * 184 * @see #getType 185 * @hide 186 */ 187 public static final int TYPE_DOCK = AudioDeviceInfo.TYPE_DOCK; 188 189 /** 190 * A device type describing a USB audio headset. 191 * 192 * @see #getType 193 * @hide 194 */ 195 public static final int TYPE_USB_HEADSET = AudioDeviceInfo.TYPE_USB_HEADSET; 196 197 /** 198 * A route type describing a Hearing Aid. 199 * 200 * @see #getType 201 * @hide 202 */ 203 public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID; 204 205 /** 206 * A route type describing a BLE HEADSET. 207 * 208 * @see #getType 209 * @hide 210 */ 211 public static final int TYPE_BLE_HEADSET = AudioDeviceInfo.TYPE_BLE_HEADSET; 212 213 /** 214 * A route type indicating the presentation of the media is happening on a TV. 215 * 216 * @see #getType 217 * @hide 218 */ 219 public static final int TYPE_REMOTE_TV = 1001; 220 221 /** 222 * A route type indicating the presentation of the media is happening on a speaker. 223 * 224 * @see #getType 225 * @hide 226 */ 227 public static final int TYPE_REMOTE_SPEAKER = 1002; 228 229 /** 230 * A route type indicating the presentation of the media is happening on multiple devices. 231 * 232 * @see #getType 233 * @hide 234 */ 235 public static final int TYPE_GROUP = 2000; 236 237 /** 238 * Route feature: Live audio. 239 * <p> 240 * A route that supports live audio routing will allow the media audio stream 241 * to be sent to supported destinations. This can include internal speakers or 242 * audio jacks on the device itself, A2DP devices, and more. 243 * </p><p> 244 * When a live audio route is selected, audio routing is transparent to the application. 245 * All audio played on the media stream will be routed to the selected destination. 246 * </p><p> 247 * Refer to the class documentation for details about live audio routes. 248 * </p> 249 */ 250 public static final String FEATURE_LIVE_AUDIO = "android.media.route.feature.LIVE_AUDIO"; 251 252 /** 253 * Route feature: Live video. 254 * <p> 255 * A route that supports live video routing will allow a mirrored version 256 * of the device's primary display or a customized 257 * {@link android.app.Presentation Presentation} to be sent to supported 258 * destinations. 259 * </p><p> 260 * When a live video route is selected, audio and video routing is transparent 261 * to the application. By default, audio and video is routed to the selected 262 * destination. For certain live video routes, the application may also use a 263 * {@link android.app.Presentation Presentation} to replace the mirrored view 264 * on the external display with different content. 265 * </p><p> 266 * Refer to the class documentation for details about live video routes. 267 * </p> 268 * 269 * @see android.app.Presentation 270 */ 271 public static final String FEATURE_LIVE_VIDEO = "android.media.route.feature.LIVE_VIDEO"; 272 273 /** 274 * Route feature: Local playback. 275 * @hide 276 */ 277 public static final String FEATURE_LOCAL_PLAYBACK = 278 "android.media.route.feature.LOCAL_PLAYBACK"; 279 280 /** 281 * Route feature: Remote playback. 282 * <p> 283 * A route that supports remote playback routing will allow an application to send 284 * requests to play content remotely to supported destinations. 285 * A route may only support {@link #FEATURE_REMOTE_AUDIO_PLAYBACK audio playback} or 286 * {@link #FEATURE_REMOTE_VIDEO_PLAYBACK video playback}. 287 * </p><p> 288 * Remote playback routes destinations operate independently of the local device. 289 * When a remote playback route is selected, the application can control the content 290 * playing on the destination using {@link MediaRouter2.RoutingController#getControlHints()}. 291 * The application may also receive status updates from the route regarding remote playback. 292 * </p><p> 293 * Refer to the class documentation for details about remote playback routes. 294 * </p> 295 * @see #FEATURE_REMOTE_AUDIO_PLAYBACK 296 * @see #FEATURE_REMOTE_VIDEO_PLAYBACK 297 */ 298 public static final String FEATURE_REMOTE_PLAYBACK = 299 "android.media.route.feature.REMOTE_PLAYBACK"; 300 301 /** 302 * Route feature: Remote audio playback. 303 * <p> 304 * A route that supports remote audio playback routing will allow an application to send 305 * requests to play audio content remotely to supported destinations. 306 * 307 * @see #FEATURE_REMOTE_PLAYBACK 308 * @see #FEATURE_REMOTE_VIDEO_PLAYBACK 309 */ 310 public static final String FEATURE_REMOTE_AUDIO_PLAYBACK = 311 "android.media.route.feature.REMOTE_AUDIO_PLAYBACK"; 312 313 /** 314 * Route feature: Remote video playback. 315 * <p> 316 * A route that supports remote video playback routing will allow an application to send 317 * requests to play video content remotely to supported destinations. 318 * 319 * @see #FEATURE_REMOTE_PLAYBACK 320 * @see #FEATURE_REMOTE_AUDIO_PLAYBACK 321 */ 322 public static final String FEATURE_REMOTE_VIDEO_PLAYBACK = 323 "android.media.route.feature.REMOTE_VIDEO_PLAYBACK"; 324 325 /** 326 * Route feature: Remote group playback. 327 * <p> 328 * @hide 329 */ 330 public static final String FEATURE_REMOTE_GROUP_PLAYBACK = 331 "android.media.route.feature.REMOTE_GROUP_PLAYBACK"; 332 333 final String mId; 334 final CharSequence mName; 335 final List<String> mFeatures; 336 @Type 337 final int mType; 338 final boolean mIsSystem; 339 final Uri mIconUri; 340 final CharSequence mDescription; 341 @ConnectionState 342 final int mConnectionState; 343 final String mClientPackageName; 344 final String mPackageName; 345 final int mVolumeHandling; 346 final int mVolumeMax; 347 final int mVolume; 348 final String mAddress; 349 final Set<String> mDeduplicationIds; 350 final Bundle mExtras; 351 final String mProviderId; 352 MediaRoute2Info(@onNull Builder builder)353 MediaRoute2Info(@NonNull Builder builder) { 354 mId = builder.mId; 355 mName = builder.mName; 356 mFeatures = builder.mFeatures; 357 mType = builder.mType; 358 mIsSystem = builder.mIsSystem; 359 mIconUri = builder.mIconUri; 360 mDescription = builder.mDescription; 361 mConnectionState = builder.mConnectionState; 362 mClientPackageName = builder.mClientPackageName; 363 mPackageName = builder.mPackageName; 364 mVolumeHandling = builder.mVolumeHandling; 365 mVolumeMax = builder.mVolumeMax; 366 mVolume = builder.mVolume; 367 mAddress = builder.mAddress; 368 mDeduplicationIds = builder.mDeduplicationIds; 369 mExtras = builder.mExtras; 370 mProviderId = builder.mProviderId; 371 } 372 MediaRoute2Info(@onNull Parcel in)373 MediaRoute2Info(@NonNull Parcel in) { 374 mId = in.readString(); 375 mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 376 mFeatures = in.createStringArrayList(); 377 mType = in.readInt(); 378 mIsSystem = in.readBoolean(); 379 mIconUri = in.readParcelable(null, android.net.Uri.class); 380 mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 381 mConnectionState = in.readInt(); 382 mClientPackageName = in.readString(); 383 mPackageName = in.readString(); 384 mVolumeHandling = in.readInt(); 385 mVolumeMax = in.readInt(); 386 mVolume = in.readInt(); 387 mAddress = in.readString(); 388 mDeduplicationIds = Set.of(in.readStringArray()); 389 mExtras = in.readBundle(); 390 mProviderId = in.readString(); 391 } 392 393 /** 394 * Gets the id of the route. The routes which are given by {@link MediaRouter2} will have 395 * unique IDs. 396 * <p> 397 * In order to ensure uniqueness in {@link MediaRouter2} side, the value of this method 398 * can be different from what was set in {@link MediaRoute2ProviderService}. 399 * 400 * @see Builder#Builder(String, CharSequence) 401 */ 402 @NonNull getId()403 public String getId() { 404 if (mProviderId != null) { 405 return toUniqueId(mProviderId, mId); 406 } else { 407 return mId; 408 } 409 } 410 411 /** 412 * Gets the user-visible name of the route. 413 */ 414 @NonNull getName()415 public CharSequence getName() { 416 return mName; 417 } 418 419 /** 420 * Gets the supported features of the route. 421 */ 422 @NonNull getFeatures()423 public List<String> getFeatures() { 424 return mFeatures; 425 } 426 427 /** 428 * Gets the type of this route. 429 * 430 * @return The type of this route: 431 * {@link #TYPE_UNKNOWN}, 432 * {@link #TYPE_BUILTIN_SPEAKER}, {@link #TYPE_WIRED_HEADSET}, {@link #TYPE_WIRED_HEADPHONES}, 433 * {@link #TYPE_BLUETOOTH_A2DP}, {@link #TYPE_HDMI}, {@link #TYPE_DOCK}, 434 * {@Link #TYPE_USB_DEVICE}, {@link #TYPE_USB_ACCESSORY}, {@link #TYPE_USB_HEADSET} 435 * {@link #TYPE_HEARING_AID}, 436 * {@link #TYPE_REMOTE_TV}, {@link #TYPE_REMOTE_SPEAKER}, {@link #TYPE_GROUP}. 437 * @hide 438 */ 439 @Type getType()440 public int getType() { 441 return mType; 442 } 443 444 /** 445 * Returns whether the route is a system route or not. 446 * <p> 447 * System routes are media routes directly controlled by the system 448 * such as phone speaker, wired headset, and Bluetooth devices. 449 * </p> 450 */ isSystemRoute()451 public boolean isSystemRoute() { 452 return mIsSystem; 453 } 454 455 /** 456 * Gets the URI of the icon representing this route. 457 * <p> 458 * This icon will be used in picker UIs if available. 459 * 460 * @return The URI of the icon representing this route, or null if none. 461 */ 462 @Nullable getIconUri()463 public Uri getIconUri() { 464 return mIconUri; 465 } 466 467 /** 468 * Gets the user-visible description of the route. 469 */ 470 @Nullable getDescription()471 public CharSequence getDescription() { 472 return mDescription; 473 } 474 475 /** 476 * Gets the connection state of the route. 477 * 478 * @return The connection state of this route: {@link #CONNECTION_STATE_DISCONNECTED}, 479 * {@link #CONNECTION_STATE_CONNECTING}, or {@link #CONNECTION_STATE_CONNECTED}. 480 */ 481 @ConnectionState getConnectionState()482 public int getConnectionState() { 483 return mConnectionState; 484 } 485 486 /** 487 * Gets the package name of the app using the route. 488 * Returns null if no apps are using this route. 489 */ 490 @Nullable getClientPackageName()491 public String getClientPackageName() { 492 return mClientPackageName; 493 } 494 495 /** 496 * Gets the package name of the provider that published the route. 497 * <p> 498 * It is set by the system service. 499 * @hide 500 */ 501 @Nullable getPackageName()502 public String getPackageName() { 503 return mPackageName; 504 } 505 506 /** 507 * Gets information about how volume is handled on the route. 508 * 509 * @return {@link #PLAYBACK_VOLUME_FIXED} or {@link #PLAYBACK_VOLUME_VARIABLE} 510 */ 511 @PlaybackVolume getVolumeHandling()512 public int getVolumeHandling() { 513 return mVolumeHandling; 514 } 515 516 /** 517 * Gets the maximum volume of the route. 518 */ getVolumeMax()519 public int getVolumeMax() { 520 return mVolumeMax; 521 } 522 523 /** 524 * Gets the current volume of the route. This may be invalid if the route is not selected. 525 */ getVolume()526 public int getVolume() { 527 return mVolume; 528 } 529 530 /** 531 * Gets the hardware address of the route if available. 532 * @hide 533 */ 534 @Nullable getAddress()535 public String getAddress() { 536 return mAddress; 537 } 538 539 /** 540 * Gets the Deduplication ID of the route if available. 541 * @see RouteDiscoveryPreference#shouldRemoveDuplicates() 542 * @hide 543 */ 544 @NonNull getDeduplicationIds()545 public Set<String> getDeduplicationIds() { 546 return mDeduplicationIds; 547 } 548 549 /** 550 * Gets an optional bundle with extra data. 551 */ 552 @Nullable getExtras()553 public Bundle getExtras() { 554 return mExtras == null ? null : new Bundle(mExtras); 555 } 556 557 /** 558 * Gets the original id set by {@link Builder#Builder(String, CharSequence)}. 559 * @hide 560 */ 561 @NonNull 562 @TestApi getOriginalId()563 public String getOriginalId() { 564 return mId; 565 } 566 567 /** 568 * Gets the provider id of the route. It is assigned automatically by 569 * {@link com.android.server.media.MediaRouterService}. 570 * 571 * @return provider id of the route or null if it's not set. 572 * @hide 573 */ 574 @Nullable getProviderId()575 public String getProviderId() { 576 return mProviderId; 577 } 578 579 /** 580 * Returns if the route has at least one of the specified route features. 581 * 582 * @param features the list of route features to consider 583 * @return {@code true} if the route has at least one feature in the list 584 * @hide 585 */ hasAnyFeatures(@onNull Collection<String> features)586 public boolean hasAnyFeatures(@NonNull Collection<String> features) { 587 Objects.requireNonNull(features, "features must not be null"); 588 for (String feature : features) { 589 if (getFeatures().contains(feature)) { 590 return true; 591 } 592 } 593 return false; 594 } 595 596 /** 597 * Returns if the route has all the specified route features. 598 * 599 * @hide 600 */ hasAllFeatures(@onNull Collection<String> features)601 public boolean hasAllFeatures(@NonNull Collection<String> features) { 602 Objects.requireNonNull(features, "features must not be null"); 603 for (String feature : features) { 604 if (!getFeatures().contains(feature)) { 605 return false; 606 } 607 } 608 return true; 609 } 610 611 /** 612 * Returns true if the route info has all of the required field. 613 * A route is valid if and only if it is obtained from 614 * {@link com.android.server.media.MediaRouterService}. 615 * @hide 616 */ isValid()617 public boolean isValid() { 618 if (TextUtils.isEmpty(getId()) || TextUtils.isEmpty(getName()) 619 || TextUtils.isEmpty(getProviderId())) { 620 return false; 621 } 622 return true; 623 } 624 625 @Override equals(Object obj)626 public boolean equals(Object obj) { 627 if (this == obj) { 628 return true; 629 } 630 if (!(obj instanceof MediaRoute2Info)) { 631 return false; 632 } 633 MediaRoute2Info other = (MediaRoute2Info) obj; 634 635 // Note: mExtras is not included. 636 return Objects.equals(mId, other.mId) 637 && Objects.equals(mName, other.mName) 638 && Objects.equals(mFeatures, other.mFeatures) 639 && (mType == other.mType) 640 && (mIsSystem == other.mIsSystem) 641 && Objects.equals(mIconUri, other.mIconUri) 642 && Objects.equals(mDescription, other.mDescription) 643 && (mConnectionState == other.mConnectionState) 644 && Objects.equals(mClientPackageName, other.mClientPackageName) 645 && Objects.equals(mPackageName, other.mPackageName) 646 && (mVolumeHandling == other.mVolumeHandling) 647 && (mVolumeMax == other.mVolumeMax) 648 && (mVolume == other.mVolume) 649 && Objects.equals(mAddress, other.mAddress) 650 && Objects.equals(mDeduplicationIds, other.mDeduplicationIds) 651 && Objects.equals(mProviderId, other.mProviderId); 652 } 653 654 @Override hashCode()655 public int hashCode() { 656 // Note: mExtras is not included. 657 return Objects.hash(mId, mName, mFeatures, mType, mIsSystem, mIconUri, mDescription, 658 mConnectionState, mClientPackageName, mPackageName, mVolumeHandling, mVolumeMax, 659 mVolume, mAddress, mDeduplicationIds, mProviderId); 660 } 661 662 @Override toString()663 public String toString() { 664 // Note: mExtras is not printed here. 665 StringBuilder result = new StringBuilder() 666 .append("MediaRoute2Info{ ") 667 .append("id=").append(getId()) 668 .append(", name=").append(getName()) 669 .append(", features=").append(getFeatures()) 670 .append(", iconUri=").append(getIconUri()) 671 .append(", description=").append(getDescription()) 672 .append(", connectionState=").append(getConnectionState()) 673 .append(", clientPackageName=").append(getClientPackageName()) 674 .append(", volumeHandling=").append(getVolumeHandling()) 675 .append(", volumeMax=").append(getVolumeMax()) 676 .append(", volume=").append(getVolume()) 677 .append(", deduplicationIds=").append(String.join(",", getDeduplicationIds())) 678 .append(", providerId=").append(getProviderId()) 679 .append(" }"); 680 return result.toString(); 681 } 682 683 @Override describeContents()684 public int describeContents() { 685 return 0; 686 } 687 688 @Override writeToParcel(@onNull Parcel dest, int flags)689 public void writeToParcel(@NonNull Parcel dest, int flags) { 690 dest.writeString(mId); 691 TextUtils.writeToParcel(mName, dest, flags); 692 dest.writeStringList(mFeatures); 693 dest.writeInt(mType); 694 dest.writeBoolean(mIsSystem); 695 dest.writeParcelable(mIconUri, flags); 696 TextUtils.writeToParcel(mDescription, dest, flags); 697 dest.writeInt(mConnectionState); 698 dest.writeString(mClientPackageName); 699 dest.writeString(mPackageName); 700 dest.writeInt(mVolumeHandling); 701 dest.writeInt(mVolumeMax); 702 dest.writeInt(mVolume); 703 dest.writeString(mAddress); 704 dest.writeStringArray(mDeduplicationIds.toArray(new String[mDeduplicationIds.size()])); 705 dest.writeBundle(mExtras); 706 dest.writeString(mProviderId); 707 } 708 709 /** 710 * Builder for {@link MediaRoute2Info media route info}. 711 */ 712 public static final class Builder { 713 final String mId; 714 final CharSequence mName; 715 final List<String> mFeatures; 716 717 @Type 718 int mType = TYPE_UNKNOWN; 719 boolean mIsSystem; 720 Uri mIconUri; 721 CharSequence mDescription; 722 @ConnectionState 723 int mConnectionState; 724 String mClientPackageName; 725 String mPackageName; 726 int mVolumeHandling = PLAYBACK_VOLUME_FIXED; 727 int mVolumeMax; 728 int mVolume; 729 String mAddress; 730 Set<String> mDeduplicationIds; 731 Bundle mExtras; 732 String mProviderId; 733 734 /** 735 * Constructor for builder to create {@link MediaRoute2Info}. 736 * <p> 737 * In order to ensure ID uniqueness, the {@link MediaRoute2Info#getId() ID} of a route info 738 * obtained from {@link MediaRouter2} can be different from what was set in 739 * {@link MediaRoute2ProviderService}. 740 * </p> 741 * @param id The ID of the route. Must not be empty. 742 * @param name The user-visible name of the route. 743 */ Builder(@onNull String id, @NonNull CharSequence name)744 public Builder(@NonNull String id, @NonNull CharSequence name) { 745 if (TextUtils.isEmpty(id)) { 746 throw new IllegalArgumentException("id must not be empty"); 747 } 748 if (TextUtils.isEmpty(name)) { 749 throw new IllegalArgumentException("name must not be empty"); 750 } 751 mId = id; 752 mName = name; 753 mFeatures = new ArrayList<>(); 754 mDeduplicationIds = Set.of(); 755 } 756 757 /** 758 * Constructor for builder to create {@link MediaRoute2Info} with existing 759 * {@link MediaRoute2Info} instance. 760 * 761 * @param routeInfo the existing instance to copy data from. 762 */ Builder(@onNull MediaRoute2Info routeInfo)763 public Builder(@NonNull MediaRoute2Info routeInfo) { 764 this(routeInfo.mId, routeInfo); 765 } 766 767 /** 768 * Constructor for builder to create {@link MediaRoute2Info} with existing 769 * {@link MediaRoute2Info} instance and replace ID with the given {@code id}. 770 * 771 * @param id The ID of the new route. Must not be empty. 772 * @param routeInfo the existing instance to copy data from. 773 * @hide 774 */ Builder(@onNull String id, @NonNull MediaRoute2Info routeInfo)775 public Builder(@NonNull String id, @NonNull MediaRoute2Info routeInfo) { 776 if (TextUtils.isEmpty(id)) { 777 throw new IllegalArgumentException("id must not be empty"); 778 } 779 Objects.requireNonNull(routeInfo, "routeInfo must not be null"); 780 781 mId = id; 782 mName = routeInfo.mName; 783 mFeatures = new ArrayList<>(routeInfo.mFeatures); 784 mType = routeInfo.mType; 785 mIsSystem = routeInfo.mIsSystem; 786 mIconUri = routeInfo.mIconUri; 787 mDescription = routeInfo.mDescription; 788 mConnectionState = routeInfo.mConnectionState; 789 mClientPackageName = routeInfo.mClientPackageName; 790 mPackageName = routeInfo.mPackageName; 791 mVolumeHandling = routeInfo.mVolumeHandling; 792 mVolumeMax = routeInfo.mVolumeMax; 793 mVolume = routeInfo.mVolume; 794 mAddress = routeInfo.mAddress; 795 mDeduplicationIds = Set.copyOf(routeInfo.mDeduplicationIds); 796 if (routeInfo.mExtras != null) { 797 mExtras = new Bundle(routeInfo.mExtras); 798 } 799 mProviderId = routeInfo.mProviderId; 800 } 801 802 /** 803 * Adds a feature for the route. 804 * @param feature a feature that the route has. May be one of predefined features 805 * such as {@link #FEATURE_LIVE_AUDIO}, {@link #FEATURE_LIVE_VIDEO} or 806 * {@link #FEATURE_REMOTE_PLAYBACK} or a custom feature defined by 807 * a provider. 808 * 809 * @see #addFeatures(Collection) 810 */ 811 @NonNull addFeature(@onNull String feature)812 public Builder addFeature(@NonNull String feature) { 813 if (TextUtils.isEmpty(feature)) { 814 throw new IllegalArgumentException("feature must not be null or empty"); 815 } 816 mFeatures.add(feature); 817 return this; 818 } 819 820 /** 821 * Adds features for the route. A route must support at least one route type. 822 * @param features features that the route has. May include predefined features 823 * such as {@link #FEATURE_LIVE_AUDIO}, {@link #FEATURE_LIVE_VIDEO} or 824 * {@link #FEATURE_REMOTE_PLAYBACK} or custom features defined by 825 * a provider. 826 * 827 * @see #addFeature(String) 828 */ 829 @NonNull addFeatures(@onNull Collection<String> features)830 public Builder addFeatures(@NonNull Collection<String> features) { 831 Objects.requireNonNull(features, "features must not be null"); 832 for (String feature : features) { 833 addFeature(feature); 834 } 835 return this; 836 } 837 838 /** 839 * Clears the features of the route. A route must support at least one route type. 840 */ 841 @NonNull clearFeatures()842 public Builder clearFeatures() { 843 mFeatures.clear(); 844 return this; 845 } 846 847 /** 848 * Sets the route's type. 849 * @hide 850 */ 851 @NonNull setType(@ype int type)852 public Builder setType(@Type int type) { 853 mType = type; 854 return this; 855 } 856 857 /** 858 * Sets whether the route is a system route or not. 859 * @hide 860 */ 861 @NonNull setSystemRoute(boolean isSystem)862 public Builder setSystemRoute(boolean isSystem) { 863 mIsSystem = isSystem; 864 return this; 865 } 866 867 /** 868 * Sets the URI of the icon representing this route. 869 * <p> 870 * This icon will be used in picker UIs if available. 871 * </p><p> 872 * The URI must be one of the following formats: 873 * <ul> 874 * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li> 875 * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE}) 876 * </li> 877 * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li> 878 * </ul> 879 * </p> 880 */ 881 @NonNull setIconUri(@ullable Uri iconUri)882 public Builder setIconUri(@Nullable Uri iconUri) { 883 mIconUri = iconUri; 884 return this; 885 } 886 887 /** 888 * Sets the user-visible description of the route. 889 */ 890 @NonNull setDescription(@ullable CharSequence description)891 public Builder setDescription(@Nullable CharSequence description) { 892 mDescription = description; 893 return this; 894 } 895 896 /** 897 * Sets the route's connection state. 898 * 899 * {@link #CONNECTION_STATE_DISCONNECTED}, 900 * {@link #CONNECTION_STATE_CONNECTING}, or 901 * {@link #CONNECTION_STATE_CONNECTED}. 902 */ 903 @NonNull setConnectionState(@onnectionState int connectionState)904 public Builder setConnectionState(@ConnectionState int connectionState) { 905 mConnectionState = connectionState; 906 return this; 907 } 908 909 /** 910 * Sets the package name of the app using the route. 911 */ 912 @NonNull setClientPackageName(@ullable String packageName)913 public Builder setClientPackageName(@Nullable String packageName) { 914 mClientPackageName = packageName; 915 return this; 916 } 917 918 /** 919 * Sets the package name of the route. 920 * @hide 921 */ 922 @NonNull setPackageName(@onNull String packageName)923 public Builder setPackageName(@NonNull String packageName) { 924 mPackageName = packageName; 925 return this; 926 } 927 928 /** 929 * Sets the route's volume handling. 930 */ 931 @NonNull setVolumeHandling(@laybackVolume int volumeHandling)932 public Builder setVolumeHandling(@PlaybackVolume int volumeHandling) { 933 mVolumeHandling = volumeHandling; 934 return this; 935 } 936 937 /** 938 * Sets the route's maximum volume, or 0 if unknown. 939 */ 940 @NonNull setVolumeMax(int volumeMax)941 public Builder setVolumeMax(int volumeMax) { 942 mVolumeMax = volumeMax; 943 return this; 944 } 945 946 /** 947 * Sets the route's current volume, or 0 if unknown. 948 */ 949 @NonNull setVolume(int volume)950 public Builder setVolume(int volume) { 951 mVolume = volume; 952 return this; 953 } 954 955 /** 956 * Sets the hardware address of the route. 957 * @hide 958 */ 959 @NonNull setAddress(String address)960 public Builder setAddress(String address) { 961 mAddress = address; 962 return this; 963 } 964 965 /** 966 * Sets the deduplication ID of the route. 967 * Routes have the same ID could be removed even when 968 * they are from different providers. 969 * <p> 970 * If it's {@code null}, the route will not be removed. 971 * @see RouteDiscoveryPreference#shouldRemoveDuplicates() 972 * @hide 973 */ 974 @NonNull setDeduplicationIds(@onNull Set<String> id)975 public Builder setDeduplicationIds(@NonNull Set<String> id) { 976 mDeduplicationIds = Set.copyOf(id); 977 return this; 978 } 979 980 /** 981 * Sets a bundle of extras for the route. 982 * <p> 983 * Note: The extras will not affect the result of {@link MediaRoute2Info#equals(Object)}. 984 */ 985 @NonNull setExtras(@ullable Bundle extras)986 public Builder setExtras(@Nullable Bundle extras) { 987 if (extras == null) { 988 mExtras = null; 989 return this; 990 } 991 mExtras = new Bundle(extras); 992 return this; 993 } 994 995 /** 996 * Sets the provider id of the route. 997 * @hide 998 */ 999 @NonNull setProviderId(@onNull String providerId)1000 public Builder setProviderId(@NonNull String providerId) { 1001 if (TextUtils.isEmpty(providerId)) { 1002 throw new IllegalArgumentException("providerId must not be null or empty"); 1003 } 1004 mProviderId = providerId; 1005 return this; 1006 } 1007 1008 /** 1009 * Builds the {@link MediaRoute2Info media route info}. 1010 * 1011 * @throws IllegalArgumentException if no features are added. 1012 */ 1013 @NonNull build()1014 public MediaRoute2Info build() { 1015 if (mFeatures.isEmpty()) { 1016 throw new IllegalArgumentException("features must not be empty!"); 1017 } 1018 return new MediaRoute2Info(this); 1019 } 1020 } 1021 } 1022