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