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