1 /* 2 * Copyright (C) 2014 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 package android.media.session; 17 18 19 import android.annotation.DrawableRes; 20 import android.annotation.IntDef; 21 import android.annotation.LongDef; 22 import android.annotation.Nullable; 23 import android.os.Bundle; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.os.SystemClock; 27 import android.text.TextUtils; 28 29 import java.lang.annotation.Retention; 30 import java.lang.annotation.RetentionPolicy; 31 import java.util.ArrayList; 32 import java.util.List; 33 34 /** 35 * Playback state for a {@link MediaSession}. This includes a state like 36 * {@link PlaybackState#STATE_PLAYING}, the current playback position, 37 * and the current control capabilities. 38 */ 39 public final class PlaybackState implements Parcelable { 40 private static final String TAG = "PlaybackState"; 41 42 /** 43 * @hide 44 */ 45 @LongDef(flag = true, value = {ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND, 46 ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING, 47 ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH, 48 ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE, 49 ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI, 50 ACTION_SET_PLAYBACK_SPEED}) 51 @Retention(RetentionPolicy.SOURCE) 52 public @interface Actions {} 53 54 /** 55 * Indicates this session supports the stop command. 56 * 57 * @see Builder#setActions(long) 58 */ 59 public static final long ACTION_STOP = 1 << 0; 60 61 /** 62 * Indicates this session supports the pause command. 63 * 64 * @see Builder#setActions(long) 65 */ 66 public static final long ACTION_PAUSE = 1 << 1; 67 68 /** 69 * Indicates this session supports the play command. 70 * 71 * @see Builder#setActions(long) 72 */ 73 public static final long ACTION_PLAY = 1 << 2; 74 75 /** 76 * Indicates this session supports the rewind command. 77 * 78 * @see Builder#setActions(long) 79 */ 80 public static final long ACTION_REWIND = 1 << 3; 81 82 /** 83 * Indicates this session supports the previous command. 84 * 85 * @see Builder#setActions(long) 86 */ 87 public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4; 88 89 /** 90 * Indicates this session supports the next command. 91 * 92 * @see Builder#setActions(long) 93 */ 94 public static final long ACTION_SKIP_TO_NEXT = 1 << 5; 95 96 /** 97 * Indicates this session supports the fast forward command. 98 * 99 * @see Builder#setActions(long) 100 */ 101 public static final long ACTION_FAST_FORWARD = 1 << 6; 102 103 /** 104 * Indicates this session supports the set rating command. 105 * 106 * @see Builder#setActions(long) 107 */ 108 public static final long ACTION_SET_RATING = 1 << 7; 109 110 /** 111 * Indicates this session supports the seek to command. 112 * 113 * @see Builder#setActions(long) 114 */ 115 public static final long ACTION_SEEK_TO = 1 << 8; 116 117 /** 118 * Indicates this session supports the play/pause toggle command. 119 * 120 * @see Builder#setActions(long) 121 */ 122 public static final long ACTION_PLAY_PAUSE = 1 << 9; 123 124 /** 125 * Indicates this session supports the play from media id command. 126 * 127 * @see Builder#setActions(long) 128 */ 129 public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10; 130 131 /** 132 * Indicates this session supports the play from search command. 133 * 134 * @see Builder#setActions(long) 135 */ 136 public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11; 137 138 /** 139 * Indicates this session supports the skip to queue item command. 140 * 141 * @see Builder#setActions(long) 142 */ 143 public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12; 144 145 /** 146 * Indicates this session supports the play from URI command. 147 * 148 * @see Builder#setActions(long) 149 */ 150 public static final long ACTION_PLAY_FROM_URI = 1 << 13; 151 152 /** 153 * Indicates this session supports the prepare command. 154 * 155 * @see Builder#setActions(long) 156 */ 157 public static final long ACTION_PREPARE = 1 << 14; 158 159 /** 160 * Indicates this session supports the prepare from media id command. 161 * 162 * @see Builder#setActions(long) 163 */ 164 public static final long ACTION_PREPARE_FROM_MEDIA_ID = 1 << 15; 165 166 /** 167 * Indicates this session supports the prepare from search command. 168 * 169 * @see Builder#setActions(long) 170 */ 171 public static final long ACTION_PREPARE_FROM_SEARCH = 1 << 16; 172 173 /** 174 * Indicates this session supports the prepare from URI command. 175 * 176 * @see Builder#setActions(long) 177 */ 178 public static final long ACTION_PREPARE_FROM_URI = 1 << 17; 179 180 // Note: The value jumps from 1 << 17 to 1 << 22 for matching same value with AndroidX. 181 /** 182 * Indicates this session supports the set playback speed command. 183 * 184 * @see Builder#setActions(long) 185 */ 186 public static final long ACTION_SET_PLAYBACK_SPEED = 1 << 22; 187 188 /** @hide */ 189 @IntDef({ 190 STATE_NONE, 191 STATE_STOPPED, 192 STATE_PAUSED, 193 STATE_PLAYING, 194 STATE_FAST_FORWARDING, 195 STATE_REWINDING, 196 STATE_BUFFERING, 197 STATE_ERROR, 198 STATE_CONNECTING, 199 STATE_SKIPPING_TO_PREVIOUS, 200 STATE_SKIPPING_TO_NEXT, 201 STATE_SKIPPING_TO_QUEUE_ITEM 202 }) 203 @Retention(RetentionPolicy.SOURCE) 204 public @interface State {} 205 206 /** 207 * This is the default playback state and indicates that no media has been 208 * added yet, or the performer has been reset and has no content to play. 209 * 210 * @see Builder#setState(int, long, float) 211 * @see Builder#setState(int, long, float, long) 212 */ 213 public static final int STATE_NONE = 0; 214 215 /** 216 * State indicating this item is currently stopped. 217 * 218 * @see Builder#setState 219 */ 220 public static final int STATE_STOPPED = 1; 221 222 /** 223 * State indicating this item is currently paused. 224 * 225 * @see Builder#setState 226 */ 227 public static final int STATE_PAUSED = 2; 228 229 /** 230 * State indicating this item is currently playing. 231 * 232 * @see Builder#setState 233 */ 234 public static final int STATE_PLAYING = 3; 235 236 /** 237 * State indicating this item is currently fast forwarding. 238 * 239 * @see Builder#setState 240 */ 241 public static final int STATE_FAST_FORWARDING = 4; 242 243 /** 244 * State indicating this item is currently rewinding. 245 * 246 * @see Builder#setState 247 */ 248 public static final int STATE_REWINDING = 5; 249 250 /** 251 * State indicating this item is currently buffering and will begin playing 252 * when enough data has buffered. 253 * 254 * @see Builder#setState 255 */ 256 public static final int STATE_BUFFERING = 6; 257 258 /** 259 * State indicating this item is currently in an error state. The error 260 * message should also be set when entering this state. 261 * 262 * @see Builder#setState 263 */ 264 public static final int STATE_ERROR = 7; 265 266 /** 267 * State indicating the class doing playback is currently connecting to a 268 * new destination. Depending on the implementation you may return to the previous 269 * state when the connection finishes or enter {@link #STATE_NONE}. 270 * If the connection failed {@link #STATE_ERROR} should be used. 271 * 272 * @see Builder#setState 273 */ 274 public static final int STATE_CONNECTING = 8; 275 276 /** 277 * State indicating the player is currently skipping to the previous item. 278 * 279 * @see Builder#setState 280 */ 281 public static final int STATE_SKIPPING_TO_PREVIOUS = 9; 282 283 /** 284 * State indicating the player is currently skipping to the next item. 285 * 286 * @see Builder#setState 287 */ 288 public static final int STATE_SKIPPING_TO_NEXT = 10; 289 290 /** 291 * State indicating the player is currently skipping to a specific item in 292 * the queue. 293 * 294 * @see Builder#setState 295 */ 296 public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; 297 298 /** 299 * Use this value for the position to indicate the position is not known. 300 */ 301 public static final long PLAYBACK_POSITION_UNKNOWN = -1; 302 303 private final int mState; 304 private final long mPosition; 305 private final long mBufferedPosition; 306 private final float mSpeed; 307 private final long mActions; 308 private List<PlaybackState.CustomAction> mCustomActions; 309 private final CharSequence mErrorMessage; 310 private final long mUpdateTime; 311 private final long mActiveItemId; 312 private final Bundle mExtras; 313 PlaybackState(int state, long position, long updateTime, float speed, long bufferedPosition, long transportControls, List<PlaybackState.CustomAction> customActions, long activeItemId, CharSequence error, Bundle extras)314 private PlaybackState(int state, long position, long updateTime, float speed, 315 long bufferedPosition, long transportControls, 316 List<PlaybackState.CustomAction> customActions, long activeItemId, 317 CharSequence error, Bundle extras) { 318 mState = state; 319 mPosition = position; 320 mSpeed = speed; 321 mUpdateTime = updateTime; 322 mBufferedPosition = bufferedPosition; 323 mActions = transportControls; 324 mCustomActions = new ArrayList<>(customActions); 325 mActiveItemId = activeItemId; 326 mErrorMessage = error; 327 mExtras = extras; 328 } 329 PlaybackState(Parcel in)330 private PlaybackState(Parcel in) { 331 mState = in.readInt(); 332 mPosition = in.readLong(); 333 mSpeed = in.readFloat(); 334 mUpdateTime = in.readLong(); 335 mBufferedPosition = in.readLong(); 336 mActions = in.readLong(); 337 mCustomActions = in.createTypedArrayList(CustomAction.CREATOR); 338 mActiveItemId = in.readLong(); 339 mErrorMessage = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 340 mExtras = in.readBundle(); 341 } 342 343 @Override toString()344 public String toString() { 345 StringBuilder bob = new StringBuilder("PlaybackState {"); 346 bob.append("state=") 347 .append(getStringForStateInt(mState)) 348 .append("(") 349 .append(mState) 350 .append(")"); 351 bob.append(", position=").append(mPosition); 352 bob.append(", buffered position=").append(mBufferedPosition); 353 bob.append(", speed=").append(mSpeed); 354 bob.append(", updated=").append(mUpdateTime); 355 bob.append(", actions=").append(mActions); 356 bob.append(", custom actions=").append(mCustomActions); 357 bob.append(", active item id=").append(mActiveItemId); 358 bob.append(", error=").append(mErrorMessage); 359 bob.append("}"); 360 return bob.toString(); 361 } 362 363 @Override describeContents()364 public int describeContents() { 365 return 0; 366 } 367 368 @Override writeToParcel(Parcel dest, int flags)369 public void writeToParcel(Parcel dest, int flags) { 370 dest.writeInt(mState); 371 dest.writeLong(mPosition); 372 dest.writeFloat(mSpeed); 373 dest.writeLong(mUpdateTime); 374 dest.writeLong(mBufferedPosition); 375 dest.writeLong(mActions); 376 dest.writeTypedList(mCustomActions); 377 dest.writeLong(mActiveItemId); 378 TextUtils.writeToParcel(mErrorMessage, dest, 0); 379 dest.writeBundle(mExtras); 380 } 381 382 /** 383 * Get the current state of playback. One of the following: 384 * <ul> 385 * <li> {@link PlaybackState#STATE_NONE}</li> 386 * <li> {@link PlaybackState#STATE_STOPPED}</li> 387 * <li> {@link PlaybackState#STATE_PLAYING}</li> 388 * <li> {@link PlaybackState#STATE_PAUSED}</li> 389 * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li> 390 * <li> {@link PlaybackState#STATE_REWINDING}</li> 391 * <li> {@link PlaybackState#STATE_BUFFERING}</li> 392 * <li> {@link PlaybackState#STATE_ERROR}</li> 393 * <li> {@link PlaybackState#STATE_CONNECTING}</li> 394 * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li> 395 * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li> 396 * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li> 397 * </ul> 398 */ 399 @State getState()400 public int getState() { 401 return mState; 402 } 403 404 /** 405 * Get the current playback position in ms. 406 */ getPosition()407 public long getPosition() { 408 return mPosition; 409 } 410 411 /** 412 * Get the current buffered position in ms. This is the farthest playback 413 * point that can be reached from the current position using only buffered 414 * content. 415 */ getBufferedPosition()416 public long getBufferedPosition() { 417 return mBufferedPosition; 418 } 419 420 /** 421 * Get the current playback speed as a multiple of normal playback. This 422 * should be negative when rewinding. A value of 1 means normal playback and 423 * 0 means paused. 424 * 425 * @return The current speed of playback. 426 */ getPlaybackSpeed()427 public float getPlaybackSpeed() { 428 return mSpeed; 429 } 430 431 /** 432 * Get the current actions available on this session. This should use a 433 * bitmask of the available actions. 434 * <ul> 435 * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li> 436 * <li> {@link PlaybackState#ACTION_REWIND}</li> 437 * <li> {@link PlaybackState#ACTION_PLAY}</li> 438 * <li> {@link PlaybackState#ACTION_PAUSE}</li> 439 * <li> {@link PlaybackState#ACTION_STOP}</li> 440 * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li> 441 * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li> 442 * <li> {@link PlaybackState#ACTION_SEEK_TO}</li> 443 * <li> {@link PlaybackState#ACTION_SET_RATING}</li> 444 * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li> 445 * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li> 446 * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li> 447 * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li> 448 * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li> 449 * <li> {@link PlaybackState#ACTION_PREPARE}</li> 450 * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li> 451 * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li> 452 * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li> 453 * <li> {@link PlaybackState#ACTION_SET_PLAYBACK_SPEED}</li> 454 * </ul> 455 */ 456 @Actions getActions()457 public long getActions() { 458 return mActions; 459 } 460 461 /** 462 * Get the list of custom actions. 463 */ getCustomActions()464 public List<PlaybackState.CustomAction> getCustomActions() { 465 return mCustomActions; 466 } 467 468 /** 469 * Get a user readable error message. This should be set when the state is 470 * {@link PlaybackState#STATE_ERROR}. 471 */ getErrorMessage()472 public CharSequence getErrorMessage() { 473 return mErrorMessage; 474 } 475 476 /** 477 * Get the elapsed real time at which position was last updated. If the 478 * position has never been set this will return 0; 479 * 480 * @return The last time the position was updated. 481 */ getLastPositionUpdateTime()482 public long getLastPositionUpdateTime() { 483 return mUpdateTime; 484 } 485 486 /** 487 * Get the id of the currently active item in the queue. If there is no 488 * queue or a queue is not supported by the session this will be 489 * {@link MediaSession.QueueItem#UNKNOWN_ID}. 490 * 491 * @return The id of the currently active item in the queue or 492 * {@link MediaSession.QueueItem#UNKNOWN_ID}. 493 */ getActiveQueueItemId()494 public long getActiveQueueItemId() { 495 return mActiveItemId; 496 } 497 498 /** 499 * Get any custom extras that were set on this playback state. 500 * 501 * @return The extras for this state or null. 502 */ getExtras()503 public @Nullable Bundle getExtras() { 504 return mExtras; 505 } 506 507 /** 508 * Returns whether this is considered as an active playback state. 509 * <p> 510 * The playback state is considered as an active if the state is one of the following: 511 * <ul> 512 * <li>{@link #STATE_BUFFERING}</li> 513 * <li>{@link #STATE_CONNECTING}</li> 514 * <li>{@link #STATE_FAST_FORWARDING}</li> 515 * <li>{@link #STATE_PLAYING}</li> 516 * <li>{@link #STATE_REWINDING}</li> 517 * <li>{@link #STATE_SKIPPING_TO_NEXT}</li> 518 * <li>{@link #STATE_SKIPPING_TO_PREVIOUS}</li> 519 * <li>{@link #STATE_SKIPPING_TO_QUEUE_ITEM}</li> 520 * </ul> 521 */ isActive()522 public boolean isActive() { 523 switch (mState) { 524 case PlaybackState.STATE_FAST_FORWARDING: 525 case PlaybackState.STATE_REWINDING: 526 case PlaybackState.STATE_SKIPPING_TO_PREVIOUS: 527 case PlaybackState.STATE_SKIPPING_TO_NEXT: 528 case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM: 529 case PlaybackState.STATE_BUFFERING: 530 case PlaybackState.STATE_CONNECTING: 531 case PlaybackState.STATE_PLAYING: 532 return true; 533 } 534 return false; 535 } 536 537 public static final @android.annotation.NonNull Parcelable.Creator<PlaybackState> CREATOR = 538 new Parcelable.Creator<PlaybackState>() { 539 @Override 540 public PlaybackState createFromParcel(Parcel in) { 541 return new PlaybackState(in); 542 } 543 544 @Override 545 public PlaybackState[] newArray(int size) { 546 return new PlaybackState[size]; 547 } 548 }; 549 550 /** Returns a human readable string representation of the given int {@code state} */ getStringForStateInt(int state)551 private static String getStringForStateInt(int state) { 552 switch (state) { 553 case STATE_NONE: 554 return "NONE"; 555 case STATE_STOPPED: 556 return "STOPPED"; 557 case STATE_PAUSED: 558 return "PAUSED"; 559 case STATE_PLAYING: 560 return "PLAYING"; 561 case STATE_FAST_FORWARDING: 562 return "FAST_FORWARDING"; 563 case STATE_REWINDING: 564 return "REWINDING"; 565 case STATE_BUFFERING: 566 return "BUFFERING"; 567 case STATE_ERROR: 568 return "ERROR"; 569 case STATE_CONNECTING: 570 return "CONNECTING"; 571 case STATE_SKIPPING_TO_PREVIOUS: 572 return "SKIPPING_TO_PREVIOUS"; 573 case STATE_SKIPPING_TO_NEXT: 574 return "SKIPPING_TO_NEXT"; 575 case STATE_SKIPPING_TO_QUEUE_ITEM: 576 return "SKIPPING_TO_QUEUE_ITEM"; 577 default: 578 return "UNKNOWN"; 579 } 580 } 581 582 /** 583 * {@link PlaybackState.CustomAction CustomActions} can be used to extend the capabilities of 584 * the standard transport controls by exposing app specific actions to 585 * {@link MediaController MediaControllers}. 586 */ 587 public static final class CustomAction implements Parcelable { 588 private final String mAction; 589 private final CharSequence mName; 590 private final int mIcon; 591 private final Bundle mExtras; 592 593 /** 594 * Use {@link PlaybackState.CustomAction.Builder#build()}. 595 */ CustomAction(String action, CharSequence name, int icon, Bundle extras)596 private CustomAction(String action, CharSequence name, int icon, Bundle extras) { 597 mAction = action; 598 mName = name; 599 mIcon = icon; 600 mExtras = extras; 601 } 602 CustomAction(Parcel in)603 private CustomAction(Parcel in) { 604 mAction = in.readString(); 605 mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 606 mIcon = in.readInt(); 607 mExtras = in.readBundle(); 608 } 609 610 @Override writeToParcel(Parcel dest, int flags)611 public void writeToParcel(Parcel dest, int flags) { 612 dest.writeString(mAction); 613 TextUtils.writeToParcel(mName, dest, flags); 614 dest.writeInt(mIcon); 615 dest.writeBundle(mExtras); 616 } 617 618 @Override describeContents()619 public int describeContents() { 620 return 0; 621 } 622 623 public static final @android.annotation.NonNull Parcelable.Creator<PlaybackState.CustomAction> CREATOR = 624 new Parcelable.Creator<PlaybackState.CustomAction>() { 625 626 @Override 627 public PlaybackState.CustomAction createFromParcel(Parcel p) { 628 return new PlaybackState.CustomAction(p); 629 } 630 631 @Override 632 public PlaybackState.CustomAction[] newArray(int size) { 633 return new PlaybackState.CustomAction[size]; 634 } 635 }; 636 637 /** 638 * Returns the action of the {@link CustomAction}. 639 * 640 * @return The action of the {@link CustomAction}. 641 */ getAction()642 public String getAction() { 643 return mAction; 644 } 645 646 /** 647 * Returns the display name of this action. e.g. "Favorite" 648 * 649 * @return The display name of this {@link CustomAction}. 650 */ getName()651 public CharSequence getName() { 652 return mName; 653 } 654 655 /** 656 * Returns the resource id of the icon in the {@link MediaSession MediaSession's} package. 657 * 658 * @return The resource id of the icon in the {@link MediaSession MediaSession's} package. 659 */ getIcon()660 public int getIcon() { 661 return mIcon; 662 } 663 664 /** 665 * Returns extras which provide additional application-specific information about the 666 * action, or null if none. These arguments are meant to be consumed by a 667 * {@link MediaController} if it knows how to handle them. 668 * 669 * @return Optional arguments for the {@link CustomAction}. 670 */ getExtras()671 public Bundle getExtras() { 672 return mExtras; 673 } 674 675 @Override toString()676 public String toString() { 677 return "Action:" + "mName='" + mName + ", mIcon=" + mIcon + ", mExtras=" + mExtras; 678 } 679 680 /** 681 * Builder for {@link CustomAction} objects. 682 */ 683 public static final class Builder { 684 private final String mAction; 685 private final CharSequence mName; 686 private final int mIcon; 687 private Bundle mExtras; 688 689 /** 690 * Creates a {@link CustomAction} builder with the id, name, and icon set. 691 * 692 * @param action The action of the {@link CustomAction}. 693 * @param name The display name of the {@link CustomAction}. This name will be displayed 694 * along side the action if the UI supports it. 695 * @param icon The icon resource id of the {@link CustomAction}. This resource id 696 * must be in the same package as the {@link MediaSession}. It will be 697 * displayed with the custom action if the UI supports it. 698 */ Builder(String action, CharSequence name, @DrawableRes int icon)699 public Builder(String action, CharSequence name, @DrawableRes int icon) { 700 if (TextUtils.isEmpty(action)) { 701 throw new IllegalArgumentException( 702 "You must specify an action to build a CustomAction."); 703 } 704 if (TextUtils.isEmpty(name)) { 705 throw new IllegalArgumentException( 706 "You must specify a name to build a CustomAction."); 707 } 708 if (icon == 0) { 709 throw new IllegalArgumentException( 710 "You must specify an icon resource id to build a CustomAction."); 711 } 712 mAction = action; 713 mName = name; 714 mIcon = icon; 715 } 716 717 /** 718 * Set optional extras for the {@link CustomAction}. These extras are meant to be 719 * consumed by a {@link MediaController} if it knows how to handle them. 720 * Keys should be fully qualified (e.g. "com.example.MY_ARG") to avoid collisions. 721 * 722 * @param extras Optional extras for the {@link CustomAction}. 723 * @return this. 724 */ setExtras(Bundle extras)725 public Builder setExtras(Bundle extras) { 726 mExtras = extras; 727 return this; 728 } 729 730 /** 731 * Build and return the {@link CustomAction} instance with the specified values. 732 * 733 * @return A new {@link CustomAction} instance. 734 */ build()735 public CustomAction build() { 736 return new CustomAction(mAction, mName, mIcon, mExtras); 737 } 738 } 739 } 740 741 /** 742 * Builder for {@link PlaybackState} objects. 743 */ 744 public static final class Builder { 745 private final List<PlaybackState.CustomAction> mCustomActions = new ArrayList<>(); 746 747 private int mState; 748 private long mPosition; 749 private long mBufferedPosition; 750 private float mSpeed; 751 private long mActions; 752 private CharSequence mErrorMessage; 753 private long mUpdateTime; 754 private long mActiveItemId = MediaSession.QueueItem.UNKNOWN_ID; 755 private Bundle mExtras; 756 757 /** 758 * Creates an initially empty state builder. 759 */ Builder()760 public Builder() { 761 } 762 763 /** 764 * Creates a builder with the same initial values as those in the from 765 * state. 766 * 767 * @param from The state to use for initializing the builder. 768 */ Builder(PlaybackState from)769 public Builder(PlaybackState from) { 770 if (from == null) { 771 return; 772 } 773 mState = from.mState; 774 mPosition = from.mPosition; 775 mBufferedPosition = from.mBufferedPosition; 776 mSpeed = from.mSpeed; 777 mActions = from.mActions; 778 if (from.mCustomActions != null) { 779 mCustomActions.addAll(from.mCustomActions); 780 } 781 mErrorMessage = from.mErrorMessage; 782 mUpdateTime = from.mUpdateTime; 783 mActiveItemId = from.mActiveItemId; 784 mExtras = from.mExtras; 785 } 786 787 /** 788 * Set the current state of playback. 789 * <p> 790 * The position must be in ms and indicates the current playback 791 * position within the item. If the position is unknown use 792 * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown 793 * position the time at which the position was updated must be provided. 794 * It is okay to use {@link SystemClock#elapsedRealtime()} if the 795 * current position was just retrieved. 796 * <p> 797 * The speed is a multiple of normal playback and should be 0 when 798 * paused and negative when rewinding. Normal playback speed is 1.0. 799 * <p> 800 * The state must be one of the following: 801 * <ul> 802 * <li> {@link PlaybackState#STATE_NONE}</li> 803 * <li> {@link PlaybackState#STATE_STOPPED}</li> 804 * <li> {@link PlaybackState#STATE_PLAYING}</li> 805 * <li> {@link PlaybackState#STATE_PAUSED}</li> 806 * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li> 807 * <li> {@link PlaybackState#STATE_REWINDING}</li> 808 * <li> {@link PlaybackState#STATE_BUFFERING}</li> 809 * <li> {@link PlaybackState#STATE_ERROR}</li> 810 * <li> {@link PlaybackState#STATE_CONNECTING}</li> 811 * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li> 812 * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li> 813 * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li> 814 * </ul> 815 * 816 * @param state The current state of playback. 817 * @param position The position in the current item in ms. 818 * @param playbackSpeed The current speed of playback as a multiple of 819 * normal playback. 820 * @param updateTime The time in the {@link SystemClock#elapsedRealtime} 821 * timebase that the position was updated at. 822 * @return this 823 */ setState(@tate int state, long position, float playbackSpeed, long updateTime)824 public Builder setState(@State int state, long position, float playbackSpeed, 825 long updateTime) { 826 mState = state; 827 mPosition = position; 828 mUpdateTime = updateTime; 829 mSpeed = playbackSpeed; 830 return this; 831 } 832 833 /** 834 * Set the current state of playback. 835 * <p> 836 * The position must be in ms and indicates the current playback 837 * position within the item. If the position is unknown use 838 * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to 839 * the current {@link SystemClock#elapsedRealtime()}. 840 * <p> 841 * The speed is a multiple of normal playback and should be 0 when 842 * paused and negative when rewinding. Normal playback speed is 1.0. 843 * <p> 844 * The state must be one of the following: 845 * <ul> 846 * <li> {@link PlaybackState#STATE_NONE}</li> 847 * <li> {@link PlaybackState#STATE_STOPPED}</li> 848 * <li> {@link PlaybackState#STATE_PLAYING}</li> 849 * <li> {@link PlaybackState#STATE_PAUSED}</li> 850 * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li> 851 * <li> {@link PlaybackState#STATE_REWINDING}</li> 852 * <li> {@link PlaybackState#STATE_BUFFERING}</li> 853 * <li> {@link PlaybackState#STATE_ERROR}</li> 854 * <li> {@link PlaybackState#STATE_CONNECTING}</li> 855 * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li> 856 * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li> 857 * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li> 858 * </ul> 859 * 860 * @param state The current state of playback. 861 * @param position The position in the current item in ms. 862 * @param playbackSpeed The current speed of playback as a multiple of 863 * normal playback. 864 * @return this 865 */ setState(@tate int state, long position, float playbackSpeed)866 public Builder setState(@State int state, long position, float playbackSpeed) { 867 return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime()); 868 } 869 870 /** 871 * Set the current actions available on this session. This should use a 872 * bitmask of possible actions. 873 * <ul> 874 * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li> 875 * <li> {@link PlaybackState#ACTION_REWIND}</li> 876 * <li> {@link PlaybackState#ACTION_PLAY}</li> 877 * <li> {@link PlaybackState#ACTION_PAUSE}</li> 878 * <li> {@link PlaybackState#ACTION_STOP}</li> 879 * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li> 880 * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li> 881 * <li> {@link PlaybackState#ACTION_SEEK_TO}</li> 882 * <li> {@link PlaybackState#ACTION_SET_RATING}</li> 883 * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li> 884 * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li> 885 * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li> 886 * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li> 887 * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li> 888 * <li> {@link PlaybackState#ACTION_PREPARE}</li> 889 * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li> 890 * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li> 891 * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li> 892 * <li> {@link PlaybackState#ACTION_SET_PLAYBACK_SPEED}</li> 893 * </ul> 894 * 895 * @param actions The set of actions allowed. 896 * @return this 897 */ setActions(@ctions long actions)898 public Builder setActions(@Actions long actions) { 899 mActions = actions; 900 return this; 901 } 902 903 /** 904 * Add a custom action to the playback state. Actions can be used to 905 * expose additional functionality to {@link MediaController 906 * MediaControllers} beyond what is offered by the standard transport 907 * controls. 908 * <p> 909 * e.g. start a radio station based on the current item or skip ahead by 910 * 30 seconds. 911 * 912 * @param action An identifier for this action. It can be sent back to 913 * the {@link MediaSession} through 914 * {@link MediaController.TransportControls#sendCustomAction(String, Bundle)}. 915 * @param name The display name for the action. If text is shown with 916 * the action or used for accessibility, this is what should 917 * be used. 918 * @param icon The resource action of the icon that should be displayed 919 * for the action. The resource should be in the package of 920 * the {@link MediaSession}. 921 * @return this 922 */ addCustomAction(String action, String name, int icon)923 public Builder addCustomAction(String action, String name, int icon) { 924 return addCustomAction(new PlaybackState.CustomAction(action, name, icon, null)); 925 } 926 927 /** 928 * Add a custom action to the playback state. Actions can be used to expose additional 929 * functionality to {@link MediaController MediaControllers} beyond what is offered by the 930 * standard transport controls. 931 * <p> 932 * An example of an action would be to start a radio station based on the current item 933 * or to skip ahead by 30 seconds. 934 * 935 * @param customAction The custom action to add to the {@link PlaybackState}. 936 * @return this 937 */ addCustomAction(PlaybackState.CustomAction customAction)938 public Builder addCustomAction(PlaybackState.CustomAction customAction) { 939 if (customAction == null) { 940 throw new IllegalArgumentException( 941 "You may not add a null CustomAction to PlaybackState."); 942 } 943 mCustomActions.add(customAction); 944 return this; 945 } 946 947 /** 948 * Set the current buffered position in ms. This is the farthest 949 * playback point that can be reached from the current position using 950 * only buffered content. 951 * 952 * @param bufferedPosition The position in ms that playback is buffered 953 * to. 954 * @return this 955 */ setBufferedPosition(long bufferedPosition)956 public Builder setBufferedPosition(long bufferedPosition) { 957 mBufferedPosition = bufferedPosition; 958 return this; 959 } 960 961 /** 962 * Set the active item in the play queue by specifying its id. The 963 * default value is {@link MediaSession.QueueItem#UNKNOWN_ID} 964 * 965 * @param id The id of the active item. 966 * @return this 967 */ setActiveQueueItemId(long id)968 public Builder setActiveQueueItemId(long id) { 969 mActiveItemId = id; 970 return this; 971 } 972 973 /** 974 * Set a user readable error message. This should be set when the state 975 * is {@link PlaybackState#STATE_ERROR}. 976 * 977 * @param error The error message for display to the user. 978 * @return this 979 */ setErrorMessage(CharSequence error)980 public Builder setErrorMessage(CharSequence error) { 981 mErrorMessage = error; 982 return this; 983 } 984 985 /** 986 * Set any custom extras to be included with the playback state. 987 * 988 * @param extras The extras to include. 989 * @return this 990 */ setExtras(Bundle extras)991 public Builder setExtras(Bundle extras) { 992 mExtras = extras; 993 return this; 994 } 995 996 /** 997 * Build and return the {@link PlaybackState} instance with these 998 * values. 999 * 1000 * @return A new state instance. 1001 */ build()1002 public PlaybackState build() { 1003 return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferedPosition, 1004 mActions, mCustomActions, mActiveItemId, mErrorMessage, mExtras); 1005 } 1006 } 1007 } 1008