MediaItemStatus.java revision 3d4c9459ed77f732dd3ba602713af6ebf9280c8c
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v7.media; 18 19import android.app.PendingIntent; 20import android.os.Bundle; 21import android.os.SystemClock; 22import android.support.v4.util.TimeUtils; 23 24/** 25 * Describes the playback status of a media item. 26 * <p> 27 * As a media item is played, it transitions through a sequence of states including: 28 * {@link #PLAYBACK_STATE_QUEUED queued}, {@link #PLAYBACK_STATE_BUFFERING buffering}, 29 * {@link #PLAYBACK_STATE_PLAYING playing}, {@link #PLAYBACK_STATE_PAUSED paused}, 30 * {@link #PLAYBACK_STATE_STOPPED stopped}, {@link #PLAYBACK_STATE_CANCELED canceled}, 31 * {@link #PLAYBACK_STATE_ERROR error}. Refer to the documentation of each state 32 * for an explanation of its meaning. 33 * </p><p> 34 * While the item is playing, the playback status may also include progress information 35 * about the {@link #getContentPosition content position} and 36 * {@link #getContentDuration content duration} although not all route destinations 37 * will report it. 38 * </p><p> 39 * To monitor playback status, the application should supply a {@link PendingIntent} to use 40 * as the {@link MediaControlIntent#EXTRA_ITEM_STATUS_UPDATE_RECEIVER status update receiver} 41 * for a given {@link MediaControlIntent#ACTION_PLAY playback request}. Note that 42 * the status update receiver will only be invoked for major status changes such as a 43 * transition from playing to stopped. 44 * </p><p class="note"> 45 * The status update receiver will not be invoked for minor progress updates such as 46 * changes to playback position or duration. If the application wants to monitor 47 * playback progress, then it must use the 48 * {@link MediaControlIntent#ACTION_GET_STATUS get status request} to poll for changes 49 * periodically and estimate the playback position while playing. Note that there may 50 * be a significant power impact to polling so the application is advised only 51 * to poll when the screen is on and never more than about once every 5 seconds or so. 52 * </p><p> 53 * This object is immutable once created using a {@link Builder} instance. 54 * </p> 55 */ 56public final class MediaItemStatus { 57 private static final String KEY_TIMESTAMP = "timestamp"; 58 private static final String KEY_PLAYBACK_STATE = "playbackState"; 59 private static final String KEY_CONTENT_POSITION = "contentPosition"; 60 private static final String KEY_CONTENT_DURATION = "contentDuration"; 61 private static final String KEY_HTTP_STATUS_CODE = "httpStatusCode"; 62 private static final String KEY_EXTRAS = "extras"; 63 64 private final Bundle mBundle; 65 66 /** 67 * Playback state: Queued. 68 * <p> 69 * Indicates that the media item is in the queue to be played eventually. 70 * </p> 71 */ 72 public static final int PLAYBACK_STATE_QUEUED = 0; 73 74 /** 75 * Playback state: Playing. 76 * <p> 77 * Indicates that the media item is currently playing. 78 * </p> 79 */ 80 public static final int PLAYBACK_STATE_PLAYING = 1; 81 82 /** 83 * Playback state: Paused. 84 * <p> 85 * Indicates that the media item has been paused. Playback can be 86 * resumed playback by sending {@link MediaControlIntent#ACTION_RESUME}. 87 * </p> 88 */ 89 public static final int PLAYBACK_STATE_PAUSED = 2; 90 91 /** 92 * Playback state: Buffering or seeking to a new position. 93 * <p> 94 * Indicates that the media item has been temporarily interrupted 95 * to fetch more content. Playback will resume automatically 96 * when enough content has been buffered. 97 * </p> 98 */ 99 public static final int PLAYBACK_STATE_BUFFERING = 3; 100 101 /** 102 * Playback state: Stopped. 103 * <p> 104 * Indicates that the media item has been stopped permanently either because 105 * it reached the end of the content or because the user ended playback. 106 * </p><p> 107 * A stopped media item cannot be resumed. To play the content again, the application 108 * must send a new {@link MediaControlIntent#ACTION_PLAY} action to enqueue 109 * a new playback request and obtain a new media item id from that request. 110 * </p> 111 */ 112 public static final int PLAYBACK_STATE_STOPPED = 4; 113 114 /** 115 * Playback state: Canceled. 116 * <p> 117 * Indicates that the media item was canceled permanently. This may 118 * happen because a new media item was queued which caused this media item 119 * to be stopped and removed from the queue. 120 * </p><p> 121 * A canceled media item cannot be resumed. To play the content again, the application 122 * must send a new {@link MediaControlIntent#ACTION_PLAY} action to enqueue 123 * a new playback request and obtain a new media item id from that request. 124 * </p> 125 */ 126 public static final int PLAYBACK_STATE_CANCELED = 5; 127 128 /** 129 * Playback state: Playback halted or aborted due to an error. 130 * <p> 131 * Examples of errors are no network connectivity when attempting to retrieve content 132 * from a server, or expired user credentials when trying to play subscription-based 133 * content. 134 * </p><p> 135 * A media item in the error state cannot be resumed. To play the content again, 136 * the application must send a new {@link MediaControlIntent#ACTION_PLAY} action to enqueue 137 * a new playback request and obtain a new media item id from that request. 138 * </p> 139 */ 140 public static final int PLAYBACK_STATE_ERROR = 6; 141 142 private MediaItemStatus(Bundle bundle) { 143 mBundle = bundle; 144 } 145 146 /** 147 * Gets the timestamp associated with the status information in 148 * milliseconds since boot in the {@link SystemClock#elapsedRealtime} time base. 149 * 150 * @return The status timestamp in the {@link SystemClock#elapsedRealtime()} time base. 151 */ 152 public long getTimestamp() { 153 return mBundle.getLong(KEY_TIMESTAMP); 154 } 155 156 /** 157 * Gets the playback state of the media item. 158 * 159 * @return The playback state. One of {@link #PLAYBACK_STATE_QUEUED}, 160 * {@link #PLAYBACK_STATE_PLAYING}, 161 * {@link #PLAYBACK_STATE_PAUSED}, {@link #PLAYBACK_STATE_BUFFERING}, 162 * {@link #PLAYBACK_STATE_CANCELED}, or {@link #PLAYBACK_STATE_ERROR}. 163 */ 164 public int getPlaybackState() { 165 return mBundle.getInt(KEY_PLAYBACK_STATE, PLAYBACK_STATE_CANCELED); 166 } 167 168 /** 169 * Gets the content playback position as a floating point number of seconds 170 * from the beginning of the content. 171 * 172 * @return The content playback position in seconds, or -1 if unknown. 173 */ 174 public double getContentPosition() { 175 return mBundle.getDouble(KEY_CONTENT_POSITION, -1); 176 } 177 178 /** 179 * Gets the total duration of the content to be played as a floating point number 180 * of seconds. 181 * 182 * @return The content duration in seconds, or -1 if unknown. 183 */ 184 public double getContentDuration() { 185 return mBundle.getDouble(KEY_CONTENT_DURATION, -1); 186 } 187 188 /** 189 * Gets the associated HTTP status code. 190 * <p> 191 * Specifies the HTTP status code that was encountered when the content 192 * was requested after all redirects were followed. This key only needs to 193 * specified when the content uri uses the HTTP or HTTPS scheme and an error 194 * occurred. This key may be omitted if the content was able to be played 195 * successfully; there is no need to report a 200 (OK) status code. 196 * </p> 197 * 198 * @return The HTTP status code from playback such as 401 (Unauthorized), 404 (Not Found), 199 * or 500 (Server Error), or 0 if none. 200 */ 201 public int getHttpStatusCode() { 202 return mBundle.getInt(KEY_HTTP_STATUS_CODE, 0); 203 } 204 205 /** 206 * Gets a bundle of extras for this status object. 207 * The extras will be ignored by the media router but they may be used 208 * by applications. 209 */ 210 public Bundle getExtras() { 211 return mBundle.getBundle(KEY_EXTRAS); 212 } 213 214 @Override 215 public String toString() { 216 StringBuilder result = new StringBuilder(); 217 result.append("MediaItemStatus{ "); 218 result.append("timestamp="); 219 TimeUtils.formatDuration(SystemClock.elapsedRealtime() - getTimestamp(), result); 220 result.append(" ms ago"); 221 result.append(", playbackState=").append(getPlaybackState()); 222 result.append(", contentPosition=").append(getContentPosition()); 223 result.append(", contentDuration=").append(getContentDuration()); 224 result.append(", httpStatusCode=").append(getHttpStatusCode()); 225 result.append(", extras=").append(getExtras()); 226 result.append(" }"); 227 return result.toString(); 228 } 229 230 /** 231 * Converts this object to a bundle for serialization. 232 * 233 * @return The contents of the object represented as a bundle. 234 */ 235 public Bundle asBundle() { 236 return mBundle; 237 } 238 239 /** 240 * Creates an instance from a bundle. 241 * 242 * @param bundle The bundle, or null if none. 243 * @return The new instance, or null if the bundle was null. 244 */ 245 public static MediaItemStatus fromBundle(Bundle bundle) { 246 return bundle != null ? new MediaItemStatus(bundle) : null; 247 } 248 249 /** 250 * Builder for {@link MediaItemStatus media item status objects}. 251 */ 252 public static final class Builder { 253 private final Bundle mBundle; 254 255 /** 256 * Creates a media item status builder using the current time as the 257 * reference timestamp. 258 * 259 * @param playbackState The item playback state. 260 */ 261 public Builder(int playbackState) { 262 mBundle = new Bundle(); 263 setTimestamp(SystemClock.elapsedRealtime()); 264 setPlaybackState(playbackState); 265 } 266 267 /** 268 * Creates a media item status builder whose initial contents are 269 * copied from an existing status. 270 */ 271 public Builder(MediaItemStatus status) { 272 if (status == null) { 273 throw new IllegalArgumentException("status must not be null"); 274 } 275 276 mBundle = new Bundle(status.mBundle); 277 } 278 279 /** 280 * Sets the timestamp associated with the status information in 281 * milliseconds since boot in the {@link SystemClock#elapsedRealtime} time base. 282 */ 283 public Builder setTimestamp(long elapsedRealtimeTimestamp) { 284 mBundle.putLong(KEY_TIMESTAMP, elapsedRealtimeTimestamp); 285 return this; 286 } 287 288 /** 289 * Sets the playback state of the media item. 290 */ 291 public Builder setPlaybackState(int playbackState) { 292 mBundle.putInt(KEY_PLAYBACK_STATE, playbackState); 293 return this; 294 } 295 296 /** 297 * Sets the content playback position as a floating point number of seconds 298 * from the beginning of the content. 299 */ 300 public Builder setContentPosition(double positionSeconds) { 301 mBundle.putDouble(KEY_CONTENT_POSITION, positionSeconds); 302 return this; 303 } 304 305 /** 306 * Sets the total duration of the content to be played as a floating point number 307 * of seconds. 308 */ 309 public Builder setContentDuration(double durationSeconds) { 310 mBundle.putDouble(KEY_CONTENT_DURATION, durationSeconds); 311 return this; 312 } 313 314 /** 315 * Sets the associated HTTP status code. 316 * <p> 317 * Specifies the HTTP status code that was encountered when the content 318 * was requested after all redirects were followed. This key only needs to 319 * specified when the content uri uses the HTTP or HTTPS scheme and an error 320 * occurred. This key may be omitted if the content was able to be played 321 * successfully; there is no need to report a 200 (OK) status code. 322 * </p> 323 */ 324 public Builder setHttpStatusCode(int httpStatusCode) { 325 mBundle.putInt(KEY_HTTP_STATUS_CODE, httpStatusCode); 326 return this; 327 } 328 329 /** 330 * Sets a bundle of extras for this status object. 331 * The extras will be ignored by the media router but they may be used 332 * by applications. 333 */ 334 public Builder setExtras(Bundle extras) { 335 mBundle.putBundle(KEY_EXTRAS, extras); 336 return this; 337 } 338 339 /** 340 * Builds the {@link MediaItemStatus media item status object}. 341 */ 342 public MediaItemStatus build() { 343 return new MediaItemStatus(mBundle); 344 } 345 } 346} 347