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