PlaybackStateCompat.java revision ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5
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 */
16package android.support.v4.media.session;
17
18import android.os.Build;
19import android.os.Parcel;
20import android.os.Parcelable;
21import android.os.SystemClock;
22import android.text.TextUtils;
23
24/**
25 * Playback state for a {@link MediaSessionCompat}. This includes a state like
26 * {@link PlaybackStateCompat#STATE_PLAYING}, the current playback position,
27 * and the current control capabilities.
28 */
29public final class PlaybackStateCompat implements Parcelable {
30
31    /**
32     * Indicates this session supports the stop command.
33     *
34     * @see Builder#setActions(long)
35     */
36    public static final long ACTION_STOP = 1 << 0;
37
38    /**
39     * Indicates this session supports the pause command.
40     *
41     * @see Builder#setActions(long)
42     */
43    public static final long ACTION_PAUSE = 1 << 1;
44
45    /**
46     * Indicates this session supports the play command.
47     *
48     * @see Builder#setActions(long)
49     */
50    public static final long ACTION_PLAY = 1 << 2;
51
52    /**
53     * Indicates this session supports the rewind command.
54     *
55     * @see Builder#setActions(long)
56     */
57    public static final long ACTION_REWIND = 1 << 3;
58
59    /**
60     * Indicates this session supports the previous command.
61     *
62     * @see Builder#setActions(long)
63     */
64    public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
65
66    /**
67     * Indicates this session supports the next command.
68     *
69     * @see Builder#setActions(long)
70     */
71    public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
72
73    /**
74     * Indicates this session supports the fast forward command.
75     *
76     * @see Builder#setActions(long)
77     */
78    public static final long ACTION_FAST_FORWARD = 1 << 6;
79
80    /**
81     * Indicates this session supports the set rating command.
82     *
83     * @see Builder#setActions(long)
84     */
85    public static final long ACTION_SET_RATING = 1 << 7;
86
87    /**
88     * Indicates this session supports the seek to command.
89     *
90     * @see Builder#setActions(long)
91     */
92    public static final long ACTION_SEEK_TO = 1 << 8;
93
94    /**
95     * Indicates this session supports the play/pause toggle command.
96     *
97     * @see Builder#setActions(long)
98     */
99    public static final long ACTION_PLAY_PAUSE = 1 << 9;
100
101    /**
102     * Indicates this session supports the play from media id command.
103     *
104     * @see Builder#setActions(long)
105     */
106    public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10;
107
108    /**
109     * Indicates this session supports the play from search command.
110     *
111     * @see Builder#setActions(long)
112     */
113    public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
114
115    /**
116     * Indicates this session supports the skip to queue item command.
117     *
118     * @see Builder#setActions(long)
119     */
120    public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
121
122    /**
123     * This is the default playback state and indicates that no media has been
124     * added yet, or the performer has been reset and has no content to play.
125     *
126     * @see Builder#setState
127     */
128    public final static int STATE_NONE = 0;
129
130    /**
131     * State indicating this item is currently stopped.
132     *
133     * @see Builder#setState
134     */
135    public final static int STATE_STOPPED = 1;
136
137    /**
138     * State indicating this item is currently paused.
139     *
140     * @see Builder#setState
141     */
142    public final static int STATE_PAUSED = 2;
143
144    /**
145     * State indicating this item is currently playing.
146     *
147     * @see Builder#setState
148     */
149    public final static int STATE_PLAYING = 3;
150
151    /**
152     * State indicating this item is currently fast forwarding.
153     *
154     * @see Builder#setState
155     */
156    public final static int STATE_FAST_FORWARDING = 4;
157
158    /**
159     * State indicating this item is currently rewinding.
160     *
161     * @see Builder#setState
162     */
163    public final static int STATE_REWINDING = 5;
164
165    /**
166     * State indicating this item is currently buffering and will begin playing
167     * when enough data has buffered.
168     *
169     * @see Builder#setState
170     */
171    public final static int STATE_BUFFERING = 6;
172
173    /**
174     * State indicating this item is currently in an error state. The error
175     * message should also be set when entering this state.
176     *
177     * @see Builder#setState
178     */
179    public final static int STATE_ERROR = 7;
180
181    /**
182     * State indicating the class doing playback is currently connecting to a
183     * route. Depending on the implementation you may return to the previous
184     * state when the connection finishes or enter {@link #STATE_NONE}. If
185     * the connection failed {@link #STATE_ERROR} should be used.
186     * @hide
187     */
188    public final static int STATE_CONNECTING = 8;
189
190    /**
191     * State indicating the player is currently skipping to the previous item.
192     *
193     * @see Builder#setState
194     */
195    public final static int STATE_SKIPPING_TO_PREVIOUS = 9;
196
197    /**
198     * State indicating the player is currently skipping to the next item.
199     *
200     * @see Builder#setState
201     */
202    public final static int STATE_SKIPPING_TO_NEXT = 10;
203
204    /**
205     * Use this value for the position to indicate the position is not known.
206     */
207    public final static long PLAYBACK_POSITION_UNKNOWN = -1;
208
209    private final int mState;
210    private final long mPosition;
211    private final long mBufferedPosition;
212    private final float mSpeed;
213    private final long mActions;
214    private final CharSequence mErrorMessage;
215    private final long mUpdateTime;
216
217    private Object mStateObj;
218
219    private PlaybackStateCompat(int state, long position, long bufferedPosition,
220            float rate, long actions, CharSequence errorMessage, long updateTime) {
221        mState = state;
222        mPosition = position;
223        mBufferedPosition = bufferedPosition;
224        mSpeed = rate;
225        mActions = actions;
226        mErrorMessage = errorMessage;
227        mUpdateTime = updateTime;
228    }
229
230    private PlaybackStateCompat(Parcel in) {
231        mState = in.readInt();
232        mPosition = in.readLong();
233        mSpeed = in.readFloat();
234        mUpdateTime = in.readLong();
235        mBufferedPosition = in.readLong();
236        mActions = in.readLong();
237        mErrorMessage = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
238    }
239
240    @Override
241    public String toString() {
242        StringBuilder bob = new StringBuilder("PlaybackState {");
243        bob.append("state=").append(mState);
244        bob.append(", position=").append(mPosition);
245        bob.append(", buffered position=").append(mBufferedPosition);
246        bob.append(", speed=").append(mSpeed);
247        bob.append(", updated=").append(mUpdateTime);
248        bob.append(", actions=").append(mActions);
249        bob.append(", error=").append(mErrorMessage);
250        bob.append("}");
251        return bob.toString();
252    }
253
254    @Override
255    public int describeContents() {
256        return 0;
257    }
258
259    @Override
260    public void writeToParcel(Parcel dest, int flags) {
261        dest.writeInt(mState);
262        dest.writeLong(mPosition);
263        dest.writeFloat(mSpeed);
264        dest.writeLong(mUpdateTime);
265        dest.writeLong(mBufferedPosition);
266        dest.writeLong(mActions);
267        TextUtils.writeToParcel(mErrorMessage, dest, flags);
268    }
269
270    /**
271     * Get the current state of playback. One of the following:
272     * <ul>
273     * <li> {@link PlaybackStateCompat#STATE_NONE}</li>
274     * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li>
275     * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li>
276     * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li>
277     * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li>
278     * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li>
279     * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li>
280     * <li> {@link PlaybackStateCompat#STATE_ERROR}</li>
281     */
282    public int getState() {
283        return mState;
284    }
285
286    /**
287     * Get the current playback position in ms.
288     */
289    public long getPosition() {
290        return mPosition;
291    }
292
293    /**
294     * Get the current buffered position in ms. This is the farthest playback
295     * point that can be reached from the current position using only buffered
296     * content.
297     */
298    public long getBufferedPosition() {
299        return mBufferedPosition;
300    }
301
302    /**
303     * Get the current playback speed as a multiple of normal playback. This
304     * should be negative when rewinding. A value of 1 means normal playback and
305     * 0 means paused.
306     *
307     * @return The current speed of playback.
308     */
309    public float getPlaybackSpeed() {
310        return mSpeed;
311    }
312
313    /**
314     * Get the current actions available on this session. This should use a
315     * bitmask of the available actions.
316     * <ul>
317     * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_PREVIOUS}</li>
318     * <li> {@link PlaybackStateCompat#ACTION_REWIND}</li>
319     * <li> {@link PlaybackStateCompat#ACTION_PLAY}</li>
320     * <li> {@link PlaybackStateCompat#ACTION_PAUSE}</li>
321     * <li> {@link PlaybackStateCompat#ACTION_STOP}</li>
322     * <li> {@link PlaybackStateCompat#ACTION_FAST_FORWARD}</li>
323     * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_NEXT}</li>
324     * <li> {@link PlaybackStateCompat#ACTION_SEEK_TO}</li>
325     * <li> {@link PlaybackStateCompat#ACTION_SET_RATING}</li>
326     * </ul>
327     */
328    public long getActions() {
329        return mActions;
330    }
331
332    /**
333     * Get a user readable error message. This should be set when the state is
334     * {@link PlaybackStateCompat#STATE_ERROR}.
335     */
336    public CharSequence getErrorMessage() {
337        return mErrorMessage;
338    }
339
340    /**
341     * Get the elapsed real time at which position was last updated. If the
342     * position has never been set this will return 0;
343     *
344     * @return The last time the position was updated.
345     */
346    public long getLastPositionUpdateTime() {
347        return mUpdateTime;
348    }
349
350    /**
351     * Creates an instance from a framework {@link android.media.session.PlaybackState} object.
352     * <p>
353     * This method is only supported on API 21+.
354     * </p>
355     *
356     * @param stateObj A {@link android.media.session.PlaybackState} object, or null if none.
357     * @return An equivalent {@link PlaybackStateCompat} object, or null if none.
358     */
359    public static PlaybackStateCompat fromPlaybackState(Object stateObj) {
360        if (stateObj == null || Build.VERSION.SDK_INT < 21) {
361            return null;
362        }
363
364        PlaybackStateCompat state = new PlaybackStateCompat(
365                PlaybackStateCompatApi21.getState(stateObj),
366                PlaybackStateCompatApi21.getPosition(stateObj),
367                PlaybackStateCompatApi21.getBufferedPosition(stateObj),
368                PlaybackStateCompatApi21.getPlaybackSpeed(stateObj),
369                PlaybackStateCompatApi21.getActions(stateObj),
370                PlaybackStateCompatApi21.getErrorMessage(stateObj),
371                PlaybackStateCompatApi21.getLastPositionUpdateTime(stateObj));
372        state.mStateObj = stateObj;
373        return state;
374    }
375
376    /**
377     * Gets the underlying framework {@link android.media.session.PlaybackState} object.
378     * <p>
379     * This method is only supported on API 21+.
380     * </p>
381     *
382     * @return An equivalent {@link android.media.session.PlaybackState} object, or null if none.
383     */
384    public Object getPlaybackState() {
385        if (mStateObj != null || Build.VERSION.SDK_INT < 21) {
386            return mStateObj;
387        }
388
389        mStateObj = PlaybackStateCompatApi21.newInstance(mState, mPosition, mBufferedPosition,
390                mSpeed, mActions, mErrorMessage, mUpdateTime);
391        return mStateObj;
392    }
393
394    public static final Parcelable.Creator<PlaybackStateCompat> CREATOR =
395            new Parcelable.Creator<PlaybackStateCompat>() {
396        @Override
397        public PlaybackStateCompat createFromParcel(Parcel in) {
398            return new PlaybackStateCompat(in);
399        }
400
401        @Override
402        public PlaybackStateCompat[] newArray(int size) {
403            return new PlaybackStateCompat[size];
404        }
405    };
406
407    /**
408     * Builder for {@link PlaybackStateCompat} objects.
409     */
410    public static final class Builder {
411        private int mState;
412        private long mPosition;
413        private long mBufferedPosition;
414        private float mRate;
415        private long mActions;
416        private CharSequence mErrorMessage;
417        private long mUpdateTime;
418
419        /**
420         * Create an empty Builder.
421         */
422        public Builder() {
423        }
424
425        /**
426         * Create a Builder using a {@link PlaybackStateCompat} instance to set the
427         * initial values.
428         *
429         * @param source The playback state to copy.
430         */
431        public Builder(PlaybackStateCompat source) {
432            mState = source.mState;
433            mPosition = source.mPosition;
434            mRate = source.mSpeed;
435            mUpdateTime = source.mUpdateTime;
436            mBufferedPosition = source.mBufferedPosition;
437            mActions = source.mActions;
438            mErrorMessage = source.mErrorMessage;
439        }
440
441        /**
442         * Set the current state of playback.
443         * <p>
444         * The position must be in ms and indicates the current playback position
445         * within the track. If the position is unknown use
446         * {@link #PLAYBACK_POSITION_UNKNOWN}.
447         * <p>
448         * The rate is a multiple of normal playback and should be 0 when paused and
449         * negative when rewinding. Normal playback rate is 1.0.
450         * <p>
451         * The state must be one of the following:
452         * <ul>
453         * <li> {@link PlaybackStateCompat#STATE_NONE}</li>
454         * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li>
455         * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li>
456         * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li>
457         * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li>
458         * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li>
459         * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li>
460         * <li> {@link PlaybackStateCompat#STATE_ERROR}</li>
461         * </ul>
462         *
463         * @param state The current state of playback.
464         * @param position The position in the current track in ms.
465         * @param playbackRate The current rate of playback as a multiple of normal
466         *            playback.
467         */
468        public void setState(int state, long position, float playbackRate) {
469            this.mState = state;
470            this.mPosition = position;
471            this.mRate = playbackRate;
472            mUpdateTime = SystemClock.elapsedRealtime();
473        }
474
475        /**
476         * Set the current buffered position in ms. This is the farthest
477         * playback point that can be reached from the current position using
478         * only buffered content.
479         */
480        public void setBufferedPosition(long bufferPosition) {
481            mBufferedPosition = bufferPosition;
482        }
483
484        /**
485         * Set the current capabilities available on this session. This should use a
486         * bitmask of the available capabilities.
487         * <ul>
488         * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_PREVIOUS}</li>
489         * <li> {@link PlaybackStateCompat#ACTION_REWIND}</li>
490         * <li> {@link PlaybackStateCompat#ACTION_PLAY}</li>
491         * <li> {@link PlaybackStateCompat#ACTION_PAUSE}</li>
492         * <li> {@link PlaybackStateCompat#ACTION_STOP}</li>
493         * <li> {@link PlaybackStateCompat#ACTION_FAST_FORWARD}</li>
494         * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_NEXT}</li>
495         * <li> {@link PlaybackStateCompat#ACTION_SEEK_TO}</li>
496         * <li> {@link PlaybackStateCompat#ACTION_SET_RATING}</li>
497         * </ul>
498         */
499        public void setActions(long capabilities) {
500            mActions = capabilities;
501        }
502
503        /**
504         * Set a user readable error message. This should be set when the state is
505         * {@link PlaybackStateCompat#STATE_ERROR}.
506         */
507        public void setErrorMessage(CharSequence errorMessage) {
508            mErrorMessage = errorMessage;
509        }
510
511        /**
512         * Creates the playback state object.
513         */
514        public PlaybackStateCompat build() {
515            return new PlaybackStateCompat(mState, mPosition, mBufferedPosition,
516                    mRate, mActions, mErrorMessage, mUpdateTime);
517        }
518    }
519}
520