1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.media.session;
17 
18 import android.annotation.DrawableRes;
19 import android.annotation.IntDef;
20 import android.annotation.LongDef;
21 import android.annotation.Nullable;
22 import android.os.Bundle;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.os.SystemClock;
26 import android.text.TextUtils;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 import java.util.ArrayList;
31 import java.util.List;
32 
33 /**
34  * Playback state for a {@link MediaSession}. This includes a state like
35  * {@link PlaybackState#STATE_PLAYING}, the current playback position,
36  * and the current control capabilities.
37  */
38 public final class PlaybackState implements Parcelable {
39     private static final String TAG = "PlaybackState";
40 
41     /**
42      * @hide
43      */
44     @LongDef(flag = true, value = {ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
45             ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
46             ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
47             ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
48             ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
49     @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 static final int STATE_NONE = 0;
195 
196     /**
197      * State indicating this item is currently stopped.
198      *
199      * @see Builder#setState
200      */
201     public static final int STATE_STOPPED = 1;
202 
203     /**
204      * State indicating this item is currently paused.
205      *
206      * @see Builder#setState
207      */
208     public static final int STATE_PAUSED = 2;
209 
210     /**
211      * State indicating this item is currently playing.
212      *
213      * @see Builder#setState
214      */
215     public static final int STATE_PLAYING = 3;
216 
217     /**
218      * State indicating this item is currently fast forwarding.
219      *
220      * @see Builder#setState
221      */
222     public static final int STATE_FAST_FORWARDING = 4;
223 
224     /**
225      * State indicating this item is currently rewinding.
226      *
227      * @see Builder#setState
228      */
229     public static final 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 static final 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 static final 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 static final 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 static final 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 static final 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 static final 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 static final 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 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
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         TextUtils.writeToParcel(mErrorMessage, dest, 0);
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     public static final @android.annotation.NonNull Parcelable.Creator<PlaybackState> CREATOR =
484             new Parcelable.Creator<PlaybackState>() {
485         @Override
486         public PlaybackState createFromParcel(Parcel in) {
487             return new PlaybackState(in);
488         }
489 
490         @Override
491         public PlaybackState[] newArray(int size) {
492             return new PlaybackState[size];
493         }
494     };
495 
496     /**
497      * {@link PlaybackState.CustomAction CustomActions} can be used to extend the capabilities of
498      * the standard transport controls by exposing app specific actions to
499      * {@link MediaController MediaControllers}.
500      */
501     public static final class CustomAction implements Parcelable {
502         private final String mAction;
503         private final CharSequence mName;
504         private final int mIcon;
505         private final Bundle mExtras;
506 
507         /**
508          * Use {@link PlaybackState.CustomAction.Builder#build()}.
509          */
CustomAction(String action, CharSequence name, int icon, Bundle extras)510         private CustomAction(String action, CharSequence name, int icon, Bundle extras) {
511             mAction = action;
512             mName = name;
513             mIcon = icon;
514             mExtras = extras;
515         }
516 
CustomAction(Parcel in)517         private CustomAction(Parcel in) {
518             mAction = in.readString();
519             mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
520             mIcon = in.readInt();
521             mExtras = in.readBundle();
522         }
523 
524         @Override
writeToParcel(Parcel dest, int flags)525         public void writeToParcel(Parcel dest, int flags) {
526             dest.writeString(mAction);
527             TextUtils.writeToParcel(mName, dest, flags);
528             dest.writeInt(mIcon);
529             dest.writeBundle(mExtras);
530         }
531 
532         @Override
describeContents()533         public int describeContents() {
534             return 0;
535         }
536 
537         public static final @android.annotation.NonNull Parcelable.Creator<PlaybackState.CustomAction> CREATOR =
538                 new Parcelable.Creator<PlaybackState.CustomAction>() {
539 
540                     @Override
541                     public PlaybackState.CustomAction createFromParcel(Parcel p) {
542                         return new PlaybackState.CustomAction(p);
543                     }
544 
545                     @Override
546                     public PlaybackState.CustomAction[] newArray(int size) {
547                         return new PlaybackState.CustomAction[size];
548                     }
549                 };
550 
551         /**
552          * Returns the action of the {@link CustomAction}.
553          *
554          * @return The action of the {@link CustomAction}.
555          */
getAction()556         public String getAction() {
557             return mAction;
558         }
559 
560         /**
561          * Returns the display name of this action. e.g. "Favorite"
562          *
563          * @return The display name of this {@link CustomAction}.
564          */
getName()565         public CharSequence getName() {
566             return mName;
567         }
568 
569         /**
570          * Returns the resource id of the icon in the {@link MediaSession MediaSession's} package.
571          *
572          * @return The resource id of the icon in the {@link MediaSession MediaSession's} package.
573          */
getIcon()574         public int getIcon() {
575             return mIcon;
576         }
577 
578         /**
579          * Returns extras which provide additional application-specific information about the
580          * action, or null if none. These arguments are meant to be consumed by a
581          * {@link MediaController} if it knows how to handle them.
582          *
583          * @return Optional arguments for the {@link CustomAction}.
584          */
getExtras()585         public Bundle getExtras() {
586             return mExtras;
587         }
588 
589         @Override
toString()590         public String toString() {
591             return "Action:" + "mName='" + mName + ", mIcon=" + mIcon + ", mExtras=" + mExtras;
592         }
593 
594         /**
595          * Builder for {@link CustomAction} objects.
596          */
597         public static final class Builder {
598             private final String mAction;
599             private final CharSequence mName;
600             private final int mIcon;
601             private Bundle mExtras;
602 
603             /**
604              * Creates a {@link CustomAction} builder with the id, name, and icon set.
605              *
606              * @param action The action of the {@link CustomAction}.
607              * @param name The display name of the {@link CustomAction}. This name will be displayed
608              *             along side the action if the UI supports it.
609              * @param icon The icon resource id of the {@link CustomAction}. This resource id
610              *             must be in the same package as the {@link MediaSession}. It will be
611              *             displayed with the custom action if the UI supports it.
612              */
Builder(String action, CharSequence name, @DrawableRes int icon)613             public Builder(String action, CharSequence name, @DrawableRes int icon) {
614                 if (TextUtils.isEmpty(action)) {
615                     throw new IllegalArgumentException(
616                             "You must specify an action to build a CustomAction.");
617                 }
618                 if (TextUtils.isEmpty(name)) {
619                     throw new IllegalArgumentException(
620                             "You must specify a name to build a CustomAction.");
621                 }
622                 if (icon == 0) {
623                     throw new IllegalArgumentException(
624                             "You must specify an icon resource id to build a CustomAction.");
625                 }
626                 mAction = action;
627                 mName = name;
628                 mIcon = icon;
629             }
630 
631             /**
632              * Set optional extras for the {@link CustomAction}. These extras are meant to be
633              * consumed by a {@link MediaController} if it knows how to handle them.
634              * Keys should be fully qualified (e.g. "com.example.MY_ARG") to avoid collisions.
635              *
636              * @param extras Optional extras for the {@link CustomAction}.
637              * @return this.
638              */
setExtras(Bundle extras)639             public Builder setExtras(Bundle extras) {
640                 mExtras = extras;
641                 return this;
642             }
643 
644             /**
645              * Build and return the {@link CustomAction} instance with the specified values.
646              *
647              * @return A new {@link CustomAction} instance.
648              */
build()649             public CustomAction build() {
650                 return new CustomAction(mAction, mName, mIcon, mExtras);
651             }
652         }
653     }
654 
655     /**
656      * Builder for {@link PlaybackState} objects.
657      */
658     public static final class Builder {
659         private final List<PlaybackState.CustomAction> mCustomActions = new ArrayList<>();
660 
661         private int mState;
662         private long mPosition;
663         private long mBufferedPosition;
664         private float mSpeed;
665         private long mActions;
666         private CharSequence mErrorMessage;
667         private long mUpdateTime;
668         private long mActiveItemId = MediaSession.QueueItem.UNKNOWN_ID;
669         private Bundle mExtras;
670 
671         /**
672          * Creates an initially empty state builder.
673          */
Builder()674         public Builder() {
675         }
676 
677         /**
678          * Creates a builder with the same initial values as those in the from
679          * state.
680          *
681          * @param from The state to use for initializing the builder.
682          */
Builder(PlaybackState from)683         public Builder(PlaybackState from) {
684             if (from == null) {
685                 return;
686             }
687             mState = from.mState;
688             mPosition = from.mPosition;
689             mBufferedPosition = from.mBufferedPosition;
690             mSpeed = from.mSpeed;
691             mActions = from.mActions;
692             if (from.mCustomActions != null) {
693                 mCustomActions.addAll(from.mCustomActions);
694             }
695             mErrorMessage = from.mErrorMessage;
696             mUpdateTime = from.mUpdateTime;
697             mActiveItemId = from.mActiveItemId;
698             mExtras = from.mExtras;
699         }
700 
701         /**
702          * Set the current state of playback.
703          * <p>
704          * The position must be in ms and indicates the current playback
705          * position within the item. If the position is unknown use
706          * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown
707          * position the time at which the position was updated must be provided.
708          * It is okay to use {@link SystemClock#elapsedRealtime()} if the
709          * current position was just retrieved.
710          * <p>
711          * The speed is a multiple of normal playback and should be 0 when
712          * paused and negative when rewinding. Normal playback speed is 1.0.
713          * <p>
714          * The state must be one of the following:
715          * <ul>
716          * <li> {@link PlaybackState#STATE_NONE}</li>
717          * <li> {@link PlaybackState#STATE_STOPPED}</li>
718          * <li> {@link PlaybackState#STATE_PLAYING}</li>
719          * <li> {@link PlaybackState#STATE_PAUSED}</li>
720          * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
721          * <li> {@link PlaybackState#STATE_REWINDING}</li>
722          * <li> {@link PlaybackState#STATE_BUFFERING}</li>
723          * <li> {@link PlaybackState#STATE_ERROR}</li>
724          * <li> {@link PlaybackState#STATE_CONNECTING}</li>
725          * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
726          * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
727          * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
728          * </ul>
729          *
730          * @param state The current state of playback.
731          * @param position The position in the current item in ms.
732          * @param playbackSpeed The current speed of playback as a multiple of
733          *            normal playback.
734          * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
735          *            timebase that the position was updated at.
736          * @return this
737          */
setState(@tate int state, long position, float playbackSpeed, long updateTime)738         public Builder setState(@State int state, long position, float playbackSpeed,
739                 long updateTime) {
740             mState = state;
741             mPosition = position;
742             mUpdateTime = updateTime;
743             mSpeed = playbackSpeed;
744             return this;
745         }
746 
747         /**
748          * Set the current state of playback.
749          * <p>
750          * The position must be in ms and indicates the current playback
751          * position within the item. If the position is unknown use
752          * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to
753          * the current {@link SystemClock#elapsedRealtime()}.
754          * <p>
755          * The speed is a multiple of normal playback and should be 0 when
756          * paused and negative when rewinding. Normal playback speed is 1.0.
757          * <p>
758          * The state must be one of the following:
759          * <ul>
760          * <li> {@link PlaybackState#STATE_NONE}</li>
761          * <li> {@link PlaybackState#STATE_STOPPED}</li>
762          * <li> {@link PlaybackState#STATE_PLAYING}</li>
763          * <li> {@link PlaybackState#STATE_PAUSED}</li>
764          * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
765          * <li> {@link PlaybackState#STATE_REWINDING}</li>
766          * <li> {@link PlaybackState#STATE_BUFFERING}</li>
767          * <li> {@link PlaybackState#STATE_ERROR}</li>
768          * <li> {@link PlaybackState#STATE_CONNECTING}</li>
769          * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
770          * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
771          * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
772          * </ul>
773          *
774          * @param state The current state of playback.
775          * @param position The position in the current item in ms.
776          * @param playbackSpeed The current speed of playback as a multiple of
777          *            normal playback.
778          * @return this
779          */
setState(@tate int state, long position, float playbackSpeed)780         public Builder setState(@State int state, long position, float playbackSpeed) {
781             return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
782         }
783 
784         /**
785          * Set the current actions available on this session. This should use a
786          * bitmask of possible actions.
787          * <ul>
788          * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
789          * <li> {@link PlaybackState#ACTION_REWIND}</li>
790          * <li> {@link PlaybackState#ACTION_PLAY}</li>
791          * <li> {@link PlaybackState#ACTION_PAUSE}</li>
792          * <li> {@link PlaybackState#ACTION_STOP}</li>
793          * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
794          * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
795          * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
796          * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
797          * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
798          * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
799          * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
800          * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
801          * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
802          * <li> {@link PlaybackState#ACTION_PREPARE}</li>
803          * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
804          * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
805          * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
806          * </ul>
807          *
808          * @param actions The set of actions allowed.
809          * @return this
810          */
setActions(@ctions long actions)811         public Builder setActions(@Actions long actions) {
812             mActions = actions;
813             return this;
814         }
815 
816         /**
817          * Add a custom action to the playback state. Actions can be used to
818          * expose additional functionality to {@link MediaController
819          * MediaControllers} beyond what is offered by the standard transport
820          * controls.
821          * <p>
822          * e.g. start a radio station based on the current item or skip ahead by
823          * 30 seconds.
824          *
825          * @param action An identifier for this action. It can be sent back to
826          *            the {@link MediaSession} through
827          *            {@link MediaController.TransportControls#sendCustomAction(String, Bundle)}.
828          * @param name The display name for the action. If text is shown with
829          *            the action or used for accessibility, this is what should
830          *            be used.
831          * @param icon The resource action of the icon that should be displayed
832          *            for the action. The resource should be in the package of
833          *            the {@link MediaSession}.
834          * @return this
835          */
addCustomAction(String action, String name, int icon)836         public Builder addCustomAction(String action, String name, int icon) {
837             return addCustomAction(new PlaybackState.CustomAction(action, name, icon, null));
838         }
839 
840         /**
841          * Add a custom action to the playback state. Actions can be used to expose additional
842          * functionality to {@link MediaController MediaControllers} beyond what is offered by the
843          * standard transport controls.
844          * <p>
845          * An example of an action would be to start a radio station based on the current item
846          * or to skip ahead by 30 seconds.
847          *
848          * @param customAction The custom action to add to the {@link PlaybackState}.
849          * @return this
850          */
addCustomAction(PlaybackState.CustomAction customAction)851         public Builder addCustomAction(PlaybackState.CustomAction customAction) {
852             if (customAction == null) {
853                 throw new IllegalArgumentException(
854                         "You may not add a null CustomAction to PlaybackState.");
855             }
856             mCustomActions.add(customAction);
857             return this;
858         }
859 
860         /**
861          * Set the current buffered position in ms. This is the farthest
862          * playback point that can be reached from the current position using
863          * only buffered content.
864          *
865          * @param bufferedPosition The position in ms that playback is buffered
866          *            to.
867          * @return this
868          */
setBufferedPosition(long bufferedPosition)869         public Builder setBufferedPosition(long bufferedPosition) {
870             mBufferedPosition = bufferedPosition;
871             return this;
872         }
873 
874         /**
875          * Set the active item in the play queue by specifying its id. The
876          * default value is {@link MediaSession.QueueItem#UNKNOWN_ID}
877          *
878          * @param id The id of the active item.
879          * @return this
880          */
setActiveQueueItemId(long id)881         public Builder setActiveQueueItemId(long id) {
882             mActiveItemId = id;
883             return this;
884         }
885 
886         /**
887          * Set a user readable error message. This should be set when the state
888          * is {@link PlaybackState#STATE_ERROR}.
889          *
890          * @param error The error message for display to the user.
891          * @return this
892          */
setErrorMessage(CharSequence error)893         public Builder setErrorMessage(CharSequence error) {
894             mErrorMessage = error;
895             return this;
896         }
897 
898         /**
899          * Set any custom extras to be included with the playback state.
900          *
901          * @param extras The extras to include.
902          * @return this
903          */
setExtras(Bundle extras)904         public Builder setExtras(Bundle extras) {
905             mExtras = extras;
906             return this;
907         }
908 
909         /**
910          * Build and return the {@link PlaybackState} instance with these
911          * values.
912          *
913          * @return A new state instance.
914          */
build()915         public PlaybackState build() {
916             return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferedPosition,
917                     mActions, mCustomActions, mActiveItemId, mErrorMessage, mExtras);
918         }
919     }
920 }
921