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