/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.support.v4.media.session; import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.support.annotation.RestrictTo; import android.text.TextUtils; import android.view.KeyEvent; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; /** * Playback state for a {@link MediaSessionCompat}. This includes a state like * {@link PlaybackStateCompat#STATE_PLAYING}, the current playback position, * and the current control capabilities. */ public final class PlaybackStateCompat implements Parcelable { /** * @hide */ @RestrictTo(LIBRARY_GROUP) @IntDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND, ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING, ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH, ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE, ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI, ACTION_SET_REPEAT_MODE, ACTION_SET_SHUFFLE_MODE_ENABLED, ACTION_SET_CAPTIONING_ENABLED}) @Retention(RetentionPolicy.SOURCE) public @interface Actions {} /** * @hide */ @RestrictTo(LIBRARY_GROUP) @IntDef({ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND, ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_PLAY_PAUSE}) @Retention(RetentionPolicy.SOURCE) public @interface MediaKeyAction {} /** * Indicates this session supports the stop command. * * @see Builder#setActions(long) */ public static final long ACTION_STOP = 1 << 0; /** * Indicates this session supports the pause command. * * @see Builder#setActions(long) */ public static final long ACTION_PAUSE = 1 << 1; /** * Indicates this session supports the play command. * * @see Builder#setActions(long) */ public static final long ACTION_PLAY = 1 << 2; /** * Indicates this session supports the rewind command. * * @see Builder#setActions(long) */ public static final long ACTION_REWIND = 1 << 3; /** * Indicates this session supports the previous command. * * @see Builder#setActions(long) */ public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4; /** * Indicates this session supports the next command. * * @see Builder#setActions(long) */ public static final long ACTION_SKIP_TO_NEXT = 1 << 5; /** * Indicates this session supports the fast forward command. * * @see Builder#setActions(long) */ public static final long ACTION_FAST_FORWARD = 1 << 6; /** * Indicates this session supports the set rating command. * * @see Builder#setActions(long) */ public static final long ACTION_SET_RATING = 1 << 7; /** * Indicates this session supports the seek to command. * * @see Builder#setActions(long) */ public static final long ACTION_SEEK_TO = 1 << 8; /** * Indicates this session supports the play/pause toggle command. * * @see Builder#setActions(long) */ public static final long ACTION_PLAY_PAUSE = 1 << 9; /** * Indicates this session supports the play from media id command. * * @see Builder#setActions(long) */ public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10; /** * Indicates this session supports the play from search command. * * @see Builder#setActions(long) */ public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11; /** * Indicates this session supports the skip to queue item command. * * @see Builder#setActions(long) */ public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12; /** * Indicates this session supports the play from URI command. * * @see Builder#setActions(long) */ public static final long ACTION_PLAY_FROM_URI = 1 << 13; /** * Indicates this session supports the prepare command. * * @see Builder#setActions(long) */ public static final long ACTION_PREPARE = 1 << 14; /** * Indicates this session supports the prepare from media id command. * * @see Builder#setActions(long) */ public static final long ACTION_PREPARE_FROM_MEDIA_ID = 1 << 15; /** * Indicates this session supports the prepare from search command. * * @see Builder#setActions(long) */ public static final long ACTION_PREPARE_FROM_SEARCH = 1 << 16; /** * Indicates this session supports the prepare from URI command. * * @see Builder#setActions(long) */ public static final long ACTION_PREPARE_FROM_URI = 1 << 17; /** * Indicates this session supports the set repeat mode command. * * @see Builder#setActions(long) */ public static final long ACTION_SET_REPEAT_MODE = 1 << 18; /** * Indicates this session supports the set shuffle mode enabled command. * * @see Builder#setActions(long) */ public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 1 << 19; /** * Indicates this session supports the set captioning enabled command. * * @see Builder#setActions(long) */ public static final long ACTION_SET_CAPTIONING_ENABLED = 1 << 20; /** * @hide */ @RestrictTo(LIBRARY_GROUP) @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING, STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING, STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM}) @Retention(RetentionPolicy.SOURCE) public @interface State {} /** * This is the default playback state and indicates that no media has been * added yet, or the performer has been reset and has no content to play. * * @see Builder#setState */ public final static int STATE_NONE = 0; /** * State indicating this item is currently stopped. * * @see Builder#setState */ public final static int STATE_STOPPED = 1; /** * State indicating this item is currently paused. * * @see Builder#setState */ public final static int STATE_PAUSED = 2; /** * State indicating this item is currently playing. * * @see Builder#setState */ public final static int STATE_PLAYING = 3; /** * State indicating this item is currently fast forwarding. * * @see Builder#setState */ public final static int STATE_FAST_FORWARDING = 4; /** * State indicating this item is currently rewinding. * * @see Builder#setState */ public final static int STATE_REWINDING = 5; /** * State indicating this item is currently buffering and will begin playing * when enough data has buffered. * * @see Builder#setState */ public final static int STATE_BUFFERING = 6; /** * State indicating this item is currently in an error state. The error * code should also be set when entering this state. * * @see Builder#setState * @see Builder#setErrorMessage(int, CharSequence) */ public final static int STATE_ERROR = 7; /** * State indicating the class doing playback is currently connecting to a * route. Depending on the implementation you may return to the previous * state when the connection finishes or enter {@link #STATE_NONE}. If * the connection failed {@link #STATE_ERROR} should be used. *
* On devices earlier than API 21, this will appear as {@link #STATE_BUFFERING} *
* * @see Builder#setState */ public final static int STATE_CONNECTING = 8; /** * State indicating the player is currently skipping to the previous item. * * @see Builder#setState */ public final static int STATE_SKIPPING_TO_PREVIOUS = 9; /** * State indicating the player is currently skipping to the next item. * * @see Builder#setState */ public final static int STATE_SKIPPING_TO_NEXT = 10; /** * State indicating the player is currently skipping to a specific item in * the queue. ** On devices earlier than API 21, this will appear as {@link #STATE_SKIPPING_TO_NEXT} *
* * @see Builder#setState */ public final static int STATE_SKIPPING_TO_QUEUE_ITEM = 11; /** * Use this value for the position to indicate the position is not known. */ public final static long PLAYBACK_POSITION_UNKNOWN = -1; /** * @hide */ @RestrictTo(LIBRARY_GROUP) @IntDef({REPEAT_MODE_NONE, REPEAT_MODE_ONE, REPEAT_MODE_ALL, REPEAT_MODE_GROUP}) @Retention(RetentionPolicy.SOURCE) public @interface RepeatMode {} /** * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode} * to indicate that the playback will be stopped at the end of the playing media list. */ public static final int REPEAT_MODE_NONE = 0; /** * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode} * to indicate that the playback of the current playing media item will be repeated. */ public static final int REPEAT_MODE_ONE = 1; /** * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode} * to indicate that the playback of the playing media list will be repeated. */ public static final int REPEAT_MODE_ALL = 2; /** * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode} * to indicate that the playback of the playing media group will be repeated. * A group is a logical block of media items which is specified in the section 5.7 of the * Bluetooth AVRCP 1.6. */ public static final int REPEAT_MODE_GROUP = 3; /** * @hide */ @RestrictTo(LIBRARY_GROUP) @IntDef({SHUFFLE_MODE_NONE, SHUFFLE_MODE_ALL, SHUFFLE_MODE_GROUP}) @Retention(RetentionPolicy.SOURCE) public @interface ShuffleMode {} /** * Use this value with {@link MediaControllerCompat.TransportControls#setShuffleMode} * to indicate that the media list will be played in order. */ public static final int SHUFFLE_MODE_NONE = 0; /** * Use this value with {@link MediaControllerCompat.TransportControls#setShuffleMode} * to indicate that the media list will be played in shuffled order. */ public static final int SHUFFLE_MODE_ALL = 1; /** * Use this value with {@link MediaControllerCompat.TransportControls#setShuffleMode} * to indicate that the media group will be played in shuffled order. * A group is a logical block of media items which is specified in the section 5.7 of the * Bluetooth AVRCP 1.6. */ public static final int SHUFFLE_MODE_GROUP = 2; /** * @hide */ @RestrictTo(LIBRARY_GROUP) @IntDef({ERROR_CODE_UNKNOWN_ERROR, ERROR_CODE_APP_ERROR, ERROR_CODE_NOT_SUPPORTED, ERROR_CODE_AUTHENTICATION_EXPIRED, ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED, ERROR_CODE_CONCURRENT_STREAM_LIMIT, ERROR_CODE_PARENTAL_CONTROL_RESTRICTED, ERROR_CODE_NOT_AVAILABLE_IN_REGION, ERROR_CODE_CONTENT_ALREADY_PLAYING, ERROR_CODE_SKIP_LIMIT_REACHED, ERROR_CODE_ACTION_ABORTED, ERROR_CODE_END_OF_QUEUE}) @Retention(RetentionPolicy.SOURCE) public @interface ErrorCode {} /** * This is the default error code and indicates that none of the other error codes applies. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_UNKNOWN_ERROR = 0; /** * Error code when the application state is invalid to fulfill the request. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_APP_ERROR = 1; /** * Error code when the request is not supported by the application. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_NOT_SUPPORTED = 2; /** * Error code when the request cannot be performed because authentication has expired. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; /** * Error code when a premium account is required for the request to succeed. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; /** * Error code when too many concurrent streams are detected. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; /** * Error code when the content is blocked due to parental controls. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; /** * Error code when the content is blocked due to being regionally unavailable. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; /** * Error code when the requested content is already playing. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; /** * Error code when the application cannot skip any more songs because skip limit is reached. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; /** * Error code when the action is interrupted due to some external event. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_ACTION_ABORTED = 10; /** * Error code when the playback navigation (previous, next) is not possible because the queue * was exhausted. * The error code should be set when entering {@link #STATE_ERROR}. */ public static final int ERROR_CODE_END_OF_QUEUE = 11; // KeyEvent constants only available on API 11+ private static final int KEYCODE_MEDIA_PAUSE = 127; private static final int KEYCODE_MEDIA_PLAY = 126; /** * Translates a given action into a matched key code defined in {@link KeyEvent}. The given * action should be one of the following: ** This method is only supported on API 21+. *
* * @param stateObj A {@link android.media.session.PlaybackState} object, or null if none. * @return An equivalent {@link PlaybackStateCompat} object, or null if none. */ public static PlaybackStateCompat fromPlaybackState(Object stateObj) { if (stateObj != null && Build.VERSION.SDK_INT >= 21) { List