diff --git a/api/current.txt b/api/current.txt index 0125dd6c305c0..9586d8ee7a01b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -15918,14 +15918,19 @@ package android.media.session { } public final class PlaybackState implements android.os.Parcelable { + ctor public PlaybackState(); + ctor public PlaybackState(android.media.session.PlaybackState); method public int describeContents(); method public long getActions(); method public long getBufferPosition(); method public java.lang.CharSequence getErrorMessage(); - method public long getLastPositionUpdateTime(); - method public float getPlaybackSpeed(); + method public float getPlaybackRate(); method public long getPosition(); method public int getState(); + method public void setActions(long); + method public void setBufferPosition(long); + method public void setErrorMessage(java.lang.CharSequence); + method public void setState(int, long, float); method public void writeToParcel(android.os.Parcel, int); field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L field public static final long ACTION_PAUSE = 2L; // 0x2L @@ -15951,17 +15956,6 @@ package android.media.session { field public static final int STATE_STOPPED = 1; // 0x1 } - public static final class PlaybackState.Builder { - ctor public PlaybackState.Builder(); - ctor public PlaybackState.Builder(android.media.session.PlaybackState); - method public android.media.session.PlaybackState build(); - method public android.media.session.PlaybackState.Builder setActions(long); - method public android.media.session.PlaybackState.Builder setBufferPosition(long); - method public android.media.session.PlaybackState.Builder setErrorMessage(java.lang.CharSequence); - method public android.media.session.PlaybackState.Builder setState(int, long, float, long); - method public android.media.session.PlaybackState.Builder setState(int, long, float); - } - } package android.media.tv { diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java index 740a9d3a4f575..73bc61a5875c5 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -682,13 +682,9 @@ public class RemoteControlClient // USE_SESSIONS if (mSession != null) { int pbState = PlaybackState.getStateFromRccState(state); - long position = hasPosition ? mPlaybackPositionMs - : PlaybackState.PLAYBACK_POSITION_UNKNOWN; - - PlaybackState.Builder bob = new PlaybackState.Builder(mSessionPlaybackState); - bob.setState(pbState, position, playbackSpeed, SystemClock.elapsedRealtime()); - bob.setErrorMessage(null); - mSessionPlaybackState = bob.build(); + mSessionPlaybackState.setState(pbState, hasPosition ? + mPlaybackPositionMs : PlaybackState.PLAYBACK_POSITION_UNKNOWN, + playbackSpeed); mSession.setPlaybackState(mSessionPlaybackState); } } @@ -749,9 +745,8 @@ public class RemoteControlClient // USE_SESSIONS if (mSession != null) { - PlaybackState.Builder bob = new PlaybackState.Builder(mSessionPlaybackState); - bob.setActions(PlaybackState.getActionsFromRccControlFlags(transportControlFlags)); - mSessionPlaybackState = bob.build(); + mSessionPlaybackState.setActions(PlaybackState + .getActionsFromRccControlFlags(transportControlFlags)); mSession.setPlaybackState(mSessionPlaybackState); } } @@ -951,7 +946,7 @@ public class RemoteControlClient /** * Cache for the current playback state using Session APIs. */ - private PlaybackState mSessionPlaybackState = null; + private final PlaybackState mSessionPlaybackState = new PlaybackState(); /** * Cache for metadata using Session APIs. This is re-initialized in apply(). diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java index 9ea3f26f609a9..1f5b216983448 100644 --- a/media/java/android/media/RemoteController.java +++ b/media/java/android/media/RemoteController.java @@ -1020,7 +1020,7 @@ public final class RemoteController l.onClientPlaybackStateUpdate(playstate); } else { l.onClientPlaybackStateUpdate(playstate, state.getLastPositionUpdateTime(), - state.getPosition(), state.getPlaybackSpeed()); + state.getPosition(), state.getPlaybackRate()); } if (state != null) { l.onClientTransportControlUpdate(PlaybackState.getRccControlFlagsFromActions(state diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java index 6595ee80fa108..6125cb49c3679 100644 --- a/media/java/android/media/session/PlaybackState.java +++ b/media/java/android/media/session/PlaybackState.java @@ -183,29 +183,41 @@ public final class PlaybackState implements Parcelable { */ public final static long PLAYBACK_POSITION_UNKNOWN = -1; - private final int mState; - private final long mPosition; - private final long mBufferPosition; - private final float mSpeed; - private final long mActions; - private final CharSequence mErrorMessage; - private final long mUpdateTime; + private int mState; + private long mPosition; + private long mBufferPosition; + private float mRate; + private long mActions; + private CharSequence mErrorMessage; + private long mUpdateTime; - private PlaybackState(int state, long position, long updateTime, float speed, - long bufferPosition, long actions, CharSequence error) { - mState = state; - mPosition = position; - mSpeed = speed; - mUpdateTime = updateTime; - mBufferPosition = bufferPosition; - mActions = actions; - mErrorMessage = error; + /** + * Create an empty PlaybackState. At minimum a state and actions should be + * set before publishing a PlaybackState. + */ + public PlaybackState() { + } + + /** + * Create a new PlaybackState from an existing PlaybackState. All fields + * will be copied to the new state. + * + * @param from The PlaybackState to duplicate + */ + public PlaybackState(PlaybackState from) { + mState = from.mState; + mPosition = from.mPosition; + mRate = from.mRate; + mUpdateTime = from.mUpdateTime; + mBufferPosition = from.mBufferPosition; + mActions = from.mActions; + mErrorMessage = from.mErrorMessage; } private PlaybackState(Parcel in) { mState = in.readInt(); mPosition = in.readLong(); - mSpeed = in.readFloat(); + mRate = in.readFloat(); mUpdateTime = in.readLong(); mBufferPosition = in.readLong(); mActions = in.readLong(); @@ -219,7 +231,7 @@ public final class PlaybackState implements Parcelable { bob.append("state=").append(mState); bob.append(", position=").append(mPosition); bob.append(", buffered position=").append(mBufferPosition); - bob.append(", speed=").append(mSpeed); + bob.append(", rate=").append(mRate); bob.append(", updated=").append(mUpdateTime); bob.append(", actions=").append(mActions); bob.append(", error=").append(mErrorMessage); @@ -236,7 +248,7 @@ public final class PlaybackState implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mState); dest.writeLong(mPosition); - dest.writeFloat(mSpeed); + dest.writeFloat(mRate); dest.writeLong(mUpdateTime); dest.writeLong(mBufferPosition); dest.writeLong(mActions); @@ -258,6 +270,41 @@ public final class PlaybackState implements Parcelable { public int getState() { return mState; } + + /** + * Set the current state of playback. + *

+ * The position must be in ms and indicates the current playback position + * within the track. If the position is unknown use + * {@link #PLAYBACK_POSITION_UNKNOWN}. + *

+ * The rate is a multiple of normal playback and should be 0 when paused and + * negative when rewinding. Normal playback rate is 1.0. + *

+ * The state must be one of the following: + *

+ * + * @param state The current state of playback. + * @param position The position in the current track in ms. + * @param playbackRate The current rate of playback as a multiple of normal + * playback. + */ + public void setState(int state, long position, float playbackRate) { + this.mState = state; + this.mPosition = position; + this.mRate = playbackRate; + mUpdateTime = SystemClock.elapsedRealtime(); + } + /** * Get the current playback position in ms. */ @@ -275,14 +322,23 @@ public final class PlaybackState implements Parcelable { } /** - * Get the current playback speed as a multiple of normal playback. This + * Set the current buffer position in ms. This is the farthest playback + * point that can be reached from the current position using only buffered + * content. + */ + public void setBufferPosition(long bufferPosition) { + mBufferPosition = bufferPosition; + } + + /** + * Get the current playback rate as a multiple of normal playback. This * should be negative when rewinding. A value of 1 means normal playback and * 0 means paused. * - * @return The current speed of playback. + * @return The current rate of playback. */ - public float getPlaybackSpeed() { - return mSpeed; + public float getPlaybackRate() { + return mRate; } /** @@ -304,6 +360,25 @@ public final class PlaybackState implements Parcelable { return mActions; } + /** + * Set the current capabilities available on this session. This should use a + * bitmask of the available capabilities. + * + */ + public void setActions(long capabilities) { + mActions = capabilities; + } + /** * Get a user readable error message. This should be set when the state is * {@link PlaybackState#STATE_ERROR}. @@ -317,11 +392,20 @@ public final class PlaybackState implements Parcelable { * position has never been set this will return 0; * * @return The last time the position was updated. + * @hide */ public long getLastPositionUpdateTime() { return mUpdateTime; } + /** + * Set a user readable error message. This should be set when the state is + * {@link PlaybackState#STATE_ERROR}. + */ + public void setErrorMessage(CharSequence errorMessage) { + mErrorMessage = errorMessage; + } + /** * Get the {@link PlaybackState} state for the given * {@link RemoteControlClient} state. @@ -489,175 +573,4 @@ public final class PlaybackState implements Parcelable { return new PlaybackState[size]; } }; - - /** - * Builder for {@link PlaybackState} objects. - */ - public static final class Builder { - private int mState; - private long mPosition; - private long mBufferPosition; - private float mSpeed; - private long mActions; - private CharSequence mErrorMessage; - private long mUpdateTime; - - /** - * Creates an initially empty state builder. - */ - public Builder() { - } - - /** - * Creates a builder with the same initial values as those in the from - * state. - * - * @param from The state to use for initializing the builder. - */ - public Builder(PlaybackState from) { - if (from == null) { - return; - } - mState = from.mState; - mPosition = from.mPosition; - mBufferPosition = from.mBufferPosition; - mSpeed = from.mSpeed; - mActions = from.mActions; - mErrorMessage = from.mErrorMessage; - mUpdateTime = from.mUpdateTime; - } - - /** - * Set the current state of playback. - *

- * The position must be in ms and indicates the current playback - * position within the track. If the position is unknown use - * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown - * position the time at which the position was updated must be provided. - * It is okay to use {@link SystemClock#elapsedRealtime()} if the - * current position was just retrieved. - *

- * The speed is a multiple of normal playback and should be 0 when - * paused and negative when rewinding. Normal playback speed is 1.0. - *

- * The state must be one of the following: - *

- * - * @param state The current state of playback. - * @param position The position in the current track in ms. - * @param playbackSpeed The current speed of playback as a multiple of - * normal playback. - * @param updateTime The time in the {@link SystemClock#elapsedRealtime} - * timebase that the position was updated at. - * @return this - */ - public Builder setState(int state, long position, float playbackSpeed, long updateTime) { - mState = state; - mPosition = position; - mUpdateTime = updateTime; - mSpeed = playbackSpeed; - return this; - } - - /** - * Set the current state of playback. - *

- * The position must be in ms and indicates the current playback - * position within the track. If the position is unknown use - * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to - * the current {@link SystemClock#elapsedRealtime()}. - *

- * The speed is a multiple of normal playback and should be 0 when - * paused and negative when rewinding. Normal playback speed is 1.0. - *

- * The state must be one of the following: - *

- * - * @param state The current state of playback. - * @param position The position in the current track in ms. - * @param playbackSpeed The current speed of playback as a multiple of - * normal playback. - * @return this - */ - public Builder setState(int state, long position, float playbackSpeed) { - return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime()); - } - - /** - * Set the current actions available on this session. This should use a - * bitmask of possible actions. - * - * - * @param actions The set of actions allowed. - * @return this - */ - public Builder setActions(long actions) { - mActions = actions; - return this; - } - - /** - * Set the current buffer position in ms. This is the farthest playback - * point that can be reached from the current position using only - * buffered content. - * - * @param bufferPosition The position in ms that playback is buffered - * to. - * @return this - */ - public Builder setBufferPosition(long bufferPosition) { - mBufferPosition = bufferPosition; - return this; - } - - /** - * Set a user readable error message. This should be set when the state - * is {@link PlaybackState#STATE_ERROR}. - * - * @param error The error message for display to the user. - * @return this - */ - public Builder setErrorMessage(CharSequence error) { - mErrorMessage = error; - return this; - } - - /** - * Build and return the PlaybackState instance with these values. - * - * @return A new state instance. - */ - public PlaybackState build() { - return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferPosition, - mActions, mErrorMessage); - } - } } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index cb09312e9ed7c..0fbcd7efcf722 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -682,19 +682,16 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { || state.getState() == PlaybackState.STATE_FAST_FORWARDING || state.getState() == PlaybackState.STATE_REWINDING) { long updateTime = state.getLastPositionUpdateTime(); - long currentTime = SystemClock.elapsedRealtime(); if (updateTime > 0) { - long position = (long) (state.getPlaybackSpeed() - * (currentTime - updateTime)) + state.getPosition(); + long position = (long) (state.getPlaybackRate() + * (SystemClock.elapsedRealtime() - updateTime)) + state.getPosition(); if (duration >= 0 && position > duration) { position = duration; } else if (position < 0) { position = 0; } - PlaybackState.Builder builder = new PlaybackState.Builder(state); - builder.setState(state.getState(), position, state.getPlaybackSpeed(), - currentTime); - result = builder.build(); + result = new PlaybackState(state); + result.setState(state.getState(), position, state.getPlaybackRate()); } } } diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java index af244386b11fd..a220107a24d59 100644 --- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java +++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java @@ -25,7 +25,6 @@ import android.media.session.MediaSession; import android.media.session.MediaSessionManager; import android.media.session.PlaybackState; import android.os.Bundle; -import android.os.SystemClock; import android.util.Log; import android.view.KeyEvent; @@ -59,9 +58,9 @@ public class PlayerSession { mRenderer = new LocalRenderer(context, null); mCallback = new SessionCb(); mRenderListener = new RenderListener(); - PlaybackState.Builder psBob = new PlaybackState.Builder(); - psBob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY); - mPlaybackState = psBob.build(); + mPlaybackState = new PlaybackState(); + mPlaybackState.setActions(PlaybackState.ACTION_PAUSE + | PlaybackState.ACTION_PLAY); mRenderer.registerListener(mRenderListener); @@ -119,10 +118,7 @@ public class PlayerSession { private void updateState(int newState) { float rate = newState == PlaybackState.STATE_PLAYING ? 1 : 0; long position = mRenderer == null ? -1 : mRenderer.getSeekPosition(); - PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState); - bob.setState(newState, position, rate, SystemClock.elapsedRealtime()); - bob.setErrorMessage(null); - mPlaybackState = bob.build(); + mPlaybackState.setState(newState, position, rate); mSession.setPlaybackState(mPlaybackState); } @@ -135,12 +131,10 @@ public class PlayerSession { @Override public void onError(int type, int extra, Bundle extras, Throwable error) { Log.d(TAG, "Sending onError with type " + type + " and extra " + extra); - PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState); - bob.setState(PlaybackState.STATE_ERROR, -1, 0, 0); + mPlaybackState.setState(PlaybackState.STATE_ERROR, -1, 0); if (error != null) { - bob.setErrorMessage(error.getLocalizedMessage()); + mPlaybackState.setErrorMessage(error.getLocalizedMessage()); } - mPlaybackState = bob.build(); mSession.setPlaybackState(mPlaybackState); if (mListener != null) { mListener.onPlayStateChanged(mPlaybackState); @@ -149,41 +143,36 @@ public class PlayerSession { @Override public void onStateChanged(int newState) { + if (newState != Renderer.STATE_ERROR) { + mPlaybackState.setErrorMessage(null); + } long position = -1; if (mRenderer != null) { position = mRenderer.getSeekPosition(); } - int pbState; - float rate = 0; - String errorMsg = null; switch (newState) { case Renderer.STATE_ENDED: case Renderer.STATE_STOPPED: - pbState = PlaybackState.STATE_STOPPED; + mPlaybackState.setState(PlaybackState.STATE_STOPPED, position, 0); break; case Renderer.STATE_INIT: case Renderer.STATE_PREPARING: - pbState = PlaybackState.STATE_BUFFERING; + mPlaybackState.setState(PlaybackState.STATE_BUFFERING, position, 0); break; case Renderer.STATE_ERROR: - pbState = PlaybackState.STATE_ERROR; + mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0); break; case Renderer.STATE_PAUSED: - pbState = PlaybackState.STATE_PAUSED; + mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0); break; case Renderer.STATE_PLAYING: - pbState = PlaybackState.STATE_PLAYING; - rate = 1; + mPlaybackState.setState(PlaybackState.STATE_PLAYING, position, 1); break; default: - pbState = PlaybackState.STATE_ERROR; - errorMsg = "unknown state"; + mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0); + mPlaybackState.setErrorMessage("unkown state"); break; } - PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState); - bob.setState(pbState, position, rate, SystemClock.elapsedRealtime()); - bob.setErrorMessage(errorMsg); - mPlaybackState = bob.build(); mSession.setPlaybackState(mPlaybackState); if (mListener != null) { mListener.onPlayStateChanged(mPlaybackState); @@ -198,10 +187,7 @@ public class PlayerSession { public void onFocusLost() { Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED); long position = mRenderer == null ? -1 : mRenderer.getSeekPosition(); - PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState); - bob.setState(PlaybackState.STATE_PAUSED, position, 0, SystemClock.elapsedRealtime()); - bob.setErrorMessage(null); - mPlaybackState = bob.build(); + mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0); mSession.setPlaybackState(mPlaybackState); if (mListener != null) { mListener.onPlayStateChanged(mPlaybackState); diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java index 0284a0302cf44..f2d691c0d4819 100644 --- a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java +++ b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java @@ -28,7 +28,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.ResultReceiver; -import android.os.SystemClock; import android.util.Log; import com.android.onemedia.playback.LocalRenderer; @@ -61,9 +60,9 @@ public class OneMediaRouteProvider extends RouteProviderService { mRouteId = UUID.randomUUID().toString(); mRenderer = new LocalRenderer(this, null); mRenderListener = new RenderListener(); - PlaybackState.Builder bob = new PlaybackState.Builder(); - bob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY); - mPlaybackState = bob.build(); + mPlaybackState = new PlaybackState(); + mPlaybackState.setActions(PlaybackState.ACTION_PAUSE + | PlaybackState.ACTION_PLAY); mRenderer.registerListener(mRenderListener); @@ -156,41 +155,36 @@ public class OneMediaRouteProvider extends RouteProviderService { @Override public void onStateChanged(int newState) { + if (newState != Renderer.STATE_ERROR) { + mPlaybackState.setErrorMessage(null); + } long position = -1; if (mRenderer != null) { position = mRenderer.getSeekPosition(); } - int pbState; - float rate = 0; - String errorMsg = null; switch (newState) { case Renderer.STATE_ENDED: case Renderer.STATE_STOPPED: - pbState = PlaybackState.STATE_STOPPED; + mPlaybackState.setState(PlaybackState.STATE_STOPPED, position, 0); break; case Renderer.STATE_INIT: case Renderer.STATE_PREPARING: - pbState = PlaybackState.STATE_BUFFERING; + mPlaybackState.setState(PlaybackState.STATE_BUFFERING, position, 0); break; case Renderer.STATE_ERROR: - pbState = PlaybackState.STATE_ERROR; + mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0); break; case Renderer.STATE_PAUSED: - pbState = PlaybackState.STATE_PAUSED; + mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0); break; case Renderer.STATE_PLAYING: - pbState = PlaybackState.STATE_PLAYING; - rate = 1; + mPlaybackState.setState(PlaybackState.STATE_PLAYING, position, 1); break; default: - pbState = PlaybackState.STATE_ERROR; - errorMsg = "unknown state"; + mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0); + mPlaybackState.setErrorMessage("unkown state"); break; } - PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState); - bob.setState(pbState, position, rate, SystemClock.elapsedRealtime()); - bob.setErrorMessage(errorMsg); - mPlaybackState = bob.build(); mControls.sendPlaybackChangeEvent(mPlaybackState.getState()); } @@ -201,9 +195,8 @@ public class OneMediaRouteProvider extends RouteProviderService { @Override public void onFocusLost() { - Log.d(TAG, "Focus lost, pausing"); - // Don't update state here, we'll get a separate call to - // onStateChanged when it pauses + Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED); + mPlaybackState.setState(PlaybackState.STATE_PAUSED, mRenderer.getSeekPosition(), 0); mRenderer.onPause(); }