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.support.v4.media.session; 17 18 import android.os.Build; 19 import android.os.Bundle; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 import android.os.SystemClock; 23 import android.text.TextUtils; 24 25 /** 26 * Playback state for a {@link MediaSessionCompat}. This includes a state like 27 * {@link PlaybackStateCompat#STATE_PLAYING}, the current playback position, 28 * and the current control capabilities. 29 */ 30 public final class PlaybackStateCompat implements Parcelable { 31 32 /** 33 * Indicates this session supports the stop command. 34 * 35 * @see Builder#setActions(long) 36 */ 37 public static final long ACTION_STOP = 1 << 0; 38 39 /** 40 * Indicates this session supports the pause command. 41 * 42 * @see Builder#setActions(long) 43 */ 44 public static final long ACTION_PAUSE = 1 << 1; 45 46 /** 47 * Indicates this session supports the play command. 48 * 49 * @see Builder#setActions(long) 50 */ 51 public static final long ACTION_PLAY = 1 << 2; 52 53 /** 54 * Indicates this session supports the rewind command. 55 * 56 * @see Builder#setActions(long) 57 */ 58 public static final long ACTION_REWIND = 1 << 3; 59 60 /** 61 * Indicates this session supports the previous command. 62 * 63 * @see Builder#setActions(long) 64 */ 65 public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4; 66 67 /** 68 * Indicates this session supports the next command. 69 * 70 * @see Builder#setActions(long) 71 */ 72 public static final long ACTION_SKIP_TO_NEXT = 1 << 5; 73 74 /** 75 * Indicates this session supports the fast forward command. 76 * 77 * @see Builder#setActions(long) 78 */ 79 public static final long ACTION_FAST_FORWARD = 1 << 6; 80 81 /** 82 * Indicates this session supports the set rating command. 83 * 84 * @see Builder#setActions(long) 85 */ 86 public static final long ACTION_SET_RATING = 1 << 7; 87 88 /** 89 * Indicates this session supports the seek to command. 90 * 91 * @see Builder#setActions(long) 92 */ 93 public static final long ACTION_SEEK_TO = 1 << 8; 94 95 /** 96 * Indicates this session supports the play/pause toggle command. 97 * 98 * @see Builder#setActions(long) 99 */ 100 public static final long ACTION_PLAY_PAUSE = 1 << 9; 101 102 /** 103 * Indicates this session supports the play from media id command. 104 * 105 * @see Builder#setActions(long) 106 */ 107 public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10; 108 109 /** 110 * Indicates this session supports the play from search command. 111 * 112 * @see Builder#setActions(long) 113 */ 114 public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11; 115 116 /** 117 * Indicates this session supports the skip to queue item command. 118 * 119 * @see Builder#setActions(long) 120 */ 121 public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12; 122 123 /** 124 * This is the default playback state and indicates that no media has been 125 * added yet, or the performer has been reset and has no content to play. 126 * 127 * @see Builder#setState 128 */ 129 public final static int STATE_NONE = 0; 130 131 /** 132 * State indicating this item is currently stopped. 133 * 134 * @see Builder#setState 135 */ 136 public final static int STATE_STOPPED = 1; 137 138 /** 139 * State indicating this item is currently paused. 140 * 141 * @see Builder#setState 142 */ 143 public final static int STATE_PAUSED = 2; 144 145 /** 146 * State indicating this item is currently playing. 147 * 148 * @see Builder#setState 149 */ 150 public final static int STATE_PLAYING = 3; 151 152 /** 153 * State indicating this item is currently fast forwarding. 154 * 155 * @see Builder#setState 156 */ 157 public final static int STATE_FAST_FORWARDING = 4; 158 159 /** 160 * State indicating this item is currently rewinding. 161 * 162 * @see Builder#setState 163 */ 164 public final static int STATE_REWINDING = 5; 165 166 /** 167 * State indicating this item is currently buffering and will begin playing 168 * when enough data has buffered. 169 * 170 * @see Builder#setState 171 */ 172 public final static int STATE_BUFFERING = 6; 173 174 /** 175 * State indicating this item is currently in an error state. The error 176 * message should also be set when entering this state. 177 * 178 * @see Builder#setState 179 */ 180 public final static int STATE_ERROR = 7; 181 182 /** 183 * State indicating the class doing playback is currently connecting to a 184 * route. Depending on the implementation you may return to the previous 185 * state when the connection finishes or enter {@link #STATE_NONE}. If 186 * the connection failed {@link #STATE_ERROR} should be used. 187 * @hide 188 */ 189 public final static int STATE_CONNECTING = 8; 190 191 /** 192 * State indicating the player is currently skipping to the previous item. 193 * 194 * @see Builder#setState 195 */ 196 public final static int STATE_SKIPPING_TO_PREVIOUS = 9; 197 198 /** 199 * State indicating the player is currently skipping to the next item. 200 * 201 * @see Builder#setState 202 */ 203 public final static int STATE_SKIPPING_TO_NEXT = 10; 204 205 /** 206 * Use this value for the position to indicate the position is not known. 207 */ 208 public final static long PLAYBACK_POSITION_UNKNOWN = -1; 209 210 private final int mState; 211 private final long mPosition; 212 private final long mBufferedPosition; 213 private final float mSpeed; 214 private final long mActions; 215 private final CharSequence mErrorMessage; 216 private final long mUpdateTime; 217 218 private Object mStateObj; 219 PlaybackStateCompat(int state, long position, long bufferedPosition, float rate, long actions, CharSequence errorMessage, long updateTime)220 private PlaybackStateCompat(int state, long position, long bufferedPosition, 221 float rate, long actions, CharSequence errorMessage, long updateTime) { 222 mState = state; 223 mPosition = position; 224 mBufferedPosition = bufferedPosition; 225 mSpeed = rate; 226 mActions = actions; 227 mErrorMessage = errorMessage; 228 mUpdateTime = updateTime; 229 } 230 PlaybackStateCompat(Parcel in)231 private PlaybackStateCompat(Parcel in) { 232 mState = in.readInt(); 233 mPosition = in.readLong(); 234 mSpeed = in.readFloat(); 235 mUpdateTime = in.readLong(); 236 mBufferedPosition = in.readLong(); 237 mActions = in.readLong(); 238 mErrorMessage = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 239 } 240 241 @Override toString()242 public String toString() { 243 StringBuilder bob = new StringBuilder("PlaybackState {"); 244 bob.append("state=").append(mState); 245 bob.append(", position=").append(mPosition); 246 bob.append(", buffered position=").append(mBufferedPosition); 247 bob.append(", speed=").append(mSpeed); 248 bob.append(", updated=").append(mUpdateTime); 249 bob.append(", actions=").append(mActions); 250 bob.append(", error=").append(mErrorMessage); 251 bob.append("}"); 252 return bob.toString(); 253 } 254 255 @Override describeContents()256 public int describeContents() { 257 return 0; 258 } 259 260 @Override writeToParcel(Parcel dest, int flags)261 public void writeToParcel(Parcel dest, int flags) { 262 dest.writeInt(mState); 263 dest.writeLong(mPosition); 264 dest.writeFloat(mSpeed); 265 dest.writeLong(mUpdateTime); 266 dest.writeLong(mBufferedPosition); 267 dest.writeLong(mActions); 268 TextUtils.writeToParcel(mErrorMessage, dest, flags); 269 } 270 271 /** 272 * Get the current state of playback. One of the following: 273 * <ul> 274 * <li> {@link PlaybackStateCompat#STATE_NONE}</li> 275 * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li> 276 * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li> 277 * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li> 278 * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li> 279 * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li> 280 * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li> 281 * <li> {@link PlaybackStateCompat#STATE_ERROR}</li> 282 */ getState()283 public int getState() { 284 return mState; 285 } 286 287 /** 288 * Get the current playback position in ms. 289 */ getPosition()290 public long getPosition() { 291 return mPosition; 292 } 293 294 /** 295 * Get the current buffered position in ms. This is the farthest playback 296 * point that can be reached from the current position using only buffered 297 * content. 298 */ getBufferedPosition()299 public long getBufferedPosition() { 300 return mBufferedPosition; 301 } 302 303 /** 304 * Get the current playback speed as a multiple of normal playback. This 305 * should be negative when rewinding. A value of 1 means normal playback and 306 * 0 means paused. 307 * 308 * @return The current speed of playback. 309 */ getPlaybackSpeed()310 public float getPlaybackSpeed() { 311 return mSpeed; 312 } 313 314 /** 315 * Get the current actions available on this session. This should use a 316 * bitmask of the available actions. 317 * <ul> 318 * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_PREVIOUS}</li> 319 * <li> {@link PlaybackStateCompat#ACTION_REWIND}</li> 320 * <li> {@link PlaybackStateCompat#ACTION_PLAY}</li> 321 * <li> {@link PlaybackStateCompat#ACTION_PAUSE}</li> 322 * <li> {@link PlaybackStateCompat#ACTION_STOP}</li> 323 * <li> {@link PlaybackStateCompat#ACTION_FAST_FORWARD}</li> 324 * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_NEXT}</li> 325 * <li> {@link PlaybackStateCompat#ACTION_SEEK_TO}</li> 326 * <li> {@link PlaybackStateCompat#ACTION_SET_RATING}</li> 327 * </ul> 328 */ getActions()329 public long getActions() { 330 return mActions; 331 } 332 333 /** 334 * Get a user readable error message. This should be set when the state is 335 * {@link PlaybackStateCompat#STATE_ERROR}. 336 */ getErrorMessage()337 public CharSequence getErrorMessage() { 338 return mErrorMessage; 339 } 340 341 /** 342 * Get the elapsed real time at which position was last updated. If the 343 * position has never been set this will return 0; 344 * 345 * @return The last time the position was updated. 346 */ getLastPositionUpdateTime()347 public long getLastPositionUpdateTime() { 348 return mUpdateTime; 349 } 350 351 /** 352 * Creates an instance from a framework {@link android.media.session.PlaybackState} object. 353 * <p> 354 * This method is only supported on API 21+. 355 * </p> 356 * 357 * @param stateObj A {@link android.media.session.PlaybackState} object, or null if none. 358 * @return An equivalent {@link PlaybackStateCompat} object, or null if none. 359 */ fromPlaybackState(Object stateObj)360 public static PlaybackStateCompat fromPlaybackState(Object stateObj) { 361 if (stateObj == null || Build.VERSION.SDK_INT < 21) { 362 return null; 363 } 364 365 PlaybackStateCompat state = new PlaybackStateCompat( 366 PlaybackStateCompatApi21.getState(stateObj), 367 PlaybackStateCompatApi21.getPosition(stateObj), 368 PlaybackStateCompatApi21.getBufferedPosition(stateObj), 369 PlaybackStateCompatApi21.getPlaybackSpeed(stateObj), 370 PlaybackStateCompatApi21.getActions(stateObj), 371 PlaybackStateCompatApi21.getErrorMessage(stateObj), 372 PlaybackStateCompatApi21.getLastPositionUpdateTime(stateObj)); 373 state.mStateObj = stateObj; 374 return state; 375 } 376 377 /** 378 * Gets the underlying framework {@link android.media.session.PlaybackState} object. 379 * <p> 380 * This method is only supported on API 21+. 381 * </p> 382 * 383 * @return An equivalent {@link android.media.session.PlaybackState} object, or null if none. 384 */ getPlaybackState()385 public Object getPlaybackState() { 386 if (mStateObj != null || Build.VERSION.SDK_INT < 21) { 387 return mStateObj; 388 } 389 390 mStateObj = PlaybackStateCompatApi21.newInstance(mState, mPosition, mBufferedPosition, 391 mSpeed, mActions, mErrorMessage, mUpdateTime); 392 return mStateObj; 393 } 394 395 public static final Parcelable.Creator<PlaybackStateCompat> CREATOR = 396 new Parcelable.Creator<PlaybackStateCompat>() { 397 @Override 398 public PlaybackStateCompat createFromParcel(Parcel in) { 399 return new PlaybackStateCompat(in); 400 } 401 402 @Override 403 public PlaybackStateCompat[] newArray(int size) { 404 return new PlaybackStateCompat[size]; 405 } 406 }; 407 408 /** 409 * {@link PlaybackStateCompat.CustomAction CustomActions} can be used to 410 * extend the capabilities of the standard transport controls by exposing 411 * app specific actions to {@link MediaControllerCompat Controllers}. 412 */ 413 public static final class CustomAction implements Parcelable { 414 private final String mAction; 415 private final CharSequence mName; 416 private final int mIcon; 417 private final Bundle mExtras; 418 419 /** 420 * Use {@link PlaybackStateCompat.CustomAction.Builder#build()}. 421 */ CustomAction(String action, CharSequence name, int icon, Bundle extras)422 private CustomAction(String action, CharSequence name, int icon, Bundle extras) { 423 mAction = action; 424 mName = name; 425 mIcon = icon; 426 mExtras = extras; 427 } 428 CustomAction(Parcel in)429 private CustomAction(Parcel in) { 430 mAction = in.readString(); 431 mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 432 mIcon = in.readInt(); 433 mExtras = in.readBundle(); 434 } 435 436 @Override writeToParcel(Parcel dest, int flags)437 public void writeToParcel(Parcel dest, int flags) { 438 dest.writeString(mAction); 439 TextUtils.writeToParcel(mName, dest, flags); 440 dest.writeInt(mIcon); 441 dest.writeBundle(mExtras); 442 } 443 444 @Override describeContents()445 public int describeContents() { 446 return 0; 447 } 448 449 public static final Parcelable.Creator<PlaybackStateCompat.CustomAction> CREATOR 450 = new Parcelable.Creator<PlaybackStateCompat.CustomAction>() { 451 452 @Override 453 public PlaybackStateCompat.CustomAction createFromParcel(Parcel p) { 454 return new PlaybackStateCompat.CustomAction(p); 455 } 456 457 @Override 458 public PlaybackStateCompat.CustomAction[] newArray(int size) { 459 return new PlaybackStateCompat.CustomAction[size]; 460 } 461 }; 462 463 /** 464 * Returns the action of the {@link CustomAction}. 465 * 466 * @return The action of the {@link CustomAction}. 467 */ getAction()468 public String getAction() { 469 return mAction; 470 } 471 472 /** 473 * Returns the display name of this action. e.g. "Favorite" 474 * 475 * @return The display name of this {@link CustomAction}. 476 */ getName()477 public CharSequence getName() { 478 return mName; 479 } 480 481 /** 482 * Returns the resource id of the icon in the {@link MediaSessionCompat 483 * Session's} package. 484 * 485 * @return The resource id of the icon in the {@link MediaSessionCompat 486 * Session's} package. 487 */ getIcon()488 public int getIcon() { 489 return mIcon; 490 } 491 492 /** 493 * Returns extras which provide additional application-specific 494 * information about the action, or null if none. These arguments are 495 * meant to be consumed by a {@link MediaControllerCompat} if it knows 496 * how to handle them. 497 * 498 * @return Optional arguments for the {@link CustomAction}. 499 */ getExtras()500 public Bundle getExtras() { 501 return mExtras; 502 } 503 504 @Override toString()505 public String toString() { 506 return "Action:" + 507 "mName='" + mName + 508 ", mIcon=" + mIcon + 509 ", mExtras=" + mExtras; 510 } 511 512 /** 513 * Builder for {@link CustomAction} objects. 514 */ 515 public static final class Builder { 516 private final String mAction; 517 private final CharSequence mName; 518 private final int mIcon; 519 private Bundle mExtras; 520 521 /** 522 * Creates a {@link CustomAction} builder with the id, name, and 523 * icon set. 524 * 525 * @param action The action of the {@link CustomAction}. 526 * @param name The display name of the {@link CustomAction}. This 527 * name will be displayed along side the action if the UI 528 * supports it. 529 * @param icon The icon resource id of the {@link CustomAction}. 530 * This resource id must be in the same package as the 531 * {@link MediaSessionCompat}. It will be displayed with 532 * the custom action if the UI supports it. 533 */ Builder(String action, CharSequence name, int icon)534 public Builder(String action, CharSequence name, int icon) { 535 if (TextUtils.isEmpty(action)) { 536 throw new IllegalArgumentException( 537 "You must specify an action to build a CustomAction."); 538 } 539 if (TextUtils.isEmpty(name)) { 540 throw new IllegalArgumentException( 541 "You must specify a name to build a CustomAction."); 542 } 543 if (icon == 0) { 544 throw new IllegalArgumentException( 545 "You must specify an icon resource id to build a CustomAction."); 546 } 547 mAction = action; 548 mName = name; 549 mIcon = icon; 550 } 551 552 /** 553 * Set optional extras for the {@link CustomAction}. These extras 554 * are meant to be consumed by a {@link MediaControllerCompat} if it 555 * knows how to handle them. Keys should be fully qualified (e.g. 556 * "com.example.MY_ARG") to avoid collisions. 557 * 558 * @param extras Optional extras for the {@link CustomAction}. 559 * @return this. 560 */ setExtras(Bundle extras)561 public Builder setExtras(Bundle extras) { 562 mExtras = extras; 563 return this; 564 } 565 566 /** 567 * Build and return the {@link CustomAction} instance with the 568 * specified values. 569 * 570 * @return A new {@link CustomAction} instance. 571 */ build()572 public CustomAction build() { 573 return new CustomAction(mAction, mName, mIcon, mExtras); 574 } 575 } 576 } 577 578 /** 579 * Builder for {@link PlaybackStateCompat} objects. 580 */ 581 public static final class Builder { 582 private int mState; 583 private long mPosition; 584 private long mBufferedPosition; 585 private float mRate; 586 private long mActions; 587 private CharSequence mErrorMessage; 588 private long mUpdateTime; 589 590 /** 591 * Create an empty Builder. 592 */ Builder()593 public Builder() { 594 } 595 596 /** 597 * Create a Builder using a {@link PlaybackStateCompat} instance to set the 598 * initial values. 599 * 600 * @param source The playback state to copy. 601 */ Builder(PlaybackStateCompat source)602 public Builder(PlaybackStateCompat source) { 603 mState = source.mState; 604 mPosition = source.mPosition; 605 mRate = source.mSpeed; 606 mUpdateTime = source.mUpdateTime; 607 mBufferedPosition = source.mBufferedPosition; 608 mActions = source.mActions; 609 mErrorMessage = source.mErrorMessage; 610 } 611 612 /** 613 * Set the current state of playback. 614 * <p> 615 * The position must be in ms and indicates the current playback 616 * position within the track. If the position is unknown use 617 * {@link #PLAYBACK_POSITION_UNKNOWN}. 618 * <p> 619 * The rate is a multiple of normal playback and should be 0 when paused 620 * and negative when rewinding. Normal playback rate is 1.0. 621 * <p> 622 * The state must be one of the following: 623 * <ul> 624 * <li> {@link PlaybackStateCompat#STATE_NONE}</li> 625 * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li> 626 * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li> 627 * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li> 628 * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li> 629 * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li> 630 * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li> 631 * <li> {@link PlaybackStateCompat#STATE_ERROR}</li> 632 * </ul> 633 * 634 * @param state The current state of playback. 635 * @param position The position in the current track in ms. 636 * @param playbackSpeed The current rate of playback as a multiple of 637 * normal playback. 638 */ setState(int state, long position, float playbackSpeed)639 public Builder setState(int state, long position, float playbackSpeed) { 640 return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime()); 641 } 642 643 /** 644 * Set the current state of playback. 645 * <p> 646 * The position must be in ms and indicates the current playback 647 * position within the track. If the position is unknown use 648 * {@link #PLAYBACK_POSITION_UNKNOWN}. 649 * <p> 650 * The rate is a multiple of normal playback and should be 0 when paused 651 * and negative when rewinding. Normal playback rate is 1.0. 652 * <p> 653 * The state must be one of the following: 654 * <ul> 655 * <li> {@link PlaybackStateCompat#STATE_NONE}</li> 656 * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li> 657 * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li> 658 * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li> 659 * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li> 660 * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li> 661 * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li> 662 * <li> {@link PlaybackStateCompat#STATE_ERROR}</li> 663 * </ul> 664 * 665 * @param state The current state of playback. 666 * @param position The position in the current item in ms. 667 * @param playbackSpeed The current speed of playback as a multiple of 668 * normal playback. 669 * @param updateTime The time in the {@link SystemClock#elapsedRealtime} 670 * timebase that the position was updated at. 671 * @return this 672 */ setState(int state, long position, float playbackSpeed, long updateTime)673 public Builder setState(int state, long position, float playbackSpeed, long updateTime) { 674 mState = state; 675 mPosition = position; 676 mUpdateTime = updateTime; 677 mRate = playbackSpeed; 678 return this; 679 } 680 681 /** 682 * Set the current buffered position in ms. This is the farthest 683 * playback point that can be reached from the current position using 684 * only buffered content. 685 * 686 * @return this 687 */ setBufferedPosition(long bufferPosition)688 public Builder setBufferedPosition(long bufferPosition) { 689 mBufferedPosition = bufferPosition; 690 return this; 691 } 692 693 /** 694 * Set the current capabilities available on this session. This should 695 * use a bitmask of the available capabilities. 696 * <ul> 697 * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_PREVIOUS}</li> 698 * <li> {@link PlaybackStateCompat#ACTION_REWIND}</li> 699 * <li> {@link PlaybackStateCompat#ACTION_PLAY}</li> 700 * <li> {@link PlaybackStateCompat#ACTION_PAUSE}</li> 701 * <li> {@link PlaybackStateCompat#ACTION_STOP}</li> 702 * <li> {@link PlaybackStateCompat#ACTION_FAST_FORWARD}</li> 703 * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_NEXT}</li> 704 * <li> {@link PlaybackStateCompat#ACTION_SEEK_TO}</li> 705 * <li> {@link PlaybackStateCompat#ACTION_SET_RATING}</li> 706 * </ul> 707 * 708 * @return this 709 */ setActions(long capabilities)710 public Builder setActions(long capabilities) { 711 mActions = capabilities; 712 return this; 713 } 714 715 /** 716 * Set a user readable error message. This should be set when the state 717 * is {@link PlaybackStateCompat#STATE_ERROR}. 718 * 719 * @return this 720 */ setErrorMessage(CharSequence errorMessage)721 public Builder setErrorMessage(CharSequence errorMessage) { 722 mErrorMessage = errorMessage; 723 return this; 724 } 725 726 /** 727 * Creates the playback state object. 728 */ build()729 public PlaybackStateCompat build() { 730 return new PlaybackStateCompat(mState, mPosition, mBufferedPosition, 731 mRate, mActions, mErrorMessage, mUpdateTime); 732 } 733 } 734 } 735