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