1129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown/*
2129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * Copyright (C) 2013 The Android Open Source Project
3129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown *
4129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * you may not use this file except in compliance with the License.
6129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * You may obtain a copy of the License at
7129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown *
8129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown *
10129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * Unless required by applicable law or agreed to in writing, software
11129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * See the License for the specific language governing permissions and
14129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * limitations under the License.
15129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown */
16129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown
17129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brownpackage android.support.v7.media;
18129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown
193d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brownimport android.app.PendingIntent;
20129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brownimport android.os.Bundle;
213d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brownimport android.os.SystemClock;
223d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brownimport android.support.v4.util.TimeUtils;
23129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown
24129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown/**
253d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * Describes the playback status of a media item.
263d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * <p>
27bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown * This class is part of the remote playback protocol described by the
28bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown * {@link MediaControlIntent MediaControlIntent} class.
29bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown * </p><p>
303d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * As a media item is played, it transitions through a sequence of states including:
31eff7719415542ba819054863b0995f07742a7a8aJeff Brown * {@link #PLAYBACK_STATE_PENDING pending}, {@link #PLAYBACK_STATE_BUFFERING buffering},
323d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * {@link #PLAYBACK_STATE_PLAYING playing}, {@link #PLAYBACK_STATE_PAUSED paused},
33eff7719415542ba819054863b0995f07742a7a8aJeff Brown * {@link #PLAYBACK_STATE_FINISHED finished}, {@link #PLAYBACK_STATE_CANCELED canceled},
34eff7719415542ba819054863b0995f07742a7a8aJeff Brown * {@link #PLAYBACK_STATE_INVALIDATED invalidated}, and
353d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * {@link #PLAYBACK_STATE_ERROR error}.  Refer to the documentation of each state
363d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * for an explanation of its meaning.
373d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * </p><p>
383d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * While the item is playing, the playback status may also include progress information
393d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * about the {@link #getContentPosition content position} and
403d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * {@link #getContentDuration content duration} although not all route destinations
413d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * will report it.
423d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * </p><p>
43bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown * To monitor playback status, the application should supply a {@link PendingIntent} to use as the
44bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown * {@link MediaControlIntent#EXTRA_ITEM_STATUS_UPDATE_RECEIVER item status update receiver}
453d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * for a given {@link MediaControlIntent#ACTION_PLAY playback request}.  Note that
463d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * the status update receiver will only be invoked for major status changes such as a
47eff7719415542ba819054863b0995f07742a7a8aJeff Brown * transition from playing to finished.
483d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * </p><p class="note">
493d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * The status update receiver will not be invoked for minor progress updates such as
503d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * changes to playback position or duration.  If the application wants to monitor
513d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * playback progress, then it must use the
523d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * {@link MediaControlIntent#ACTION_GET_STATUS get status request} to poll for changes
533d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * periodically and estimate the playback position while playing.  Note that there may
543d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * be a significant power impact to polling so the application is advised only
553d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * to poll when the screen is on and never more than about once every 5 seconds or so.
563d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * </p><p>
573d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * This object is immutable once created using a {@link Builder} instance.
583d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * </p>
59129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown */
6043f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brownpublic final class MediaItemStatus {
613d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    private static final String KEY_TIMESTAMP = "timestamp";
623d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    private static final String KEY_PLAYBACK_STATE = "playbackState";
633d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    private static final String KEY_CONTENT_POSITION = "contentPosition";
643d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    private static final String KEY_CONTENT_DURATION = "contentDuration";
653d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    private static final String KEY_EXTRAS = "extras";
6655eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown
673d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    private final Bundle mBundle;
6855eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown
6955eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    /**
70eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Playback state: Pending.
7155eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * <p>
72eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Indicates that the media item has not yet started playback but will be played eventually.
7355eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * </p>
7455eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     */
75eff7719415542ba819054863b0995f07742a7a8aJeff Brown    public static final int PLAYBACK_STATE_PENDING = 0;
7655eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown
7755eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    /**
7855eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * Playback state: Playing.
7955eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * <p>
8043f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown     * Indicates that the media item is currently playing.
8155eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * </p>
8255eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     */
8355eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    public static final int PLAYBACK_STATE_PLAYING = 1;
8455eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown
8555eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    /**
8655eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * Playback state: Paused.
8755eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * <p>
88eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Indicates that playback of the media item has been paused.  Playback can be
89eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * resumed using the {@link MediaControlIntent#ACTION_RESUME resume} action.
9055eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * </p>
9155eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     */
9255eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    public static final int PLAYBACK_STATE_PAUSED = 2;
9355eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown
9455eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    /**
9555eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * Playback state: Buffering or seeking to a new position.
9655eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * <p>
9743f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown     * Indicates that the media item has been temporarily interrupted
98eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * to fetch more content.  Playback will continue automatically
9955eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * when enough content has been buffered.
10055eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * </p>
10155eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     */
10255eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    public static final int PLAYBACK_STATE_BUFFERING = 3;
10355eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown
10455eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    /**
105eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Playback state: Finished.
10655eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * <p>
107eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Indicates that the media item played to the end of the content and finished normally.
10855eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * </p><p>
109eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * A finished media item cannot be resumed.  To play the content again, the application
110bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown     * must send a new {@link MediaControlIntent#ACTION_PLAY play} or
111bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown     * {@link MediaControlIntent#ACTION_ENQUEUE enqueue} action.
11255eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * </p>
11355eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     */
114eff7719415542ba819054863b0995f07742a7a8aJeff Brown    public static final int PLAYBACK_STATE_FINISHED = 4;
11555eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown
11655eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    /**
11755eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * Playback state: Canceled.
11855eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * <p>
119eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Indicates that the media item was explicitly removed from the queue by the
120bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown     * application.  Items may be canceled and removed from the queue using
121bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown     * the {@link MediaControlIntent#ACTION_REMOVE remove} or
122eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * {@link MediaControlIntent#ACTION_STOP stop} action or by issuing
123eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * another {@link MediaControlIntent#ACTION_PLAY play} action that has the
124eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * side-effect of clearing the queue.
12555eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * </p><p>
126eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * A canceled media item cannot be resumed.  To play the content again, the
127bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown     * application must send a new {@link MediaControlIntent#ACTION_PLAY play} or
128bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown     * {@link MediaControlIntent#ACTION_ENQUEUE enqueue} action.
12955eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * </p>
13055eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     */
13155eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    public static final int PLAYBACK_STATE_CANCELED = 5;
13255eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown
13355eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    /**
134eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Playback state: Invalidated.
135eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * <p>
136eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Indicates that the media item was invalidated permanently and involuntarily.
137eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * This state is used to indicate that the media item was invalidated and removed
138eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * from the queue because the session to which it belongs was invalidated
139eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * (typically by another application taking control of the route).
140eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * </p><p>
141eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * When invalidation occurs, the application should generally wait for the user
142eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * to perform an explicit action, such as clicking on a play button in the UI,
143eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * before creating a new media session to avoid unnecessarily interrupting
144eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * another application that may have just started using the route.
145eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * </p><p>
146eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * An invalidated media item cannot be resumed.  To play the content again, the application
147bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown     * must send a new {@link MediaControlIntent#ACTION_PLAY play} or
148bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown     * {@link MediaControlIntent#ACTION_ENQUEUE enqueue} action.
149eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * </p>
150eff7719415542ba819054863b0995f07742a7a8aJeff Brown     */
151eff7719415542ba819054863b0995f07742a7a8aJeff Brown    public static final int PLAYBACK_STATE_INVALIDATED = 6;
152eff7719415542ba819054863b0995f07742a7a8aJeff Brown
153eff7719415542ba819054863b0995f07742a7a8aJeff Brown    /**
15455eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * Playback state: Playback halted or aborted due to an error.
15555eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * <p>
15643f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown     * Examples of errors are no network connectivity when attempting to retrieve content
15743f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown     * from a server, or expired user credentials when trying to play subscription-based
15843f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown     * content.
15955eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * </p><p>
16043f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown     * A media item in the error state cannot be resumed.  To play the content again,
161bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown     * the application must send a new {@link MediaControlIntent#ACTION_PLAY play} or
162bf1bbdfcb39667dfb3a98f5c14c118fab278ede0Jeff Brown     * {@link MediaControlIntent#ACTION_ENQUEUE enqueue} action.
16355eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     * </p>
16455eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown     */
165eff7719415542ba819054863b0995f07742a7a8aJeff Brown    public static final int PLAYBACK_STATE_ERROR = 7;
16655eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown
167fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown    /**
168fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * Integer extra: HTTP status code.
169fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * <p>
170fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * Specifies the HTTP status code that was encountered when the content
171fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * was requested after all redirects were followed.  This key only needs to
172fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * specified when the content uri uses the HTTP or HTTPS scheme and an error
173fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * occurred.  This key may be omitted if the content was able to be played
174fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * successfully; there is no need to report a 200 (OK) status code.
175fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * </p><p>
176fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * The value is an integer HTTP status code, such as 401 (Unauthorized),
177fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * 404 (Not Found), or 500 (Server Error), or 0 if none.
178fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * </p>
179fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     */
180fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown    public static final String EXTRA_HTTP_STATUS_CODE =
181fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown            "android.media.status.extra.HTTP_STATUS_CODE";
182fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown
183fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown    /**
184fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * Bundle extra: HTTP response headers.
185fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * <p>
186fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * Specifies the HTTP response headers that were returned when the content was
187fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * requested from the network.  The headers may include additional information
188fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * about the content or any errors conditions that were encountered while
189fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * trying to fetch the content.
190fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * </p><p>
191fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * The value is a {@link android.os.Bundle} of string based key-value pairs
192fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * that describe the HTTP response headers.
193fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     * </p>
194fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown     */
195fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown    public static final String EXTRA_HTTP_RESPONSE_HEADERS =
196fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown            "android.media.status.extra.HTTP_RESPONSE_HEADERS";
197fb75232cb13b19004ec1189888b46767db20daf4Jeff Brown
1983d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    private MediaItemStatus(Bundle bundle) {
1993d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        mBundle = bundle;
2003d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    }
2013d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
20255eb54486dde6c1eb7857bdfff29f420fb2ecdfbJeff Brown    /**
2033d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * Gets the timestamp associated with the status information in
2043d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * milliseconds since boot in the {@link SystemClock#elapsedRealtime} time base.
2053d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     *
2063d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * @return The status timestamp in the {@link SystemClock#elapsedRealtime()} time base.
2073d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     */
2083d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    public long getTimestamp() {
2093d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        return mBundle.getLong(KEY_TIMESTAMP);
2103d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    }
2113d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
2123d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    /**
2133d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * Gets the playback state of the media item.
2143d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     *
215eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * @return The playback state.  One of {@link #PLAYBACK_STATE_PENDING},
216eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * {@link #PLAYBACK_STATE_PLAYING}, {@link #PLAYBACK_STATE_PAUSED},
217eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * {@link #PLAYBACK_STATE_BUFFERING}, {@link #PLAYBACK_STATE_FINISHED},
218eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * {@link #PLAYBACK_STATE_CANCELED}, {@link #PLAYBACK_STATE_INVALIDATED},
219eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * or {@link #PLAYBACK_STATE_ERROR}.
2203d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     */
2213d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    public int getPlaybackState() {
222eff7719415542ba819054863b0995f07742a7a8aJeff Brown        return mBundle.getInt(KEY_PLAYBACK_STATE, PLAYBACK_STATE_ERROR);
2233d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    }
2243d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
2253d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    /**
226ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown     * Gets the content playback position as a long integer number of milliseconds
2273d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * from the beginning of the content.
2283d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     *
229ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown     * @return The content playback position in milliseconds, or -1 if unknown.
2303d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     */
231ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown    public long getContentPosition() {
232ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown        return mBundle.getLong(KEY_CONTENT_POSITION, -1);
2333d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    }
2343d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
2353d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    /**
236ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown     * Gets the total duration of the content to be played as a long integer number of
237ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown     * milliseconds.
2383d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     *
239ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown     * @return The content duration in milliseconds, or -1 if unknown.
2403d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     */
241ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown    public long getContentDuration() {
242ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown        return mBundle.getLong(KEY_CONTENT_DURATION, -1);
2433d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    }
2443d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
2453d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    /**
2463d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * Gets a bundle of extras for this status object.
2473d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * The extras will be ignored by the media router but they may be used
2483d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * by applications.
2493d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     */
2503d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    public Bundle getExtras() {
2513d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        return mBundle.getBundle(KEY_EXTRAS);
2523d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    }
2533d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
2543d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    @Override
2553d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    public String toString() {
2563d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        StringBuilder result = new StringBuilder();
2573d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        result.append("MediaItemStatus{ ");
2583d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        result.append("timestamp=");
2593d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        TimeUtils.formatDuration(SystemClock.elapsedRealtime() - getTimestamp(), result);
2603d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        result.append(" ms ago");
261eff7719415542ba819054863b0995f07742a7a8aJeff Brown        result.append(", playbackState=").append(playbackStateToString(getPlaybackState()));
2623d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        result.append(", contentPosition=").append(getContentPosition());
2633d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        result.append(", contentDuration=").append(getContentDuration());
2643d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        result.append(", extras=").append(getExtras());
2653d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        result.append(" }");
2663d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        return result.toString();
2673d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    }
2683d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
269eff7719415542ba819054863b0995f07742a7a8aJeff Brown    private static String playbackStateToString(int playbackState) {
270eff7719415542ba819054863b0995f07742a7a8aJeff Brown        switch (playbackState) {
271eff7719415542ba819054863b0995f07742a7a8aJeff Brown            case PLAYBACK_STATE_PENDING:
272eff7719415542ba819054863b0995f07742a7a8aJeff Brown                return "pending";
273eff7719415542ba819054863b0995f07742a7a8aJeff Brown            case PLAYBACK_STATE_BUFFERING:
274eff7719415542ba819054863b0995f07742a7a8aJeff Brown                return "buffering";
275eff7719415542ba819054863b0995f07742a7a8aJeff Brown            case PLAYBACK_STATE_PLAYING:
276eff7719415542ba819054863b0995f07742a7a8aJeff Brown                return "playing";
277eff7719415542ba819054863b0995f07742a7a8aJeff Brown            case PLAYBACK_STATE_PAUSED:
278eff7719415542ba819054863b0995f07742a7a8aJeff Brown                return "paused";
279eff7719415542ba819054863b0995f07742a7a8aJeff Brown            case PLAYBACK_STATE_FINISHED:
280eff7719415542ba819054863b0995f07742a7a8aJeff Brown                return "finished";
281eff7719415542ba819054863b0995f07742a7a8aJeff Brown            case PLAYBACK_STATE_CANCELED:
282eff7719415542ba819054863b0995f07742a7a8aJeff Brown                return "canceled";
283eff7719415542ba819054863b0995f07742a7a8aJeff Brown            case PLAYBACK_STATE_INVALIDATED:
284eff7719415542ba819054863b0995f07742a7a8aJeff Brown                return "invalidated";
285eff7719415542ba819054863b0995f07742a7a8aJeff Brown            case PLAYBACK_STATE_ERROR:
286eff7719415542ba819054863b0995f07742a7a8aJeff Brown                return "error";
287eff7719415542ba819054863b0995f07742a7a8aJeff Brown        }
288eff7719415542ba819054863b0995f07742a7a8aJeff Brown        return Integer.toString(playbackState);
289eff7719415542ba819054863b0995f07742a7a8aJeff Brown    }
290eff7719415542ba819054863b0995f07742a7a8aJeff Brown
2913d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    /**
2923d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * Converts this object to a bundle for serialization.
2933d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     *
2943d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * @return The contents of the object represented as a bundle.
2953d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     */
2963d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    public Bundle asBundle() {
2973d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        return mBundle;
2983d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    }
2993d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3003d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    /**
3013d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * Creates an instance from a bundle.
3023d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     *
3033d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * @param bundle The bundle, or null if none.
3043d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * @return The new instance, or null if the bundle was null.
3053d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     */
3063d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    public static MediaItemStatus fromBundle(Bundle bundle) {
3073d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        return bundle != null ? new MediaItemStatus(bundle) : null;
3083d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    }
3093d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3103d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    /**
3113d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     * Builder for {@link MediaItemStatus media item status objects}.
3123d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown     */
3133d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    public static final class Builder {
3143d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        private final Bundle mBundle;
3153d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3163d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        /**
3173d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * Creates a media item status builder using the current time as the
3183d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * reference timestamp.
3193d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         *
3203d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * @param playbackState The item playback state.
3213d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         */
3223d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        public Builder(int playbackState) {
3233d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            mBundle = new Bundle();
3243d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            setTimestamp(SystemClock.elapsedRealtime());
3253d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            setPlaybackState(playbackState);
3263d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        }
3273d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3283d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        /**
3293d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * Creates a media item status builder whose initial contents are
3303d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * copied from an existing status.
3313d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         */
3323d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        public Builder(MediaItemStatus status) {
3333d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            if (status == null) {
3343d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                throw new IllegalArgumentException("status must not be null");
3353d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            }
3363d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3373d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            mBundle = new Bundle(status.mBundle);
3383d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        }
3393d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3403d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        /**
3413d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * Sets the timestamp associated with the status information in
3423d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * milliseconds since boot in the {@link SystemClock#elapsedRealtime} time base.
3433d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         */
3443d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        public Builder setTimestamp(long elapsedRealtimeTimestamp) {
3453d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            mBundle.putLong(KEY_TIMESTAMP, elapsedRealtimeTimestamp);
3463d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            return this;
3473d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        }
3483d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3493d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        /**
3503d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * Sets the playback state of the media item.
3513d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         */
3523d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        public Builder setPlaybackState(int playbackState) {
3533d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            mBundle.putInt(KEY_PLAYBACK_STATE, playbackState);
3543d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            return this;
3553d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        }
3563d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3573d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        /**
358ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown         * Sets the content playback position as a long integer number of milliseconds
3593d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * from the beginning of the content.
3603d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         */
361ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown        public Builder setContentPosition(long positionMilliseconds) {
362ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown            mBundle.putLong(KEY_CONTENT_POSITION, positionMilliseconds);
3633d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            return this;
3643d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        }
3653d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3663d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        /**
367ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown         * Sets the total duration of the content to be played as a long integer number
368ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown         * of milliseconds.
3693d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         */
370ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown        public Builder setContentDuration(long durationMilliseconds) {
371ba811896e3057cb48ad0f017efe1bf0c262430ecJeff Brown            mBundle.putLong(KEY_CONTENT_DURATION, durationMilliseconds);
3723d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            return this;
3733d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        }
3743d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3753d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        /**
3763d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * Sets a bundle of extras for this status object.
3773d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * The extras will be ignored by the media router but they may be used
3783d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * by applications.
3793d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         */
3803d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        public Builder setExtras(Bundle extras) {
3813d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            mBundle.putBundle(KEY_EXTRAS, extras);
3823d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            return this;
3833d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        }
3843d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3853d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        /**
3863d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         * Builds the {@link MediaItemStatus media item status object}.
3873d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown         */
3883d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        public MediaItemStatus build() {
3893d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown            return new MediaItemStatus(mBundle);
3903d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown        }
3913d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown    }
392129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown}
393