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