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