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