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