Home | History | Annotate | Download | only in session
      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 static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
     19 
     20 import android.os.Build;
     21 import android.os.Bundle;
     22 import android.os.Parcel;
     23 import android.os.Parcelable;
     24 import android.os.SystemClock;
     25 import android.text.TextUtils;
     26 import android.view.KeyEvent;
     27 
     28 import androidx.annotation.IntDef;
     29 import androidx.annotation.LongDef;
     30 import androidx.annotation.Nullable;
     31 import androidx.annotation.RestrictTo;
     32 
     33 import java.lang.annotation.Retention;
     34 import java.lang.annotation.RetentionPolicy;
     35 import java.util.ArrayList;
     36 import java.util.List;
     37 
     38 /**
     39  * Playback state for a {@link MediaSessionCompat}. This includes a state like
     40  * {@link PlaybackStateCompat#STATE_PLAYING}, the current playback position,
     41  * and the current control capabilities.
     42  */
     43 public final class PlaybackStateCompat implements Parcelable {
     44 
     45     /**
     46      * @hide
     47      */
     48     @RestrictTo(LIBRARY_GROUP)
     49     @LongDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
     50             ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
     51             ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
     52             ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
     53             ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI,
     54             ACTION_SET_REPEAT_MODE, ACTION_SET_SHUFFLE_MODE, ACTION_SET_CAPTIONING_ENABLED})
     55     @Retention(RetentionPolicy.SOURCE)
     56     public @interface Actions {}
     57 
     58     /**
     59      * @hide
     60      */
     61     @RestrictTo(LIBRARY_GROUP)
     62     @LongDef({ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND, ACTION_SKIP_TO_PREVIOUS,
     63             ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_PLAY_PAUSE})
     64     @Retention(RetentionPolicy.SOURCE)
     65     public @interface MediaKeyAction {}
     66 
     67     /**
     68      * Indicates this session supports the stop command.
     69      *
     70      * @see Builder#setActions(long)
     71      */
     72     public static final long ACTION_STOP = 1 << 0;
     73 
     74     /**
     75      * Indicates this session supports the pause command.
     76      *
     77      * @see Builder#setActions(long)
     78      */
     79     public static final long ACTION_PAUSE = 1 << 1;
     80 
     81     /**
     82      * Indicates this session supports the play command.
     83      *
     84      * @see Builder#setActions(long)
     85      */
     86     public static final long ACTION_PLAY = 1 << 2;
     87 
     88     /**
     89      * Indicates this session supports the rewind command.
     90      *
     91      * @see Builder#setActions(long)
     92      */
     93     public static final long ACTION_REWIND = 1 << 3;
     94 
     95     /**
     96      * Indicates this session supports the previous command.
     97      *
     98      * @see Builder#setActions(long)
     99      */
    100     public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
    101 
    102     /**
    103      * Indicates this session supports the next command.
    104      *
    105      * @see Builder#setActions(long)
    106      */
    107     public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
    108 
    109     /**
    110      * Indicates this session supports the fast forward command.
    111      *
    112      * @see Builder#setActions(long)
    113      */
    114     public static final long ACTION_FAST_FORWARD = 1 << 6;
    115 
    116     /**
    117      * Indicates this session supports the set rating command.
    118      *
    119      * @see Builder#setActions(long)
    120      */
    121     public static final long ACTION_SET_RATING = 1 << 7;
    122 
    123     /**
    124      * Indicates this session supports the seek to command.
    125      *
    126      * @see Builder#setActions(long)
    127      */
    128     public static final long ACTION_SEEK_TO = 1 << 8;
    129 
    130     /**
    131      * Indicates this session supports the play/pause toggle command.
    132      *
    133      * @see Builder#setActions(long)
    134      */
    135     public static final long ACTION_PLAY_PAUSE = 1 << 9;
    136 
    137     /**
    138      * Indicates this session supports the play from media id command.
    139      *
    140      * @see Builder#setActions(long)
    141      */
    142     public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10;
    143 
    144     /**
    145      * Indicates this session supports the play from search command.
    146      *
    147      * @see Builder#setActions(long)
    148      */
    149     public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
    150 
    151     /**
    152      * Indicates this session supports the skip to queue item command.
    153      *
    154      * @see Builder#setActions(long)
    155      */
    156     public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
    157 
    158     /**
    159      * Indicates this session supports the play from URI command.
    160      *
    161      * @see Builder#setActions(long)
    162      */
    163     public static final long ACTION_PLAY_FROM_URI = 1 << 13;
    164 
    165     /**
    166      * Indicates this session supports the prepare command.
    167      *
    168      * @see Builder#setActions(long)
    169      */
    170     public static final long ACTION_PREPARE = 1 << 14;
    171 
    172     /**
    173      * Indicates this session supports the prepare from media id command.
    174      *
    175      * @see Builder#setActions(long)
    176      */
    177     public static final long ACTION_PREPARE_FROM_MEDIA_ID = 1 << 15;
    178 
    179     /**
    180      * Indicates this session supports the prepare from search command.
    181      *
    182      * @see Builder#setActions(long)
    183      */
    184     public static final long ACTION_PREPARE_FROM_SEARCH = 1 << 16;
    185 
    186     /**
    187      * Indicates this session supports the prepare from URI command.
    188      *
    189      * @see Builder#setActions(long)
    190      */
    191     public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
    192 
    193     /**
    194      * Indicates this session supports the set repeat mode command.
    195      *
    196      * @see Builder#setActions(long)
    197      */
    198     public static final long ACTION_SET_REPEAT_MODE = 1 << 18;
    199 
    200     /**
    201      * Indicates this session supports the set shuffle mode enabled command.
    202      *
    203      * @see Builder#setActions(long)
    204      * @deprecated Use {@link #ACTION_SET_SHUFFLE_MODE} instead.
    205      */
    206     @Deprecated
    207     public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 1 << 19;
    208 
    209     /**
    210      * Indicates this session supports the set captioning enabled command.
    211      *
    212      * @see Builder#setActions(long)
    213      */
    214     public static final long ACTION_SET_CAPTIONING_ENABLED = 1 << 20;
    215 
    216     /**
    217      * Indicates this session supports the set shuffle mode command.
    218      *
    219      * @see Builder#setActions(long)
    220      */
    221     public static final long ACTION_SET_SHUFFLE_MODE = 1 << 21;
    222 
    223     /**
    224      * @hide
    225      */
    226     @RestrictTo(LIBRARY_GROUP)
    227     @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
    228             STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING,
    229             STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM})
    230     @Retention(RetentionPolicy.SOURCE)
    231     public @interface State {}
    232 
    233     /**
    234      * This is the default playback state and indicates that no media has been
    235      * added yet, or the performer has been reset and has no content to play.
    236      *
    237      * @see Builder#setState
    238      */
    239     public final static int STATE_NONE = 0;
    240 
    241     /**
    242      * State indicating this item is currently stopped.
    243      *
    244      * @see Builder#setState
    245      */
    246     public final static int STATE_STOPPED = 1;
    247 
    248     /**
    249      * State indicating this item is currently paused.
    250      *
    251      * @see Builder#setState
    252      */
    253     public final static int STATE_PAUSED = 2;
    254 
    255     /**
    256      * State indicating this item is currently playing.
    257      *
    258      * @see Builder#setState
    259      */
    260     public final static int STATE_PLAYING = 3;
    261 
    262     /**
    263      * State indicating this item is currently fast forwarding.
    264      *
    265      * @see Builder#setState
    266      */
    267     public final static int STATE_FAST_FORWARDING = 4;
    268 
    269     /**
    270      * State indicating this item is currently rewinding.
    271      *
    272      * @see Builder#setState
    273      */
    274     public final static int STATE_REWINDING = 5;
    275 
    276     /**
    277      * State indicating this item is currently buffering and will begin playing
    278      * when enough data has buffered.
    279      *
    280      * @see Builder#setState
    281      */
    282     public final static int STATE_BUFFERING = 6;
    283 
    284     /**
    285      * State indicating this item is currently in an error state. The error
    286      * code should also be set when entering this state.
    287      *
    288      * @see Builder#setState
    289      * @see Builder#setErrorMessage(int, CharSequence)
    290      */
    291     public final static int STATE_ERROR = 7;
    292 
    293     /**
    294      * State indicating the class doing playback is currently connecting to a
    295      * route. Depending on the implementation you may return to the previous
    296      * state when the connection finishes or enter {@link #STATE_NONE}. If
    297      * the connection failed {@link #STATE_ERROR} should be used.
    298      * <p>
    299      * On devices earlier than API 21, this will appear as {@link #STATE_BUFFERING}
    300      * </p>
    301      *
    302      * @see Builder#setState
    303      */
    304     public final static int STATE_CONNECTING = 8;
    305 
    306     /**
    307      * State indicating the player is currently skipping to the previous item.
    308      *
    309      * @see Builder#setState
    310      */
    311     public final static int STATE_SKIPPING_TO_PREVIOUS = 9;
    312 
    313     /**
    314      * State indicating the player is currently skipping to the next item.
    315      *
    316      * @see Builder#setState
    317      */
    318     public final static int STATE_SKIPPING_TO_NEXT = 10;
    319 
    320     /**
    321      * State indicating the player is currently skipping to a specific item in
    322      * the queue.
    323      * <p>
    324      * On devices earlier than API 21, this will appear as {@link #STATE_SKIPPING_TO_NEXT}
    325      * </p>
    326      *
    327      * @see Builder#setState
    328      */
    329     public final static int STATE_SKIPPING_TO_QUEUE_ITEM = 11;
    330 
    331     /**
    332      * Use this value for the position to indicate the position is not known.
    333      */
    334     public final static long PLAYBACK_POSITION_UNKNOWN = -1;
    335 
    336     /**
    337      * @hide
    338      */
    339     @RestrictTo(LIBRARY_GROUP)
    340     @IntDef({REPEAT_MODE_INVALID, REPEAT_MODE_NONE, REPEAT_MODE_ONE, REPEAT_MODE_ALL,
    341             REPEAT_MODE_GROUP})
    342     @Retention(RetentionPolicy.SOURCE)
    343     public @interface RepeatMode {}
    344 
    345     /**
    346      * {@link MediaControllerCompat.TransportControls#getRepeatMode} returns this value
    347      * when the session is not ready for providing its repeat mode.
    348      */
    349     public static final int REPEAT_MODE_INVALID = -1;
    350 
    351     /**
    352      * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
    353      * to indicate that the playback will be stopped at the end of the playing media list.
    354      */
    355     public static final int REPEAT_MODE_NONE = 0;
    356 
    357     /**
    358      * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
    359      * to indicate that the playback of the current playing media item will be repeated.
    360      */
    361     public static final int REPEAT_MODE_ONE = 1;
    362 
    363     /**
    364      * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
    365      * to indicate that the playback of the playing media list will be repeated.
    366      */
    367     public static final int REPEAT_MODE_ALL = 2;
    368 
    369     /**
    370      * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
    371      * to indicate that the playback of the playing media group will be repeated.
    372      * A group is a logical block of media items which is specified in the section 5.7 of the
    373      * Bluetooth AVRCP 1.6.
    374      */
    375     public static final int REPEAT_MODE_GROUP = 3;
    376 
    377     /**
    378      * @hide
    379      */
    380     @RestrictTo(LIBRARY_GROUP)
    381     @IntDef({SHUFFLE_MODE_INVALID, SHUFFLE_MODE_NONE, SHUFFLE_MODE_ALL, SHUFFLE_MODE_GROUP})
    382     @Retention(RetentionPolicy.SOURCE)
    383     public @interface ShuffleMode {}
    384 
    385     /**
    386      * {@link MediaControllerCompat.TransportControls#getShuffleMode} returns this value
    387      * when the session is not ready for providing its shuffle mode.
    388      */
    389     public static final int SHUFFLE_MODE_INVALID = -1;
    390 
    391     /**
    392      * Use this value with {@link MediaControllerCompat.TransportControls#setShuffleMode}
    393      * to indicate that the media list will be played in order.
    394      */
    395     public static final int SHUFFLE_MODE_NONE = 0;
    396 
    397     /**
    398      * Use this value with {@link MediaControllerCompat.TransportControls#setShuffleMode}
    399      * to indicate that the media list will be played in shuffled order.
    400      */
    401     public static final int SHUFFLE_MODE_ALL = 1;
    402 
    403     /**
    404      * Use this value with {@link MediaControllerCompat.TransportControls#setShuffleMode}
    405      * to indicate that the media group will be played in shuffled order.
    406      * A group is a logical block of media items which is specified in the section 5.7 of the
    407      * Bluetooth AVRCP 1.6.
    408      */
    409     public static final int SHUFFLE_MODE_GROUP = 2;
    410 
    411     /**
    412      * @hide
    413      */
    414     @RestrictTo(LIBRARY_GROUP)
    415     @IntDef({ERROR_CODE_UNKNOWN_ERROR, ERROR_CODE_APP_ERROR, ERROR_CODE_NOT_SUPPORTED,
    416             ERROR_CODE_AUTHENTICATION_EXPIRED, ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED,
    417             ERROR_CODE_CONCURRENT_STREAM_LIMIT, ERROR_CODE_PARENTAL_CONTROL_RESTRICTED,
    418             ERROR_CODE_NOT_AVAILABLE_IN_REGION, ERROR_CODE_CONTENT_ALREADY_PLAYING,
    419             ERROR_CODE_SKIP_LIMIT_REACHED, ERROR_CODE_ACTION_ABORTED, ERROR_CODE_END_OF_QUEUE})
    420     @Retention(RetentionPolicy.SOURCE)
    421     public @interface ErrorCode {}
    422 
    423     /**
    424      * This is the default error code and indicates that none of the other error codes applies.
    425      * The error code should be set when entering {@link #STATE_ERROR}.
    426      */
    427     public static final int ERROR_CODE_UNKNOWN_ERROR = 0;
    428 
    429     /**
    430      * Error code when the application state is invalid to fulfill the request.
    431      * The error code should be set when entering {@link #STATE_ERROR}.
    432      */
    433     public static final int ERROR_CODE_APP_ERROR = 1;
    434 
    435     /**
    436      * Error code when the request is not supported by the application.
    437      * The error code should be set when entering {@link #STATE_ERROR}.
    438      */
    439     public static final int ERROR_CODE_NOT_SUPPORTED = 2;
    440 
    441     /**
    442      * Error code when the request cannot be performed because authentication has expired.
    443      * The error code should be set when entering {@link #STATE_ERROR}.
    444      */
    445     public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3;
    446 
    447     /**
    448      * Error code when a premium account is required for the request to succeed.
    449      * The error code should be set when entering {@link #STATE_ERROR}.
    450      */
    451     public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4;
    452 
    453     /**
    454      * Error code when too many concurrent streams are detected.
    455      * The error code should be set when entering {@link #STATE_ERROR}.
    456      */
    457     public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5;
    458 
    459     /**
    460      * Error code when the content is blocked due to parental controls.
    461      * The error code should be set when entering {@link #STATE_ERROR}.
    462      */
    463     public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6;
    464 
    465     /**
    466      * Error code when the content is blocked due to being regionally unavailable.
    467      * The error code should be set when entering {@link #STATE_ERROR}.
    468      */
    469     public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7;
    470 
    471     /**
    472      * Error code when the requested content is already playing.
    473      * The error code should be set when entering {@link #STATE_ERROR}.
    474      */
    475     public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8;
    476 
    477     /**
    478      * Error code when the application cannot skip any more songs because skip limit is reached.
    479      * The error code should be set when entering {@link #STATE_ERROR}.
    480      */
    481     public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9;
    482 
    483     /**
    484      * Error code when the action is interrupted due to some external event.
    485      * The error code should be set when entering {@link #STATE_ERROR}.
    486      */
    487     public static final int ERROR_CODE_ACTION_ABORTED = 10;
    488 
    489     /**
    490      * Error code when the playback navigation (previous, next) is not possible because the queue
    491      * was exhausted.
    492      * The error code should be set when entering {@link #STATE_ERROR}.
    493      */
    494     public static final int ERROR_CODE_END_OF_QUEUE = 11;
    495 
    496     // KeyEvent constants only available on API 11+
    497     private static final int KEYCODE_MEDIA_PAUSE = 127;
    498     private static final int KEYCODE_MEDIA_PLAY = 126;
    499 
    500     /**
    501      * Translates a given action into a matched key code defined in {@link KeyEvent}. The given
    502      * action should be one of the following:
    503      * <ul>
    504      * <li>{@link PlaybackStateCompat#ACTION_PLAY}</li>
    505      * <li>{@link PlaybackStateCompat#ACTION_PAUSE}</li>
    506      * <li>{@link PlaybackStateCompat#ACTION_SKIP_TO_NEXT}</li>
    507      * <li>{@link PlaybackStateCompat#ACTION_SKIP_TO_PREVIOUS}</li>
    508      * <li>{@link PlaybackStateCompat#ACTION_STOP}</li>
    509      * <li>{@link PlaybackStateCompat#ACTION_FAST_FORWARD}</li>
    510      * <li>{@link PlaybackStateCompat#ACTION_REWIND}</li>
    511      * <li>{@link PlaybackStateCompat#ACTION_PLAY_PAUSE}</li>
    512      * </ul>
    513      *
    514      * @param action The action to be translated.
    515      *
    516      * @return the key code matched to the given action.
    517      */
    518     public static int toKeyCode(@MediaKeyAction long action) {
    519         if (action == ACTION_PLAY) {
    520             return KEYCODE_MEDIA_PLAY;
    521         } else if (action == ACTION_PAUSE) {
    522             return KEYCODE_MEDIA_PAUSE;
    523         } else if (action == ACTION_SKIP_TO_NEXT) {
    524             return KeyEvent.KEYCODE_MEDIA_NEXT;
    525         } else if (action == ACTION_SKIP_TO_PREVIOUS) {
    526             return KeyEvent.KEYCODE_MEDIA_PREVIOUS;
    527         } else if (action == ACTION_STOP) {
    528             return KeyEvent.KEYCODE_MEDIA_STOP;
    529         } else if (action == ACTION_FAST_FORWARD) {
    530             return KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
    531         } else if (action == ACTION_REWIND) {
    532             return KeyEvent.KEYCODE_MEDIA_REWIND;
    533         } else if (action == ACTION_PLAY_PAUSE) {
    534             return KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
    535         }
    536         return KeyEvent.KEYCODE_UNKNOWN;
    537     }
    538 
    539     final int mState;
    540     final long mPosition;
    541     final long mBufferedPosition;
    542     final float mSpeed;
    543     final long mActions;
    544     final int mErrorCode;
    545     final CharSequence mErrorMessage;
    546     final long mUpdateTime;
    547     List<PlaybackStateCompat.CustomAction> mCustomActions;
    548     final long mActiveItemId;
    549     final Bundle mExtras;
    550 
    551     private Object mStateObj;
    552 
    553     PlaybackStateCompat(int state, long position, long bufferedPosition,
    554             float rate, long actions, int errorCode, CharSequence errorMessage, long updateTime,
    555             List<PlaybackStateCompat.CustomAction> customActions,
    556             long activeItemId, Bundle extras) {
    557         mState = state;
    558         mPosition = position;
    559         mBufferedPosition = bufferedPosition;
    560         mSpeed = rate;
    561         mActions = actions;
    562         mErrorCode = errorCode;
    563         mErrorMessage = errorMessage;
    564         mUpdateTime = updateTime;
    565         mCustomActions = new ArrayList<>(customActions);
    566         mActiveItemId = activeItemId;
    567         mExtras = extras;
    568     }
    569 
    570     PlaybackStateCompat(Parcel in) {
    571         mState = in.readInt();
    572         mPosition = in.readLong();
    573         mSpeed = in.readFloat();
    574         mUpdateTime = in.readLong();
    575         mBufferedPosition = in.readLong();
    576         mActions = in.readLong();
    577         mErrorMessage = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
    578         mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
    579         mActiveItemId = in.readLong();
    580         mExtras = in.readBundle();
    581         // New attributes should be added at the end for backward compatibility.
    582         mErrorCode = in.readInt();
    583     }
    584 
    585     @Override
    586     public String toString() {
    587         StringBuilder bob = new StringBuilder("PlaybackState {");
    588         bob.append("state=").append(mState);
    589         bob.append(", position=").append(mPosition);
    590         bob.append(", buffered position=").append(mBufferedPosition);
    591         bob.append(", speed=").append(mSpeed);
    592         bob.append(", updated=").append(mUpdateTime);
    593         bob.append(", actions=").append(mActions);
    594         bob.append(", error code=").append(mErrorCode);
    595         bob.append(", error message=").append(mErrorMessage);
    596         bob.append(", custom actions=").append(mCustomActions);
    597         bob.append(", active item id=").append(mActiveItemId);
    598         bob.append("}");
    599         return bob.toString();
    600     }
    601 
    602     @Override
    603     public int describeContents() {
    604         return 0;
    605     }
    606 
    607     @Override
    608     public void writeToParcel(Parcel dest, int flags) {
    609         dest.writeInt(mState);
    610         dest.writeLong(mPosition);
    611         dest.writeFloat(mSpeed);
    612         dest.writeLong(mUpdateTime);
    613         dest.writeLong(mBufferedPosition);
    614         dest.writeLong(mActions);
    615         TextUtils.writeToParcel(mErrorMessage, dest, flags);
    616         dest.writeTypedList(mCustomActions);
    617         dest.writeLong(mActiveItemId);
    618         dest.writeBundle(mExtras);
    619         // New attributes should be added at the end for backward compatibility.
    620         dest.writeInt(mErrorCode);
    621     }
    622 
    623     /**
    624      * Get the current state of playback. One of the following:
    625      * <ul>
    626      * <li> {@link PlaybackStateCompat#STATE_NONE}</li>
    627      * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li>
    628      * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li>
    629      * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li>
    630      * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li>
    631      * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li>
    632      * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li>
    633      * <li> {@link PlaybackStateCompat#STATE_ERROR}</li>
    634      * <li> {@link PlaybackStateCompat#STATE_CONNECTING}</li>
    635      * <li> {@link PlaybackStateCompat#STATE_SKIPPING_TO_PREVIOUS}</li>
    636      * <li> {@link PlaybackStateCompat#STATE_SKIPPING_TO_NEXT}</li>
    637      * <li> {@link PlaybackStateCompat#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
    638      */
    639     @State
    640     public int getState() {
    641         return mState;
    642     }
    643 
    644     /**
    645      * Get the current playback position in ms.
    646      */
    647     public long getPosition() {
    648         return mPosition;
    649     }
    650 
    651     /**
    652      * Get the current buffered position in ms. This is the farthest playback
    653      * point that can be reached from the current position using only buffered
    654      * content.
    655      */
    656     public long getBufferedPosition() {
    657         return mBufferedPosition;
    658     }
    659 
    660     /**
    661      * Get the current playback speed as a multiple of normal playback. This
    662      * should be negative when rewinding. A value of 1 means normal playback and
    663      * 0 means paused.
    664      *
    665      * @return The current speed of playback.
    666      */
    667     public float getPlaybackSpeed() {
    668         return mSpeed;
    669     }
    670 
    671     /**
    672      * Get the current actions available on this session. This should use a
    673      * bitmask of the available actions.
    674      * <ul>
    675      * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_PREVIOUS}</li>
    676      * <li> {@link PlaybackStateCompat#ACTION_REWIND}</li>
    677      * <li> {@link PlaybackStateCompat#ACTION_PLAY}</li>
    678      * <li> {@link PlaybackStateCompat#ACTION_PLAY_PAUSE}</li>
    679      * <li> {@link PlaybackStateCompat#ACTION_PAUSE}</li>
    680      * <li> {@link PlaybackStateCompat#ACTION_STOP}</li>
    681      * <li> {@link PlaybackStateCompat#ACTION_FAST_FORWARD}</li>
    682      * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_NEXT}</li>
    683      * <li> {@link PlaybackStateCompat#ACTION_SEEK_TO}</li>
    684      * <li> {@link PlaybackStateCompat#ACTION_SET_RATING}</li>
    685      * <li> {@link PlaybackStateCompat#ACTION_PLAY_FROM_MEDIA_ID}</li>
    686      * <li> {@link PlaybackStateCompat#ACTION_PLAY_FROM_SEARCH}</li>
    687      * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_QUEUE_ITEM}</li>
    688      * <li> {@link PlaybackStateCompat#ACTION_PLAY_FROM_URI}</li>
    689      * <li> {@link PlaybackStateCompat#ACTION_PREPARE}</li>
    690      * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_MEDIA_ID}</li>
    691      * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_SEARCH}</li>
    692      * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_URI}</li>
    693      * <li> {@link PlaybackStateCompat#ACTION_SET_REPEAT_MODE}</li>
    694      * <li> {@link PlaybackStateCompat#ACTION_SET_SHUFFLE_MODE}</li>
    695      * <li> {@link PlaybackStateCompat#ACTION_SET_CAPTIONING_ENABLED}</li>
    696      * </ul>
    697      */
    698     @Actions
    699     public long getActions() {
    700         return mActions;
    701     }
    702 
    703     /**
    704      * Get the list of custom actions.
    705      */
    706     public List<PlaybackStateCompat.CustomAction> getCustomActions() {
    707         return mCustomActions;
    708     }
    709 
    710     /**
    711      * Get the error code. This should be set when the state is
    712      * {@link PlaybackStateCompat#STATE_ERROR}.
    713      *
    714      * @see #ERROR_CODE_UNKNOWN_ERROR
    715      * @see #ERROR_CODE_APP_ERROR
    716      * @see #ERROR_CODE_NOT_SUPPORTED
    717      * @see #ERROR_CODE_AUTHENTICATION_EXPIRED
    718      * @see #ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED
    719      * @see #ERROR_CODE_CONCURRENT_STREAM_LIMIT
    720      * @see #ERROR_CODE_PARENTAL_CONTROL_RESTRICTED
    721      * @see #ERROR_CODE_NOT_AVAILABLE_IN_REGION
    722      * @see #ERROR_CODE_CONTENT_ALREADY_PLAYING
    723      * @see #ERROR_CODE_SKIP_LIMIT_REACHED
    724      * @see #ERROR_CODE_ACTION_ABORTED
    725      * @see #ERROR_CODE_END_OF_QUEUE
    726      * @see #getErrorMessage()
    727      */
    728     @ErrorCode
    729     public int getErrorCode() {
    730         return mErrorCode;
    731     }
    732 
    733     /**
    734      * Get the user readable optional error message. This may be set when the state is
    735      * {@link PlaybackStateCompat#STATE_ERROR}.
    736      *
    737      * @see #getErrorCode()
    738      */
    739     public CharSequence getErrorMessage() {
    740         return mErrorMessage;
    741     }
    742 
    743     /**
    744      * Get the elapsed real time at which position was last updated. If the
    745      * position has never been set this will return 0;
    746      *
    747      * @return The last time the position was updated.
    748      */
    749     public long getLastPositionUpdateTime() {
    750         return mUpdateTime;
    751     }
    752 
    753     /**
    754      * Get the id of the currently active item in the queue. If there is no
    755      * queue or a queue is not supported by the session this will be
    756      * {@link MediaSessionCompat.QueueItem#UNKNOWN_ID}.
    757      *
    758      * @return The id of the currently active item in the queue or
    759      *         {@link MediaSessionCompat.QueueItem#UNKNOWN_ID}.
    760      */
    761     public long getActiveQueueItemId() {
    762         return mActiveItemId;
    763     }
    764 
    765     /**
    766      * Get any custom extras that were set on this playback state.
    767      *
    768      * @return The extras for this state or null.
    769      */
    770     public @Nullable Bundle getExtras() {
    771         return mExtras;
    772     }
    773 
    774     /**
    775      * Creates an instance from a framework {@link android.media.session.PlaybackState} object.
    776      * <p>
    777      * This method is only supported on API 21+.
    778      * </p>
    779      *
    780      * @param stateObj A {@link android.media.session.PlaybackState} object, or null if none.
    781      * @return An equivalent {@link PlaybackStateCompat} object, or null if none.
    782      */
    783     public static PlaybackStateCompat fromPlaybackState(Object stateObj) {
    784         if (stateObj != null && Build.VERSION.SDK_INT >= 21) {
    785             List<Object> customActionObjs = PlaybackStateCompatApi21.getCustomActions(stateObj);
    786             List<PlaybackStateCompat.CustomAction> customActions = null;
    787             if (customActionObjs != null) {
    788                 customActions = new ArrayList<>(customActionObjs.size());
    789                 for (Object customActionObj : customActionObjs) {
    790                     customActions.add(CustomAction.fromCustomAction(customActionObj));
    791                 }
    792             }
    793             Bundle extras;
    794             if (Build.VERSION.SDK_INT >= 22) {
    795                 extras = PlaybackStateCompatApi22.getExtras(stateObj);
    796             } else {
    797                 extras = null;
    798             }
    799             PlaybackStateCompat state = new PlaybackStateCompat(
    800                     PlaybackStateCompatApi21.getState(stateObj),
    801                     PlaybackStateCompatApi21.getPosition(stateObj),
    802                     PlaybackStateCompatApi21.getBufferedPosition(stateObj),
    803                     PlaybackStateCompatApi21.getPlaybackSpeed(stateObj),
    804                     PlaybackStateCompatApi21.getActions(stateObj),
    805                     ERROR_CODE_UNKNOWN_ERROR,
    806                     PlaybackStateCompatApi21.getErrorMessage(stateObj),
    807                     PlaybackStateCompatApi21.getLastPositionUpdateTime(stateObj),
    808                     customActions,
    809                     PlaybackStateCompatApi21.getActiveQueueItemId(stateObj),
    810                     extras);
    811             state.mStateObj = stateObj;
    812             return state;
    813         } else {
    814             return null;
    815         }
    816     }
    817 
    818     /**
    819      * Gets the underlying framework {@link android.media.session.PlaybackState} object.
    820      * <p>
    821      * This method is only supported on API 21+.
    822      * </p>
    823      *
    824      * @return An equivalent {@link android.media.session.PlaybackState} object, or null if none.
    825      */
    826     public Object getPlaybackState() {
    827         if (mStateObj == null && Build.VERSION.SDK_INT >= 21) {
    828             List<Object> customActions = null;
    829             if (mCustomActions != null) {
    830                 customActions = new ArrayList<>(mCustomActions.size());
    831                 for (PlaybackStateCompat.CustomAction customAction : mCustomActions) {
    832                     customActions.add(customAction.getCustomAction());
    833                 }
    834             }
    835             if (Build.VERSION.SDK_INT >= 22) {
    836                 mStateObj = PlaybackStateCompatApi22.newInstance(mState, mPosition,
    837                         mBufferedPosition,
    838                         mSpeed, mActions, mErrorMessage, mUpdateTime,
    839                         customActions, mActiveItemId, mExtras);
    840             } else {
    841                 //noinspection AndroidLintNewApi - NewApi lint fails to handle nested checks.
    842                 mStateObj = PlaybackStateCompatApi21.newInstance(mState, mPosition,
    843                         mBufferedPosition, mSpeed, mActions, mErrorMessage, mUpdateTime,
    844                         customActions, mActiveItemId);
    845             }
    846         }
    847         return mStateObj;
    848     }
    849 
    850     public static final Parcelable.Creator<PlaybackStateCompat> CREATOR =
    851             new Parcelable.Creator<PlaybackStateCompat>() {
    852         @Override
    853         public PlaybackStateCompat createFromParcel(Parcel in) {
    854             return new PlaybackStateCompat(in);
    855         }
    856 
    857         @Override
    858         public PlaybackStateCompat[] newArray(int size) {
    859             return new PlaybackStateCompat[size];
    860         }
    861     };
    862 
    863     /**
    864      * {@link PlaybackStateCompat.CustomAction CustomActions} can be used to
    865      * extend the capabilities of the standard transport controls by exposing
    866      * app specific actions to {@link MediaControllerCompat Controllers}.
    867      */
    868     public static final class CustomAction implements Parcelable {
    869         private final String mAction;
    870         private final CharSequence mName;
    871         private final int mIcon;
    872         private final Bundle mExtras;
    873 
    874         private Object mCustomActionObj;
    875 
    876         /**
    877          * Use {@link PlaybackStateCompat.CustomAction.Builder#build()}.
    878          */
    879         CustomAction(String action, CharSequence name, int icon, Bundle extras) {
    880             mAction = action;
    881             mName = name;
    882             mIcon = icon;
    883             mExtras = extras;
    884         }
    885 
    886         CustomAction(Parcel in) {
    887             mAction = in.readString();
    888             mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
    889             mIcon = in.readInt();
    890             mExtras = in.readBundle();
    891         }
    892 
    893         @Override
    894         public void writeToParcel(Parcel dest, int flags) {
    895             dest.writeString(mAction);
    896             TextUtils.writeToParcel(mName, dest, flags);
    897             dest.writeInt(mIcon);
    898             dest.writeBundle(mExtras);
    899         }
    900 
    901         @Override
    902         public int describeContents() {
    903             return 0;
    904         }
    905 
    906         /**
    907          * Creates an instance from a framework
    908          * {@link android.media.session.PlaybackState.CustomAction} object.
    909          * <p>
    910          * This method is only supported on API 21+.
    911          * </p>
    912          *
    913          * @param customActionObj A {@link android.media.session.PlaybackState.CustomAction} object,
    914          * or null if none.
    915          * @return An equivalent {@link PlaybackStateCompat.CustomAction} object, or null if none.
    916          */
    917         public static PlaybackStateCompat.CustomAction fromCustomAction(Object customActionObj) {
    918             if (customActionObj == null || Build.VERSION.SDK_INT < 21) {
    919                 return null;
    920             }
    921 
    922             PlaybackStateCompat.CustomAction customAction = new PlaybackStateCompat.CustomAction(
    923                     PlaybackStateCompatApi21.CustomAction.getAction(customActionObj),
    924                     PlaybackStateCompatApi21.CustomAction.getName(customActionObj),
    925                     PlaybackStateCompatApi21.CustomAction.getIcon(customActionObj),
    926                     PlaybackStateCompatApi21.CustomAction.getExtras(customActionObj));
    927             customAction.mCustomActionObj = customActionObj;
    928             return customAction;
    929         }
    930 
    931         /**
    932          * Gets the underlying framework {@link android.media.session.PlaybackState.CustomAction}
    933          * object.
    934          * <p>
    935          * This method is only supported on API 21+.
    936          * </p>
    937          *
    938          * @return An equivalent {@link android.media.session.PlaybackState.CustomAction} object,
    939          * or null if none.
    940          */
    941         public Object getCustomAction() {
    942             if (mCustomActionObj != null || Build.VERSION.SDK_INT < 21) {
    943                 return mCustomActionObj;
    944             }
    945 
    946             mCustomActionObj = PlaybackStateCompatApi21.CustomAction.newInstance(mAction,
    947                     mName, mIcon, mExtras);
    948             return mCustomActionObj;
    949         }
    950 
    951         public static final Parcelable.Creator<PlaybackStateCompat.CustomAction> CREATOR
    952                 = new Parcelable.Creator<PlaybackStateCompat.CustomAction>() {
    953 
    954                     @Override
    955                     public PlaybackStateCompat.CustomAction createFromParcel(Parcel p) {
    956                         return new PlaybackStateCompat.CustomAction(p);
    957                     }
    958 
    959                     @Override
    960                     public PlaybackStateCompat.CustomAction[] newArray(int size) {
    961                         return new PlaybackStateCompat.CustomAction[size];
    962                     }
    963                 };
    964 
    965         /**
    966          * Returns the action of the {@link CustomAction}.
    967          *
    968          * @return The action of the {@link CustomAction}.
    969          */
    970         public String getAction() {
    971             return mAction;
    972         }
    973 
    974         /**
    975          * Returns the display name of this action. e.g. "Favorite"
    976          *
    977          * @return The display name of this {@link CustomAction}.
    978          */
    979         public CharSequence getName() {
    980             return mName;
    981         }
    982 
    983         /**
    984          * Returns the resource id of the icon in the {@link MediaSessionCompat
    985          * Session's} package.
    986          *
    987          * @return The resource id of the icon in the {@link MediaSessionCompat
    988          *         Session's} package.
    989          */
    990         public int getIcon() {
    991             return mIcon;
    992         }
    993 
    994         /**
    995          * Returns extras which provide additional application-specific
    996          * information about the action, or null if none. These arguments are
    997          * meant to be consumed by a {@link MediaControllerCompat} if it knows
    998          * how to handle them.
    999          *
   1000          * @return Optional arguments for the {@link CustomAction}.
   1001          */
   1002         public Bundle getExtras() {
   1003             return mExtras;
   1004         }
   1005 
   1006         @Override
   1007         public String toString() {
   1008             return "Action:" +
   1009                     "mName='" + mName +
   1010                     ", mIcon=" + mIcon +
   1011                     ", mExtras=" + mExtras;
   1012         }
   1013 
   1014         /**
   1015          * Builder for {@link CustomAction} objects.
   1016          */
   1017         public static final class Builder {
   1018             private final String mAction;
   1019             private final CharSequence mName;
   1020             private final int mIcon;
   1021             private Bundle mExtras;
   1022 
   1023             /**
   1024              * Creates a {@link CustomAction} builder with the id, name, and
   1025              * icon set.
   1026              *
   1027              * @param action The action of the {@link CustomAction}.
   1028              * @param name The display name of the {@link CustomAction}. This
   1029              *            name will be displayed along side the action if the UI
   1030              *            supports it.
   1031              * @param icon The icon resource id of the {@link CustomAction}.
   1032              *            This resource id must be in the same package as the
   1033              *            {@link MediaSessionCompat}. It will be displayed with
   1034              *            the custom action if the UI supports it.
   1035              */
   1036             public Builder(String action, CharSequence name, int icon) {
   1037                 if (TextUtils.isEmpty(action)) {
   1038                     throw new IllegalArgumentException(
   1039                             "You must specify an action to build a CustomAction.");
   1040                 }
   1041                 if (TextUtils.isEmpty(name)) {
   1042                     throw new IllegalArgumentException(
   1043                             "You must specify a name to build a CustomAction.");
   1044                 }
   1045                 if (icon == 0) {
   1046                     throw new IllegalArgumentException(
   1047                             "You must specify an icon resource id to build a CustomAction.");
   1048                 }
   1049                 mAction = action;
   1050                 mName = name;
   1051                 mIcon = icon;
   1052             }
   1053 
   1054             /**
   1055              * Set optional extras for the {@link CustomAction}. These extras
   1056              * are meant to be consumed by a {@link MediaControllerCompat} if it
   1057              * knows how to handle them. Keys should be fully qualified (e.g.
   1058              * "com.example.MY_ARG") to avoid collisions.
   1059              *
   1060              * @param extras Optional extras for the {@link CustomAction}.
   1061              * @return this.
   1062              */
   1063             public Builder setExtras(Bundle extras) {
   1064                 mExtras = extras;
   1065                 return this;
   1066             }
   1067 
   1068             /**
   1069              * Build and return the {@link CustomAction} instance with the
   1070              * specified values.
   1071              *
   1072              * @return A new {@link CustomAction} instance.
   1073              */
   1074             public CustomAction build() {
   1075                 return new CustomAction(mAction, mName, mIcon, mExtras);
   1076             }
   1077         }
   1078     }
   1079 
   1080     /**
   1081      * Builder for {@link PlaybackStateCompat} objects.
   1082      */
   1083     public static final class Builder {
   1084         private final List<PlaybackStateCompat.CustomAction> mCustomActions = new ArrayList<>();
   1085 
   1086         private int mState;
   1087         private long mPosition;
   1088         private long mBufferedPosition;
   1089         private float mRate;
   1090         private long mActions;
   1091         private int mErrorCode;
   1092         private CharSequence mErrorMessage;
   1093         private long mUpdateTime;
   1094         private long mActiveItemId = MediaSessionCompat.QueueItem.UNKNOWN_ID;
   1095         private Bundle mExtras;
   1096 
   1097         /**
   1098          * Create an empty Builder.
   1099          */
   1100         public Builder() {
   1101         }
   1102 
   1103         /**
   1104          * Create a Builder using a {@link PlaybackStateCompat} instance to set the
   1105          * initial values.
   1106          *
   1107          * @param source The playback state to copy.
   1108          */
   1109         public Builder(PlaybackStateCompat source) {
   1110             mState = source.mState;
   1111             mPosition = source.mPosition;
   1112             mRate = source.mSpeed;
   1113             mUpdateTime = source.mUpdateTime;
   1114             mBufferedPosition = source.mBufferedPosition;
   1115             mActions = source.mActions;
   1116             mErrorCode = source.mErrorCode;
   1117             mErrorMessage = source.mErrorMessage;
   1118             if (source.mCustomActions != null) {
   1119                 mCustomActions.addAll(source.mCustomActions);
   1120             }
   1121             mActiveItemId = source.mActiveItemId;
   1122             mExtras = source.mExtras;
   1123         }
   1124 
   1125         /**
   1126          * Set the current state of playback.
   1127          * <p>
   1128          * The position must be in ms and indicates the current playback
   1129          * position within the track. If the position is unknown use
   1130          * {@link #PLAYBACK_POSITION_UNKNOWN}.
   1131          * <p>
   1132          * The rate is a multiple of normal playback and should be 0 when paused
   1133          * and negative when rewinding. Normal playback rate is 1.0.
   1134          * <p>
   1135          * The state must be one of the following:
   1136          * <ul>
   1137          * <li> {@link PlaybackStateCompat#STATE_NONE}</li>
   1138          * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li>
   1139          * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li>
   1140          * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li>
   1141          * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li>
   1142          * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li>
   1143          * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li>
   1144          * <li> {@link PlaybackStateCompat#STATE_ERROR}</li>
   1145          * <li> {@link PlaybackStateCompat#STATE_CONNECTING}</li>
   1146          * <li> {@link PlaybackStateCompat#STATE_SKIPPING_TO_PREVIOUS}</li>
   1147          * <li> {@link PlaybackStateCompat#STATE_SKIPPING_TO_NEXT}</li>
   1148          * <li> {@link PlaybackStateCompat#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
   1149          * </ul>
   1150          *
   1151          * @param state The current state of playback.
   1152          * @param position The position in the current track in ms.
   1153          * @param playbackSpeed The current rate of playback as a multiple of
   1154          *            normal playback.
   1155          */
   1156         public Builder setState(@State int state, long position, float playbackSpeed) {
   1157             return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
   1158         }
   1159 
   1160         /**
   1161          * Set the current state of playback.
   1162          * <p>
   1163          * The position must be in ms and indicates the current playback
   1164          * position within the track. If the position is unknown use
   1165          * {@link #PLAYBACK_POSITION_UNKNOWN}.
   1166          * <p>
   1167          * The rate is a multiple of normal playback and should be 0 when paused
   1168          * and negative when rewinding. Normal playback rate is 1.0.
   1169          * <p>
   1170          * The state must be one of the following:
   1171          * <ul>
   1172          * <li> {@link PlaybackStateCompat#STATE_NONE}</li>
   1173          * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li>
   1174          * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li>
   1175          * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li>
   1176          * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li>
   1177          * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li>
   1178          * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li>
   1179          * <li> {@link PlaybackStateCompat#STATE_ERROR}</li>
   1180          * <li> {@link PlaybackStateCompat#STATE_CONNECTING}</li>
   1181          * <li> {@link PlaybackStateCompat#STATE_SKIPPING_TO_PREVIOUS}</li>
   1182          * <li> {@link PlaybackStateCompat#STATE_SKIPPING_TO_NEXT}</li>
   1183          * <li> {@link PlaybackStateCompat#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
   1184          * </ul>
   1185          *
   1186          * @param state The current state of playback.
   1187          * @param position The position in the current item in ms.
   1188          * @param playbackSpeed The current speed of playback as a multiple of
   1189          *            normal playback.
   1190          * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
   1191          *            timebase that the position was updated at.
   1192          * @return this
   1193          */
   1194         public Builder setState(@State int state, long position, float playbackSpeed,
   1195                 long updateTime) {
   1196             mState = state;
   1197             mPosition = position;
   1198             mUpdateTime = updateTime;
   1199             mRate = playbackSpeed;
   1200             return this;
   1201         }
   1202 
   1203         /**
   1204          * Set the current buffered position in ms. This is the farthest
   1205          * playback point that can be reached from the current position using
   1206          * only buffered content.
   1207          *
   1208          * @return this
   1209          */
   1210         public Builder setBufferedPosition(long bufferPosition) {
   1211             mBufferedPosition = bufferPosition;
   1212             return this;
   1213         }
   1214 
   1215         /**
   1216          * Set the current capabilities available on this session. This should
   1217          * use a bitmask of the available capabilities.
   1218          * <ul>
   1219          * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_PREVIOUS}</li>
   1220          * <li> {@link PlaybackStateCompat#ACTION_REWIND}</li>
   1221          * <li> {@link PlaybackStateCompat#ACTION_PLAY}</li>
   1222          * <li> {@link PlaybackStateCompat#ACTION_PLAY_PAUSE}</li>
   1223          * <li> {@link PlaybackStateCompat#ACTION_PAUSE}</li>
   1224          * <li> {@link PlaybackStateCompat#ACTION_STOP}</li>
   1225          * <li> {@link PlaybackStateCompat#ACTION_FAST_FORWARD}</li>
   1226          * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_NEXT}</li>
   1227          * <li> {@link PlaybackStateCompat#ACTION_SEEK_TO}</li>
   1228          * <li> {@link PlaybackStateCompat#ACTION_SET_RATING}</li>
   1229          * <li> {@link PlaybackStateCompat#ACTION_PLAY_FROM_MEDIA_ID}</li>
   1230          * <li> {@link PlaybackStateCompat#ACTION_PLAY_FROM_SEARCH}</li>
   1231          * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_QUEUE_ITEM}</li>
   1232          * <li> {@link PlaybackStateCompat#ACTION_PLAY_FROM_URI}</li>
   1233          * <li> {@link PlaybackStateCompat#ACTION_PREPARE}</li>
   1234          * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_MEDIA_ID}</li>
   1235          * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_SEARCH}</li>
   1236          * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_URI}</li>
   1237          * <li> {@link PlaybackStateCompat#ACTION_SET_REPEAT_MODE}</li>
   1238          * <li> {@link PlaybackStateCompat#ACTION_SET_SHUFFLE_MODE}</li>
   1239          * <li> {@link PlaybackStateCompat#ACTION_SET_CAPTIONING_ENABLED}</li>
   1240          * </ul>
   1241          *
   1242          * @return this
   1243          */
   1244         public Builder setActions(@Actions long capabilities) {
   1245             mActions = capabilities;
   1246             return this;
   1247         }
   1248 
   1249         /**
   1250          * Add a custom action to the playback state. Actions can be used to
   1251          * expose additional functionality to {@link MediaControllerCompat
   1252          * Controllers} beyond what is offered by the standard transport
   1253          * controls.
   1254          * <p>
   1255          * e.g. start a radio station based on the current item or skip ahead by
   1256          * 30 seconds.
   1257          *
   1258          * @param action An identifier for this action. It can be sent back to
   1259          *            the {@link MediaSessionCompat} through
   1260          *            {@link MediaControllerCompat.TransportControls#sendCustomAction(String, Bundle)}.
   1261          * @param name The display name for the action. If text is shown with
   1262          *            the action or used for accessibility, this is what should
   1263          *            be used.
   1264          * @param icon The resource action of the icon that should be displayed
   1265          *            for the action. The resource should be in the package of
   1266          *            the {@link MediaSessionCompat}.
   1267          * @return this
   1268          */
   1269         public Builder addCustomAction(String action, String name, int icon) {
   1270             return addCustomAction(new PlaybackStateCompat.CustomAction(action, name, icon, null));
   1271         }
   1272 
   1273         /**
   1274          * Add a custom action to the playback state. Actions can be used to expose additional
   1275          * functionality to {@link MediaControllerCompat Controllers} beyond what is offered
   1276          * by the standard transport controls.
   1277          * <p>
   1278          * An example of an action would be to start a radio station based on the current item
   1279          * or to skip ahead by 30 seconds.
   1280          *
   1281          * @param customAction The custom action to add to the {@link PlaybackStateCompat}.
   1282          * @return this
   1283          */
   1284         public Builder addCustomAction(PlaybackStateCompat.CustomAction customAction) {
   1285             if (customAction == null) {
   1286                 throw new IllegalArgumentException(
   1287                         "You may not add a null CustomAction to PlaybackStateCompat.");
   1288             }
   1289             mCustomActions.add(customAction);
   1290             return this;
   1291         }
   1292 
   1293         /**
   1294          * Set the active item in the play queue by specifying its id. The
   1295          * default value is {@link MediaSessionCompat.QueueItem#UNKNOWN_ID}
   1296          *
   1297          * @param id The id of the active item.
   1298          * @return this
   1299          */
   1300         public Builder setActiveQueueItemId(long id) {
   1301             mActiveItemId = id;
   1302             return this;
   1303         }
   1304 
   1305         /**
   1306          * Set a user readable error message. This should be set when the state
   1307          * is {@link PlaybackStateCompat#STATE_ERROR}.
   1308          *
   1309          * @return this
   1310          * @deprecated Use {@link #setErrorMessage(int, CharSequence)} instead.
   1311          */
   1312         public Builder setErrorMessage(CharSequence errorMessage) {
   1313             mErrorMessage = errorMessage;
   1314             return this;
   1315         }
   1316 
   1317         /**
   1318          * Set the error code with an optional user readable error message. This should be set when
   1319          * the state is {@link PlaybackStateCompat#STATE_ERROR}.
   1320          *
   1321          * @param errorCode The errorCode to set.
   1322          * @param errorMessage The user readable error message. Can be null.
   1323          * @return this
   1324          */
   1325         public Builder setErrorMessage(@ErrorCode int errorCode, CharSequence errorMessage) {
   1326             mErrorCode = errorCode;
   1327             mErrorMessage = errorMessage;
   1328             return this;
   1329         }
   1330 
   1331         /**
   1332          * Set any custom extras to be included with the playback state.
   1333          *
   1334          * @param extras The extras to include.
   1335          * @return this
   1336          */
   1337         public Builder setExtras(Bundle extras) {
   1338             mExtras = extras;
   1339             return this;
   1340         }
   1341 
   1342         /**
   1343          * Creates the playback state object.
   1344          */
   1345         public PlaybackStateCompat build() {
   1346             return new PlaybackStateCompat(mState, mPosition, mBufferedPosition,
   1347                     mRate, mActions, mErrorCode, mErrorMessage, mUpdateTime,
   1348                     mCustomActions, mActiveItemId, mExtras);
   1349         }
   1350     }
   1351 }
   1352