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