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