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