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