PlaybackStateCompat.java revision ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4
124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown/*
224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Copyright (C) 2014 The Android Open Source Project
324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *
424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * you may not use this file except in compliance with the License.
624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * You may obtain a copy of the License at
724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *
824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *
1024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Unless required by applicable law or agreed to in writing, software
1124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * See the License for the specific language governing permissions and
1424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * limitations under the License.
1524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown */
1624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownpackage android.support.v4.media.session;
1724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
18ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
1924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Build;
20aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErikimport android.os.Bundle;
2124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Parcel;
2224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Parcelable;
2324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.SystemClock;
24ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lakeimport android.support.annotation.Nullable;
2524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.text.TextUtils;
2624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
27ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lakeimport java.util.ArrayList;
28ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lakeimport java.util.List;
29ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
3024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown/**
3124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Playback state for a {@link MediaSessionCompat}. This includes a state like
3224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * {@link PlaybackStateCompat#STATE_PLAYING}, the current playback position,
3324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * and the current control capabilities.
3424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown */
3524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownpublic final class PlaybackStateCompat implements Parcelable {
36ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik
3724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
38ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the stop command.
3924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
40ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
4124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
4224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final long ACTION_STOP = 1 << 0;
4324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
4424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
45ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the pause command.
4624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
47ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
4824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
4924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final long ACTION_PAUSE = 1 << 1;
5024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
5124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
52ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the play command.
5324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
54ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
5524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
5624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final long ACTION_PLAY = 1 << 2;
5724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
5824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
59ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the rewind command.
6024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
61ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
6224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
6324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final long ACTION_REWIND = 1 << 3;
6424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
6524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
66ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the previous command.
6724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
68ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
6924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
7024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
7124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
7224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
73ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the next command.
7424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
75ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
7624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
7724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
7824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
7924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
80ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the fast forward command.
8124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
82ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
8324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
8424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final long ACTION_FAST_FORWARD = 1 << 6;
8524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
8624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
87ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the set rating command.
8824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
89ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
9024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
9124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final long ACTION_SET_RATING = 1 << 7;
9224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
9324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
94ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the seek to command.
9524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
96ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
9724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
9824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final long ACTION_SEEK_TO = 1 << 8;
9924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
10024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
101ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the play/pause toggle command.
10224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
103ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
10424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
10524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final long ACTION_PLAY_PAUSE = 1 << 9;
10624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
10724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
108ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the play from media id command.
109ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     *
110ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
111ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     */
112ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik    public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10;
113ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik
114ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik    /**
115ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the play from search command.
116ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     *
117ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
118ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     */
119ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik    public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
120ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik
121ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik    /**
122ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * Indicates this session supports the skip to queue item command.
123ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     *
124ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     * @see Builder#setActions(long)
125ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik     */
126ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik    public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
127ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik
128ff40f5c731e8a4e6e2d33ffc95f77dce0397f2c5RoboErik    /**
12924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * This is the default playback state and indicates that no media has been
13024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * added yet, or the performer has been reset and has no content to play.
13124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
13224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @see Builder#setState
13324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
13424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_NONE = 0;
13524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
13624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
13724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * State indicating this item is currently stopped.
13824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
13924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @see Builder#setState
14024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
14124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_STOPPED = 1;
14224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
14324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
14424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * State indicating this item is currently paused.
14524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
14624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @see Builder#setState
14724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
14824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_PAUSED = 2;
14924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
15024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
15124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * State indicating this item is currently playing.
15224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
15324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @see Builder#setState
15424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
15524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_PLAYING = 3;
15624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
15724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
15824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * State indicating this item is currently fast forwarding.
15924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
16024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @see Builder#setState
16124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
16224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_FAST_FORWARDING = 4;
16324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
16424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
16524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * State indicating this item is currently rewinding.
16624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
16724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @see Builder#setState
16824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
16924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_REWINDING = 5;
17024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
17124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
17224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * State indicating this item is currently buffering and will begin playing
17324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * when enough data has buffered.
17424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
17524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @see Builder#setState
17624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
17724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_BUFFERING = 6;
17824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
17924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
18024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * State indicating this item is currently in an error state. The error
18124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * message should also be set when entering this state.
18224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
18324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @see Builder#setState
18424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
18524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_ERROR = 7;
18624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
18724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
18824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * State indicating the class doing playback is currently connecting to a
18924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * route. Depending on the implementation you may return to the previous
19024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * state when the connection finishes or enter {@link #STATE_NONE}. If
19124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * the connection failed {@link #STATE_ERROR} should be used.
19224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @hide
19324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
19424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_CONNECTING = 8;
19524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
19624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
19724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * State indicating the player is currently skipping to the previous item.
19824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
19924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @see Builder#setState
20024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
20124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_SKIPPING_TO_PREVIOUS = 9;
20224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
20324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
20424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * State indicating the player is currently skipping to the next item.
20524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
20624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @see Builder#setState
20724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
20824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static int STATE_SKIPPING_TO_NEXT = 10;
20924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
21024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
21124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Use this value for the position to indicate the position is not known.
21224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
21324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public final static long PLAYBACK_POSITION_UNKNOWN = -1;
21424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
21524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    private final int mState;
21624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    private final long mPosition;
217312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik    private final long mBufferedPosition;
21884b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik    private final float mSpeed;
21924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    private final long mActions;
22024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    private final CharSequence mErrorMessage;
22124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    private final long mUpdateTime;
222ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    private List<PlaybackStateCompat.CustomAction> mCustomActions;
223ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    private final long mActiveItemId;
224ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    private final Bundle mExtras;
22524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
22624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    private Object mStateObj;
22724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
228312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik    private PlaybackStateCompat(int state, long position, long bufferedPosition,
229ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            float rate, long actions, CharSequence errorMessage, long updateTime,
230ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            List<PlaybackStateCompat.CustomAction> customActions,
231ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            long activeItemId, Bundle extras) {
23224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mState = state;
23324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mPosition = position;
234312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        mBufferedPosition = bufferedPosition;
23584b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik        mSpeed = rate;
23624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mActions = actions;
23724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mErrorMessage = errorMessage;
23824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mUpdateTime = updateTime;
239ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        mCustomActions = new ArrayList<>(customActions);
240ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        mActiveItemId = activeItemId;
241ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        mExtras = extras;
24224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
24324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
24424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    private PlaybackStateCompat(Parcel in) {
24524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mState = in.readInt();
24624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mPosition = in.readLong();
24784b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik        mSpeed = in.readFloat();
24824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mUpdateTime = in.readLong();
249312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        mBufferedPosition = in.readLong();
25024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mActions = in.readLong();
25124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mErrorMessage = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
252ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
253ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        mActiveItemId = in.readLong();
254ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        mExtras = in.readBundle();
25524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
25624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
25724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    @Override
25824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public String toString() {
25924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        StringBuilder bob = new StringBuilder("PlaybackState {");
26024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        bob.append("state=").append(mState);
26124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        bob.append(", position=").append(mPosition);
262312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        bob.append(", buffered position=").append(mBufferedPosition);
26384b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik        bob.append(", speed=").append(mSpeed);
26424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        bob.append(", updated=").append(mUpdateTime);
26524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        bob.append(", actions=").append(mActions);
26624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        bob.append(", error=").append(mErrorMessage);
267ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        bob.append(", custom actions=").append(mCustomActions);
268ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        bob.append(", active item id=").append(mActiveItemId);
26924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        bob.append("}");
27024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return bob.toString();
27124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
27224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
27324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    @Override
27424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public int describeContents() {
27524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return 0;
27624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
27724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
27824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    @Override
27924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void writeToParcel(Parcel dest, int flags) {
28024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        dest.writeInt(mState);
28124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        dest.writeLong(mPosition);
28284b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik        dest.writeFloat(mSpeed);
28324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        dest.writeLong(mUpdateTime);
284312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        dest.writeLong(mBufferedPosition);
28524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        dest.writeLong(mActions);
28624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        TextUtils.writeToParcel(mErrorMessage, dest, flags);
287ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        dest.writeTypedList(mCustomActions);
288ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        dest.writeLong(mActiveItemId);
289ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        dest.writeBundle(mExtras);
29024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
29124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
29224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
29324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current state of playback. One of the following:
29424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <ul>
29524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#STATE_NONE}</li>
29624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li>
29724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li>
29824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li>
29924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li>
30024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li>
30124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li>
30224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#STATE_ERROR}</li>
30324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
30424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public int getState() {
30524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mState;
30624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
30724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
30824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
30924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current playback position in ms.
31024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
31124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public long getPosition() {
31224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mPosition;
31324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
31424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
31524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
316312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik     * Get the current buffered position in ms. This is the farthest playback
31724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * point that can be reached from the current position using only buffered
31824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * content.
31924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
320312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik    public long getBufferedPosition() {
321312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        return mBufferedPosition;
32224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
32324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
32424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
32584b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik     * Get the current playback speed as a multiple of normal playback. This
32624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * should be negative when rewinding. A value of 1 means normal playback and
32724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * 0 means paused.
32824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
32984b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik     * @return The current speed of playback.
33024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
33184b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik    public float getPlaybackSpeed() {
33284b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik        return mSpeed;
33324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
33424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
33524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
33624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current actions available on this session. This should use a
33724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * bitmask of the available actions.
33824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <ul>
33924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_PREVIOUS}</li>
34024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#ACTION_REWIND}</li>
34124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#ACTION_PLAY}</li>
34224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#ACTION_PAUSE}</li>
34324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#ACTION_STOP}</li>
34424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#ACTION_FAST_FORWARD}</li>
34524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_NEXT}</li>
34624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#ACTION_SEEK_TO}</li>
34724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li> {@link PlaybackStateCompat#ACTION_SET_RATING}</li>
34824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * </ul>
34924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
35024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public long getActions() {
35124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mActions;
35224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
35324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
35424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
355ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     * Get the list of custom actions.
356ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     */
357ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    public List<PlaybackStateCompat.CustomAction> getCustomActions() {
358ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        return mCustomActions;
359ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    }
360ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
361ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    /**
36224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get a user readable error message. This should be set when the state is
36324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * {@link PlaybackStateCompat#STATE_ERROR}.
36424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
36524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public CharSequence getErrorMessage() {
36624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mErrorMessage;
36724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
36824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
36924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
37024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the elapsed real time at which position was last updated. If the
37124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * position has never been set this will return 0;
37224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
37324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The last time the position was updated.
37424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
37524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public long getLastPositionUpdateTime() {
37624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mUpdateTime;
37724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
37824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
37924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
380ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     * Get the id of the currently active item in the queue. If there is no
381ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     * queue or a queue is not supported by the session this will be
382ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     * {@link MediaSessionCompat.QueueItem#UNKNOWN_ID}.
383ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     *
384ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     * @return The id of the currently active item in the queue or
385ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     *         {@link MediaSessionCompat.QueueItem#UNKNOWN_ID}.
386ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     */
387ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    public long getActiveQueueItemId() {
388ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        return mActiveItemId;
389ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    }
390ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
391ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    /**
392ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     * Get any custom extras that were set on this playback state.
393ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     *
394ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     * @return The extras for this state or null.
395ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake     */
396ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    public @Nullable Bundle getExtras() {
397ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        return mExtras;
398ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    }
399ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
400ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake    /**
40124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Creates an instance from a framework {@link android.media.session.PlaybackState} object.
40224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <p>
40324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * This method is only supported on API 21+.
40424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * </p>
40524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
40624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param stateObj A {@link android.media.session.PlaybackState} object, or null if none.
40724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return An equivalent {@link PlaybackStateCompat} object, or null if none.
40824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
40924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static PlaybackStateCompat fromPlaybackState(Object stateObj) {
41024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (stateObj == null || Build.VERSION.SDK_INT < 21) {
41124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
41224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
41324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
414ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        List<Object> customActionObjs = PlaybackStateCompatApi21.getCustomActions(stateObj);
415ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        List<PlaybackStateCompat.CustomAction> customActions = null;
416ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        if (customActionObjs != null) {
417ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            customActions = new ArrayList<>(customActionObjs.size());
418ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            for (Object customActionObj : customActionObjs) {
419ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                customActions.add(CustomAction.fromCustomAction(customActionObj));
420ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            }
421ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        }
422ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        Bundle extras = Build.VERSION.SDK_INT >= 22
423ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                ? PlaybackStateCompatApi22.getExtras(stateObj)
424ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                : null;
42524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        PlaybackStateCompat state = new PlaybackStateCompat(
42624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                PlaybackStateCompatApi21.getState(stateObj),
42724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                PlaybackStateCompatApi21.getPosition(stateObj),
428312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                PlaybackStateCompatApi21.getBufferedPosition(stateObj),
42984b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik                PlaybackStateCompatApi21.getPlaybackSpeed(stateObj),
43024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                PlaybackStateCompatApi21.getActions(stateObj),
43124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                PlaybackStateCompatApi21.getErrorMessage(stateObj),
432ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                PlaybackStateCompatApi21.getLastPositionUpdateTime(stateObj),
433ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                customActions,
434ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                PlaybackStateCompatApi21.getActiveQueueItemId(stateObj),
435ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                extras);
43624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        state.mStateObj = stateObj;
43724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return state;
43824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
43924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
44024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
44124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Gets the underlying framework {@link android.media.session.PlaybackState} object.
44224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <p>
44324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * This method is only supported on API 21+.
44424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * </p>
44524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
44624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return An equivalent {@link android.media.session.PlaybackState} object, or null if none.
44724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
44824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public Object getPlaybackState() {
44924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (mStateObj != null || Build.VERSION.SDK_INT < 21) {
45024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mStateObj;
45124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
45224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
453ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        List<Object> customActions = null;
454ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        if (mCustomActions != null) {
455ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            customActions = new ArrayList<>(mCustomActions.size());
456ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            for (PlaybackStateCompat.CustomAction customAction : mCustomActions) {
457ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                customActions.add(customAction.getCustomAction());
458ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            }
459ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        }
460ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        if (Build.VERSION.SDK_INT >= 22) {
461ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            mStateObj = PlaybackStateCompatApi22.newInstance(mState, mPosition, mBufferedPosition,
462ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    mSpeed, mActions, mErrorMessage, mUpdateTime,
463ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    customActions, mActiveItemId, mExtras);
464ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        } else {
465ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            mStateObj = PlaybackStateCompatApi21.newInstance(mState, mPosition, mBufferedPosition,
466ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    mSpeed, mActions, mErrorMessage, mUpdateTime,
467ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    customActions, mActiveItemId);
468ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        }
46924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mStateObj;
47024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
47124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
47224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final Parcelable.Creator<PlaybackStateCompat> CREATOR =
47324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            new Parcelable.Creator<PlaybackStateCompat>() {
47424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
47524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public PlaybackStateCompat createFromParcel(Parcel in) {
47624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return new PlaybackStateCompat(in);
47724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
47824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
47924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
48024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public PlaybackStateCompat[] newArray(int size) {
48124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return new PlaybackStateCompat[size];
48224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
48324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    };
48424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
48524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
486aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link PlaybackStateCompat.CustomAction CustomActions} can be used to
487aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * extend the capabilities of the standard transport controls by exposing
488aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * app specific actions to {@link MediaControllerCompat Controllers}.
489aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
490aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public static final class CustomAction implements Parcelable {
491aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        private final String mAction;
492aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        private final CharSequence mName;
493aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        private final int mIcon;
494aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        private final Bundle mExtras;
495aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
496ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        private Object mCustomActionObj;
497ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
498aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
499aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Use {@link PlaybackStateCompat.CustomAction.Builder#build()}.
500aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
501aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        private CustomAction(String action, CharSequence name, int icon, Bundle extras) {
502aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            mAction = action;
503aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            mName = name;
504aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            mIcon = icon;
505aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            mExtras = extras;
506aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
507aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
508aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        private CustomAction(Parcel in) {
509aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            mAction = in.readString();
510aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
511aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            mIcon = in.readInt();
512aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            mExtras = in.readBundle();
513aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
514aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
515aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
516aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void writeToParcel(Parcel dest, int flags) {
517aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            dest.writeString(mAction);
518aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            TextUtils.writeToParcel(mName, dest, flags);
519aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            dest.writeInt(mIcon);
520aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            dest.writeBundle(mExtras);
521aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
522aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
523aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
524aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public int describeContents() {
525aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return 0;
526aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
527aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
528ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        /**
529ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * Creates an instance from a framework
530ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * {@link android.media.session.PlaybackState.CustomAction} object.
531ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * <p>
532ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * This method is only supported on API 21+.
533ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * </p>
534ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *
535ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @param customActionObj A {@link android.media.session.PlaybackState.CustomAction} object,
536ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * or null if none.
537ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @return An equivalent {@link PlaybackStateCompat.CustomAction} object, or null if none.
538ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         */
539ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        public static PlaybackStateCompat.CustomAction fromCustomAction(Object customActionObj) {
540ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            if (customActionObj == null || Build.VERSION.SDK_INT < 21) {
541ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                return null;
542ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            }
543ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
544ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            PlaybackStateCompat.CustomAction customAction = new PlaybackStateCompat.CustomAction(
545ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    PlaybackStateCompatApi21.CustomAction.getAction(customActionObj),
546ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    PlaybackStateCompatApi21.CustomAction.getName(customActionObj),
547ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    PlaybackStateCompatApi21.CustomAction.getIcon(customActionObj),
548ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    PlaybackStateCompatApi21.CustomAction.getExtras(customActionObj));
549ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            customAction.mCustomActionObj = customActionObj;
550ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            return customAction;
551ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        }
552ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
553ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        /**
554ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * Gets the underlying framework {@link android.media.session.PlaybackState.CustomAction}
555ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * object.
556ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * <p>
557ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * This method is only supported on API 21+.
558ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * </p>
559ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *
560ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @return An equivalent {@link android.media.session.PlaybackState.CustomAction} object,
561ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * or null if none.
562ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         */
563ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        public Object getCustomAction() {
564ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            if (mCustomActionObj != null || Build.VERSION.SDK_INT < 21) {
565ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                return mCustomActionObj;
566ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            }
567ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
568ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            mCustomActionObj = PlaybackStateCompatApi21.CustomAction.newInstance(mAction,
569ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    mName, mIcon, mExtras);
570ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            return mCustomActionObj;
571ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        }
572ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
573aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public static final Parcelable.Creator<PlaybackStateCompat.CustomAction> CREATOR
574aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                = new Parcelable.Creator<PlaybackStateCompat.CustomAction>() {
575aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
576aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    @Override
577aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    public PlaybackStateCompat.CustomAction createFromParcel(Parcel p) {
578aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                        return new PlaybackStateCompat.CustomAction(p);
579aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    }
580aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
581aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    @Override
582aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    public PlaybackStateCompat.CustomAction[] newArray(int size) {
583aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                        return new PlaybackStateCompat.CustomAction[size];
584aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    }
585aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                };
586aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
587aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
588aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Returns the action of the {@link CustomAction}.
589aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
590aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @return The action of the {@link CustomAction}.
591aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
592aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public String getAction() {
593aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return mAction;
594aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
595aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
596aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
597aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Returns the display name of this action. e.g. "Favorite"
598aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
599aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @return The display name of this {@link CustomAction}.
600aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
601aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public CharSequence getName() {
602aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return mName;
603aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
604aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
605aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
606aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Returns the resource id of the icon in the {@link MediaSessionCompat
607aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Session's} package.
608aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
609aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @return The resource id of the icon in the {@link MediaSessionCompat
610aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *         Session's} package.
611aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
612aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public int getIcon() {
613aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return mIcon;
614aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
615aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
616aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
617aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Returns extras which provide additional application-specific
618aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * information about the action, or null if none. These arguments are
619aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * meant to be consumed by a {@link MediaControllerCompat} if it knows
620aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * how to handle them.
621aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
622aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @return Optional arguments for the {@link CustomAction}.
623aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
624aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public Bundle getExtras() {
625aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return mExtras;
626aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
627aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
628aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
629aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public String toString() {
630aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return "Action:" +
631aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    "mName='" + mName +
632aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    ", mIcon=" + mIcon +
633aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    ", mExtras=" + mExtras;
634aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
635aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
636aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
637aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Builder for {@link CustomAction} objects.
638aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
639aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public static final class Builder {
640aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            private final String mAction;
641aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            private final CharSequence mName;
642aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            private final int mIcon;
643aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            private Bundle mExtras;
644aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
645aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            /**
646aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * Creates a {@link CustomAction} builder with the id, name, and
647aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * icon set.
648aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             *
649aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * @param action The action of the {@link CustomAction}.
650aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * @param name The display name of the {@link CustomAction}. This
651aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             *            name will be displayed along side the action if the UI
652aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             *            supports it.
653aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * @param icon The icon resource id of the {@link CustomAction}.
654aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             *            This resource id must be in the same package as the
655aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             *            {@link MediaSessionCompat}. It will be displayed with
656aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             *            the custom action if the UI supports it.
657aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             */
658aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            public Builder(String action, CharSequence name, int icon) {
659aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                if (TextUtils.isEmpty(action)) {
660aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    throw new IllegalArgumentException(
661aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                            "You must specify an action to build a CustomAction.");
662aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                }
663aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                if (TextUtils.isEmpty(name)) {
664aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    throw new IllegalArgumentException(
665aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                            "You must specify a name to build a CustomAction.");
666aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                }
667aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                if (icon == 0) {
668aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    throw new IllegalArgumentException(
669aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                            "You must specify an icon resource id to build a CustomAction.");
670aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                }
671aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                mAction = action;
672aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                mName = name;
673aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                mIcon = icon;
674aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            }
675aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
676aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            /**
677aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * Set optional extras for the {@link CustomAction}. These extras
678aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * are meant to be consumed by a {@link MediaControllerCompat} if it
679aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * knows how to handle them. Keys should be fully qualified (e.g.
680aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * "com.example.MY_ARG") to avoid collisions.
681aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             *
682aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * @param extras Optional extras for the {@link CustomAction}.
683aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * @return this.
684aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             */
685aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            public Builder setExtras(Bundle extras) {
686aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                mExtras = extras;
687aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                return this;
688aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            }
689aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
690aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            /**
691aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * Build and return the {@link CustomAction} instance with the
692aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * specified values.
693aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             *
694aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             * @return A new {@link CustomAction} instance.
695aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik             */
696aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            public CustomAction build() {
697aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                return new CustomAction(mAction, mName, mIcon, mExtras);
698aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            }
699aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
700aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
701aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
702aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
70324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Builder for {@link PlaybackStateCompat} objects.
70424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
70524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final class Builder {
706ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        private final List<PlaybackStateCompat.CustomAction> mCustomActions = new ArrayList<>();
707ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
70824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private int mState;
70924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private long mPosition;
710312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        private long mBufferedPosition;
71124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private float mRate;
71224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private long mActions;
71324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private CharSequence mErrorMessage;
71424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private long mUpdateTime;
715ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        private long mActiveItemId = MediaSessionCompat.QueueItem.UNKNOWN_ID;
716ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        private Bundle mExtras;
71724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
71824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
71924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Create an empty Builder.
72024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
72124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Builder() {
72224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
72324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
72424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
72524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Create a Builder using a {@link PlaybackStateCompat} instance to set the
72624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * initial values.
72724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
72824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param source The playback state to copy.
72924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
73024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Builder(PlaybackStateCompat source) {
73124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mState = source.mState;
73224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mPosition = source.mPosition;
73384b0350796e4ae8a113ce1abba54f07a2605cc5cRoboErik            mRate = source.mSpeed;
73424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mUpdateTime = source.mUpdateTime;
735312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            mBufferedPosition = source.mBufferedPosition;
73624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mActions = source.mActions;
73724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mErrorMessage = source.mErrorMessage;
738ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            if (source.mCustomActions != null) {
739ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                mCustomActions.addAll(source.mCustomActions);
740ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            }
741ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            mActiveItemId = source.mActiveItemId;
742ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            mExtras = source.mExtras;
74324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
74424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
74524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
74624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Set the current state of playback.
74724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <p>
748e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * The position must be in ms and indicates the current playback
749e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * position within the track. If the position is unknown use
75024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * {@link #PLAYBACK_POSITION_UNKNOWN}.
75124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <p>
752e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * The rate is a multiple of normal playback and should be 0 when paused
753e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * and negative when rewinding. Normal playback rate is 1.0.
75424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <p>
75524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * The state must be one of the following:
75624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <ul>
75724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#STATE_NONE}</li>
75824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li>
75924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li>
76024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li>
76124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li>
76224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li>
76324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li>
76424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#STATE_ERROR}</li>
76524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * </ul>
76624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
76724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param state The current state of playback.
76824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param position The position in the current track in ms.
769e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @param playbackSpeed The current rate of playback as a multiple of
770e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         *            normal playback.
77124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
772e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public Builder setState(int state, long position, float playbackSpeed) {
773e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
774e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
775e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
776e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        /**
777e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * Set the current state of playback.
778e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <p>
779e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * The position must be in ms and indicates the current playback
780e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * position within the track. If the position is unknown use
781e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * {@link #PLAYBACK_POSITION_UNKNOWN}.
782e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <p>
783e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * The rate is a multiple of normal playback and should be 0 when paused
784e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * and negative when rewinding. Normal playback rate is 1.0.
785e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <p>
786e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * The state must be one of the following:
787e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <ul>
788e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <li> {@link PlaybackStateCompat#STATE_NONE}</li>
789e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <li> {@link PlaybackStateCompat#STATE_STOPPED}</li>
790e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <li> {@link PlaybackStateCompat#STATE_PLAYING}</li>
791e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <li> {@link PlaybackStateCompat#STATE_PAUSED}</li>
792e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <li> {@link PlaybackStateCompat#STATE_FAST_FORWARDING}</li>
793e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <li> {@link PlaybackStateCompat#STATE_REWINDING}</li>
794e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <li> {@link PlaybackStateCompat#STATE_BUFFERING}</li>
795e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * <li> {@link PlaybackStateCompat#STATE_ERROR}</li>
796e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * </ul>
797e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         *
798e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @param state The current state of playback.
799e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @param position The position in the current item in ms.
800e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @param playbackSpeed The current speed of playback as a multiple of
801e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         *            normal playback.
802e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
803e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         *            timebase that the position was updated at.
804e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @return this
805e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         */
806e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public Builder setState(int state, long position, float playbackSpeed, long updateTime) {
807e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mState = state;
808e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mPosition = position;
809e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mUpdateTime = updateTime;
810e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mRate = playbackSpeed;
811e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return this;
81224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
81324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
81424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
815312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * Set the current buffered position in ms. This is the farthest
816312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * playback point that can be reached from the current position using
817312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * only buffered content.
818e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         *
819e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @return this
82024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
821e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public Builder setBufferedPosition(long bufferPosition) {
822312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            mBufferedPosition = bufferPosition;
823e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return this;
82424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
82524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
82624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
827e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * Set the current capabilities available on this session. This should
828e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * use a bitmask of the available capabilities.
82924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <ul>
83024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_PREVIOUS}</li>
83124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#ACTION_REWIND}</li>
83224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#ACTION_PLAY}</li>
83324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#ACTION_PAUSE}</li>
83424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#ACTION_STOP}</li>
83524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#ACTION_FAST_FORWARD}</li>
83624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#ACTION_SKIP_TO_NEXT}</li>
83724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#ACTION_SEEK_TO}</li>
83824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li> {@link PlaybackStateCompat#ACTION_SET_RATING}</li>
83924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * </ul>
840e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         *
841e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @return this
84224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
843e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public Builder setActions(long capabilities) {
84424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mActions = capabilities;
845e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return this;
84624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
84724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
84824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
849ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * Add a custom action to the playback state. Actions can be used to
850ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * expose additional functionality to {@link MediaControllerCompat
851ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * Controllers} beyond what is offered by the standard transport
852ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * controls.
853ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * <p>
854ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * e.g. start a radio station based on the current item or skip ahead by
855ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * 30 seconds.
856ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *
857ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @param action An identifier for this action. It can be sent back to
858ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *            the {@link MediaSessionCompat} through
859ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *            {@link MediaControllerCompat.TransportControls#sendCustomAction(String, Bundle)}.
860ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @param name The display name for the action. If text is shown with
861ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *            the action or used for accessibility, this is what should
862ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *            be used.
863ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @param icon The resource action of the icon that should be displayed
864ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *            for the action. The resource should be in the package of
865ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *            the {@link MediaSessionCompat}.
866ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @return this
867ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         */
868ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        public Builder addCustomAction(String action, String name, int icon) {
869ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            return addCustomAction(new PlaybackStateCompat.CustomAction(action, name, icon, null));
870ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        }
871ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
872ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        /**
873ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * Add a custom action to the playback state. Actions can be used to expose additional
874ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * functionality to {@link MediaControllerCompat Controllers} beyond what is offered
875ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * by the standard transport controls.
876ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * <p>
877ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * An example of an action would be to start a radio station based on the current item
878ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * or to skip ahead by 30 seconds.
879ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *
880ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @param customAction The custom action to add to the {@link PlaybackStateCompat}.
881ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @return this
882ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         */
883ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        public Builder addCustomAction(PlaybackStateCompat.CustomAction customAction) {
884ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            if (customAction == null) {
885ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                throw new IllegalArgumentException(
886ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                        "You may not add a null CustomAction to PlaybackStateCompat.");
887ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            }
888ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            mCustomActions.add(customAction);
889ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            return this;
890ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        }
891ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
892ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        /**
893ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * Set the active item in the play queue by specifying its id. The
894ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * default value is {@link MediaSessionCompat.QueueItem#UNKNOWN_ID}
895ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *
896ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @param id The id of the active item.
897ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @return this
898ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         */
899ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        public Builder setActiveQueueItemId(long id) {
900ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            mActiveItemId = id;
901ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            return this;
902ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        }
903ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
904ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        /**
905e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * Set a user readable error message. This should be set when the state
906e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * is {@link PlaybackStateCompat#STATE_ERROR}.
907e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         *
908e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @return this
90924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
910e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public Builder setErrorMessage(CharSequence errorMessage) {
91124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mErrorMessage = errorMessage;
912e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return this;
91324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
91424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
91524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
916ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * Set any custom extras to be included with the playback state.
917ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         *
918ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @param extras The extras to include.
919ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         * @return this
920ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake         */
921ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        public Builder setExtras(Bundle extras) {
922ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            mExtras = extras;
923ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake            return this;
924ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        }
925ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake
926ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake        /**
92724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Creates the playback state object.
92824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
92924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public PlaybackStateCompat build() {
930312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            return new PlaybackStateCompat(mState, mPosition, mBufferedPosition,
931ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    mRate, mActions, mErrorMessage, mUpdateTime,
932ea79b7d36972eb3f518a7e7b59a92e7bd5faefb4Ian Lake                    mCustomActions, mActiveItemId, mExtras);
93324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
93424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
93524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown}
936