MediaRouteDescriptor.java revision 893feff5ea67f24af45af6dc9d6d09640ea66b86
1/* 2 * Copyright (C) 2013 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 */ 16package android.support.v7.media; 17 18import android.content.IntentFilter; 19import android.content.IntentSender; 20import android.net.Uri; 21import android.os.Bundle; 22import android.text.TextUtils; 23 24import java.util.ArrayList; 25import java.util.Arrays; 26import java.util.Collection; 27import java.util.Collections; 28import java.util.List; 29 30/** 31 * Describes the properties of a route. 32 * <p> 33 * Each route is uniquely identified by an opaque id string. This token 34 * may take any form as long as it is unique within the media route provider. 35 * </p><p> 36 * This object is immutable once created using a {@link Builder} instance. 37 * </p> 38 */ 39public final class MediaRouteDescriptor { 40 private static final String KEY_ID = "id"; 41 private static final String KEY_GROUP_MEMBER_IDS = "groupMemberIds"; 42 private static final String KEY_NAME = "name"; 43 private static final String KEY_DESCRIPTION = "status"; 44 private static final String KEY_ICON_URI = "iconUri"; 45 private static final String KEY_ENABLED = "enabled"; 46 private static final String KEY_CONNECTING = "connecting"; 47 private static final String KEY_CONNECTION_STATE = "connectionState"; 48 private static final String KEY_CONTROL_FILTERS = "controlFilters"; 49 private static final String KEY_PLAYBACK_TYPE = "playbackType"; 50 private static final String KEY_PLAYBACK_STREAM = "playbackStream"; 51 private static final String KEY_DEVICE_TYPE = "deviceType"; 52 private static final String KEY_VOLUME = "volume"; 53 private static final String KEY_VOLUME_MAX = "volumeMax"; 54 private static final String KEY_VOLUME_HANDLING = "volumeHandling"; 55 private static final String KEY_PRESENTATION_DISPLAY_ID = "presentationDisplayId"; 56 private static final String KEY_EXTRAS = "extras"; 57 private static final String KEY_CAN_DISCONNECT = "canDisconnect"; 58 private static final String KEY_SETTINGS_INTENT = "settingsIntent"; 59 60 private final Bundle mBundle; 61 private List<IntentFilter> mControlFilters; 62 63 private MediaRouteDescriptor(Bundle bundle, List<IntentFilter> controlFilters) { 64 mBundle = bundle; 65 mControlFilters = controlFilters; 66 } 67 68 /** 69 * Gets the unique id of the route. 70 * <p> 71 * The route id associated with a route descriptor functions as a stable 72 * identifier for the route and must be unique among all routes offered 73 * by the provider. 74 * </p> 75 */ 76 public String getId() { 77 return mBundle.getString(KEY_ID); 78 } 79 80 /** 81 * Gets the group member ids of the route. 82 * <p> 83 * A route descriptor that has one or more group member route ids 84 * represents a route group. A member route may belong to another group. 85 * </p> 86 * @hide 87 * STOPSHIP: Unhide or remove. 88 */ 89 public List<String> getGroupMemberIds() { 90 return mBundle.getStringArrayList(KEY_GROUP_MEMBER_IDS); 91 } 92 93 /** 94 * Gets the user-visible name of the route. 95 * <p> 96 * The route name identifies the destination represented by the route. 97 * It may be a user-supplied name, an alias, or device serial number. 98 * </p> 99 */ 100 public String getName() { 101 return mBundle.getString(KEY_NAME); 102 } 103 104 /** 105 * Gets the user-visible description of the route. 106 * <p> 107 * The route description describes the kind of destination represented by the route. 108 * It may be a user-supplied string, a model number or brand of device. 109 * </p> 110 */ 111 public String getDescription() { 112 return mBundle.getString(KEY_DESCRIPTION); 113 } 114 115 /** 116 * Gets the URI of the icon representing this route. 117 * <p> 118 * This icon will be used in picker UIs if available. 119 * </p> 120 * @hide 121 * STOPSHIP: Unhide or remove. 122 */ 123 public Uri getIconUri() { 124 String iconUri = mBundle.getString(KEY_ICON_URI); 125 return iconUri == null ? null : Uri.parse(iconUri); 126 } 127 128 /** 129 * Gets whether the route is enabled. 130 */ 131 public boolean isEnabled() { 132 return mBundle.getBoolean(KEY_ENABLED, true); 133 } 134 135 /** 136 * Gets whether the route is connecting. 137 * STOPSHIP: Deprecate or keep. 138 */ 139 public boolean isConnecting() { 140 return mBundle.getBoolean(KEY_CONNECTING, false); 141 } 142 143 /** 144 * Gets the connection state of the route. 145 * @hide 146 * STOPSHIP: Unhide or remove. 147 */ 148 public int getConnectionState() { 149 return mBundle.getInt(KEY_CONNECTION_STATE, 150 MediaRouter.RouteInfo.CONNECTION_STATE_DISCONNECTED); 151 } 152 153 /** 154 * Gets whether the route can be disconnected without stopping playback. 155 * <p> 156 * The route can normally be disconnected without stopping playback when 157 * the destination device on the route is connected to two or more source 158 * devices. The route provider should update the route immediately when the 159 * number of connected devices changes. 160 * </p><p> 161 * To specify that the route should disconnect without stopping use 162 * {@link MediaRouter#unselect(int)} with 163 * {@link MediaRouter#UNSELECT_REASON_DISCONNECTED}. 164 * </p> 165 */ 166 public boolean canDisconnectAndKeepPlaying() { 167 return mBundle.getBoolean(KEY_CAN_DISCONNECT, false); 168 } 169 170 /** 171 * Gets an {@link IntentSender} for starting a settings activity for this 172 * route. The activity may have specific route settings or general settings 173 * for the connected device or route provider. 174 * 175 * @return An {@link IntentSender} to start a settings activity. 176 */ 177 public IntentSender getSettingsActivity() { 178 return mBundle.getParcelable(KEY_SETTINGS_INTENT); 179 } 180 181 /** 182 * Gets the route's {@link MediaControlIntent media control intent} filters. 183 */ 184 public List<IntentFilter> getControlFilters() { 185 ensureControlFilters(); 186 return mControlFilters; 187 } 188 189 private void ensureControlFilters() { 190 if (mControlFilters == null) { 191 mControlFilters = mBundle.<IntentFilter>getParcelableArrayList(KEY_CONTROL_FILTERS); 192 if (mControlFilters == null) { 193 mControlFilters = Collections.<IntentFilter>emptyList(); 194 } 195 } 196 } 197 198 /** 199 * Gets the route's playback type. 200 */ 201 public int getPlaybackType() { 202 return mBundle.getInt(KEY_PLAYBACK_TYPE, MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE); 203 } 204 205 /** 206 * Gets the route's playback stream. 207 */ 208 public int getPlaybackStream() { 209 return mBundle.getInt(KEY_PLAYBACK_STREAM, -1); 210 } 211 212 /** 213 * Gets the route's receiver device type. 214 * 215 * @hide 216 * STOPSHIP: Unhide or remove. 217 */ 218 public int getDeviceType() { 219 return mBundle.getInt(KEY_DEVICE_TYPE); 220 } 221 222 /** 223 * Gets the route's current volume, or 0 if unknown. 224 */ 225 public int getVolume() { 226 return mBundle.getInt(KEY_VOLUME); 227 } 228 229 /** 230 * Gets the route's maximum volume, or 0 if unknown. 231 */ 232 public int getVolumeMax() { 233 return mBundle.getInt(KEY_VOLUME_MAX); 234 } 235 236 /** 237 * Gets the route's volume handling. 238 */ 239 public int getVolumeHandling() { 240 return mBundle.getInt(KEY_VOLUME_HANDLING, 241 MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED); 242 } 243 244 /** 245 * Gets the route's presentation display id, or -1 if none. 246 */ 247 public int getPresentationDisplayId() { 248 return mBundle.getInt( 249 KEY_PRESENTATION_DISPLAY_ID, MediaRouter.RouteInfo.PRESENTATION_DISPLAY_ID_NONE); 250 } 251 252 /** 253 * Gets a bundle of extras for this route descriptor. 254 * The extras will be ignored by the media router but they may be used 255 * by applications. 256 */ 257 public Bundle getExtras() { 258 return mBundle.getBundle(KEY_EXTRAS); 259 } 260 261 /** 262 * Returns true if the route descriptor has all of the required fields. 263 */ 264 public boolean isValid() { 265 ensureControlFilters(); 266 if (TextUtils.isEmpty(getId()) 267 || TextUtils.isEmpty(getName()) 268 || mControlFilters.contains(null)) { 269 return false; 270 } 271 return true; 272 } 273 274 @Override 275 public String toString() { 276 StringBuilder result = new StringBuilder(); 277 result.append("MediaRouteDescriptor{ "); 278 result.append("id=").append(getId()); 279 result.append(", groupMemberIds=").append(getGroupMemberIds()); 280 result.append(", name=").append(getName()); 281 result.append(", description=").append(getDescription()); 282 result.append(", iconUri=").append(getIconUri()); 283 result.append(", isEnabled=").append(isEnabled()); 284 result.append(", isConnecting=").append(isConnecting()); 285 result.append(", connectionState=").append(getConnectionState()); 286 result.append(", controlFilters=").append(Arrays.toString(getControlFilters().toArray())); 287 result.append(", playbackType=").append(getPlaybackType()); 288 result.append(", playbackStream=").append(getPlaybackStream()); 289 result.append(", deviceType=").append(getDeviceType()); 290 result.append(", volume=").append(getVolume()); 291 result.append(", volumeMax=").append(getVolumeMax()); 292 result.append(", volumeHandling=").append(getVolumeHandling()); 293 result.append(", presentationDisplayId=").append(getPresentationDisplayId()); 294 result.append(", extras=").append(getExtras()); 295 result.append(", isValid=").append(isValid()); 296 result.append(" }"); 297 return result.toString(); 298 } 299 300 /** 301 * Converts this object to a bundle for serialization. 302 * 303 * @return The contents of the object represented as a bundle. 304 */ 305 public Bundle asBundle() { 306 return mBundle; 307 } 308 309 /** 310 * Creates an instance from a bundle. 311 * 312 * @param bundle The bundle, or null if none. 313 * @return The new instance, or null if the bundle was null. 314 */ 315 public static MediaRouteDescriptor fromBundle(Bundle bundle) { 316 return bundle != null ? new MediaRouteDescriptor(bundle, null) : null; 317 } 318 319 /** 320 * Builder for {@link MediaRouteDescriptor media route descriptors}. 321 */ 322 public static final class Builder { 323 private final Bundle mBundle; 324 private ArrayList<String> mGroupMemberIds; 325 private ArrayList<IntentFilter> mControlFilters; 326 327 /** 328 * Creates a media route descriptor builder. 329 * 330 * @param id The unique id of the route. 331 * @param name The user-visible name of the route. 332 */ 333 public Builder(String id, String name) { 334 mBundle = new Bundle(); 335 setId(id); 336 setName(name); 337 } 338 339 /** 340 * Creates a media route descriptor builder whose initial contents are 341 * copied from an existing descriptor. 342 */ 343 public Builder(MediaRouteDescriptor descriptor) { 344 if (descriptor == null) { 345 throw new IllegalArgumentException("descriptor must not be null"); 346 } 347 348 mBundle = new Bundle(descriptor.mBundle); 349 350 descriptor.ensureControlFilters(); 351 if (!descriptor.mControlFilters.isEmpty()) { 352 mControlFilters = new ArrayList<IntentFilter>(descriptor.mControlFilters); 353 } 354 } 355 356 /** 357 * Sets the unique id of the route. 358 * <p> 359 * The route id associated with a route descriptor functions as a stable 360 * identifier for the route and must be unique among all routes offered 361 * by the provider. 362 * </p> 363 */ 364 public Builder setId(String id) { 365 mBundle.putString(KEY_ID, id); 366 return this; 367 } 368 369 /** 370 * Adds a group member id of the route. 371 * <p> 372 * A route descriptor that has one or more group member route ids 373 * represents a route group. A member route may belong to another group. 374 * </p> 375 * @hide 376 * STOPSHIP: Unhide or remove. 377 */ 378 public Builder addGroupMemberId(String groupMemberId) { 379 if (TextUtils.isEmpty(groupMemberId)) { 380 throw new IllegalArgumentException("groupMemberId must not be empty"); 381 } 382 383 if (mGroupMemberIds == null) { 384 mGroupMemberIds = new ArrayList<>(); 385 } 386 if (!mGroupMemberIds.contains(groupMemberId)) { 387 mGroupMemberIds.add(groupMemberId); 388 } 389 return this; 390 } 391 392 /** 393 * Adds a list of group member ids of the route. 394 * <p> 395 * A route descriptor that has one or more group member route ids 396 * represents a route group. A member route may belong to another group. 397 * </p> 398 * @hide 399 * STOPSHIP: Unhide or remove. 400 */ 401 public Builder addGroupMemberIds(Collection<String> groupMemberIds) { 402 if (groupMemberIds == null) { 403 throw new IllegalArgumentException("groupMemberIds must not be null"); 404 } 405 406 if (!groupMemberIds.isEmpty()) { 407 for (String groupMemberId : groupMemberIds) { 408 addGroupMemberId(groupMemberId); 409 } 410 } 411 return this; 412 } 413 414 /** 415 * Sets the user-visible name of the route. 416 * <p> 417 * The route name identifies the destination represented by the route. 418 * It may be a user-supplied name, an alias, or device serial number. 419 * </p> 420 */ 421 public Builder setName(String name) { 422 mBundle.putString(KEY_NAME, name); 423 return this; 424 } 425 426 /** 427 * Sets the user-visible description of the route. 428 * <p> 429 * The route description describes the kind of destination represented by the route. 430 * It may be a user-supplied string, a model number or brand of device. 431 * </p> 432 */ 433 public Builder setDescription(String description) { 434 mBundle.putString(KEY_DESCRIPTION, description); 435 return this; 436 } 437 438 /** 439 * Sets the URI of the icon representing this route. 440 * <p> 441 * This icon will be used in picker UIs if available. 442 * </p><p> 443 * The URI must be one of the following formats: 444 * <ul> 445 * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li> 446 * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE}) 447 * </li> 448 * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li> 449 * </ul> 450 * </p> 451 * @hide 452 * STOPSHIP: Unhide or remove. 453 */ 454 public Builder setIconUri(Uri iconUri) { 455 if (iconUri == null) { 456 throw new IllegalArgumentException("iconUri must not be null"); 457 } 458 mBundle.putString(KEY_ICON_URI, iconUri.toString()); 459 return this; 460 } 461 462 /** 463 * Sets whether the route is enabled. 464 * <p> 465 * Disabled routes represent routes that a route provider knows about, such as paired 466 * Wifi Display receivers, but that are not currently available for use. 467 * </p> 468 */ 469 public Builder setEnabled(boolean enabled) { 470 mBundle.putBoolean(KEY_ENABLED, enabled); 471 return this; 472 } 473 474 /** 475 * Sets whether the route is in the process of connecting and is not yet 476 * ready for use. 477 * STOPSHIP: Deprecate or keep. 478 */ 479 public Builder setConnecting(boolean connecting) { 480 mBundle.putBoolean(KEY_CONNECTING, connecting); 481 return this; 482 } 483 484 /** 485 * Sets the route's connection state. 486 * @hide 487 * STOPSHIP: Unhide or remove. 488 */ 489 public Builder setConnectionState(int connectionState) { 490 mBundle.putInt(KEY_CONNECTION_STATE, connectionState); 491 return this; 492 } 493 494 /** 495 * Sets whether the route can be disconnected without stopping playback. 496 */ 497 public Builder setCanDisconnect(boolean canDisconnect) { 498 mBundle.putBoolean(KEY_CAN_DISCONNECT, canDisconnect); 499 return this; 500 } 501 502 /** 503 * Sets an intent sender for launching the settings activity for this 504 * route. 505 */ 506 public Builder setSettingsActivity(IntentSender is) { 507 mBundle.putParcelable(KEY_SETTINGS_INTENT, is); 508 return this; 509 } 510 511 /** 512 * Adds a {@link MediaControlIntent media control intent} filter for the route. 513 */ 514 public Builder addControlFilter(IntentFilter filter) { 515 if (filter == null) { 516 throw new IllegalArgumentException("filter must not be null"); 517 } 518 519 if (mControlFilters == null) { 520 mControlFilters = new ArrayList<IntentFilter>(); 521 } 522 if (!mControlFilters.contains(filter)) { 523 mControlFilters.add(filter); 524 } 525 return this; 526 } 527 528 /** 529 * Adds a list of {@link MediaControlIntent media control intent} filters for the route. 530 */ 531 public Builder addControlFilters(Collection<IntentFilter> filters) { 532 if (filters == null) { 533 throw new IllegalArgumentException("filters must not be null"); 534 } 535 536 if (!filters.isEmpty()) { 537 for (IntentFilter filter : filters) { 538 addControlFilter(filter); 539 } 540 } 541 return this; 542 } 543 544 /** 545 * Sets the route's playback type. 546 */ 547 public Builder setPlaybackType(int playbackType) { 548 mBundle.putInt(KEY_PLAYBACK_TYPE, playbackType); 549 return this; 550 } 551 552 /** 553 * Sets the route's playback stream. 554 */ 555 public Builder setPlaybackStream(int playbackStream) { 556 mBundle.putInt(KEY_PLAYBACK_STREAM, playbackStream); 557 return this; 558 } 559 560 /** 561 * Sets the route's receiver device type. 562 * 563 * @hide 564 * STOPSHIP: Unhide or remove. 565 */ 566 public Builder setDeviceType(int deviceType) { 567 mBundle.putInt(KEY_DEVICE_TYPE, deviceType); 568 return this; 569 } 570 571 /** 572 * Sets the route's current volume, or 0 if unknown. 573 */ 574 public Builder setVolume(int volume) { 575 mBundle.putInt(KEY_VOLUME, volume); 576 return this; 577 } 578 579 /** 580 * Sets the route's maximum volume, or 0 if unknown. 581 */ 582 public Builder setVolumeMax(int volumeMax) { 583 mBundle.putInt(KEY_VOLUME_MAX, volumeMax); 584 return this; 585 } 586 587 /** 588 * Sets the route's volume handling. 589 */ 590 public Builder setVolumeHandling(int volumeHandling) { 591 mBundle.putInt(KEY_VOLUME_HANDLING, volumeHandling); 592 return this; 593 } 594 595 /** 596 * Sets the route's presentation display id, or -1 if none. 597 */ 598 public Builder setPresentationDisplayId(int presentationDisplayId) { 599 mBundle.putInt(KEY_PRESENTATION_DISPLAY_ID, presentationDisplayId); 600 return this; 601 } 602 603 /** 604 * Sets a bundle of extras for this route descriptor. 605 * The extras will be ignored by the media router but they may be used 606 * by applications. 607 */ 608 public Builder setExtras(Bundle extras) { 609 mBundle.putBundle(KEY_EXTRAS, extras); 610 return this; 611 } 612 613 /** 614 * Builds the {@link MediaRouteDescriptor media route descriptor}. 615 */ 616 public MediaRouteDescriptor build() { 617 if (mControlFilters != null) { 618 mBundle.putParcelableArrayList(KEY_CONTROL_FILTERS, mControlFilters); 619 } 620 if (mGroupMemberIds != null) { 621 mBundle.putStringArrayList(KEY_GROUP_MEMBER_IDS, mGroupMemberIds); 622 } 623 return new MediaRouteDescriptor(mBundle, mControlFilters); 624 } 625 } 626}