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