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