diff options
author | RoboErik <epastern@google.com> | 2014-02-24 18:02:08 -0800 |
---|---|---|
committer | RoboErik <epastern@google.com> | 2014-03-12 15:09:42 -0700 |
commit | 8ae0f34db936a649ddaf9cdd086c224f6514efeb (patch) | |
tree | 6699d2481e68c205dc62a35c1c434f05d721c03f /tests | |
parent | 1ebd4ad6cd645830d1eca12b2108c6ab4327c108 (diff) | |
download | frameworks_base-8ae0f34db936a649ddaf9cdd086c224f6514efeb.zip frameworks_base-8ae0f34db936a649ddaf9cdd086c224f6514efeb.tar.gz frameworks_base-8ae0f34db936a649ddaf9cdd086c224f6514efeb.tar.bz2 |
Adds a TransportController and TransportPerformer to session
This makes transport controls a primitive interface on sessions with
a way to create the performer, register callbacks, and send commands
and updates between controllers and performers. This still needs some
cleanup but has been tested with OneMedia.
Change-Id: I373d35f7ccc383b8421bd14044457467d80425f3
Diffstat (limited to 'tests')
6 files changed, 286 insertions, 50 deletions
diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java index 7ff81e4..3114ca9 100644 --- a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java +++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java @@ -1,7 +1,24 @@ +/* + * 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 com.android.onemedia; import android.app.Activity; +import android.media.session.MediaMetadata; +import android.media.session.PlaybackState; import android.os.Bundle; import android.util.Log; import android.view.Menu; @@ -79,10 +96,10 @@ public class OnePlayerActivity extends Activity { switch (v.getId()) { case R.id.play_button: Log.d(TAG, "Play button pressed, in state " + mPlaybackState); - if (mPlaybackState == Renderer.STATE_PAUSED - || mPlaybackState == Renderer.STATE_ENDED) { + if (mPlaybackState == PlaybackState.PLAYSTATE_PAUSED + || mPlaybackState == PlaybackState.PLAYSTATE_STOPPED) { mPlayer.play(); - } else if (mPlaybackState == Renderer.STATE_PLAYING) { + } else if (mPlaybackState == PlaybackState.PLAYSTATE_PLAYING) { mPlayer.pause(); } break; @@ -97,48 +114,55 @@ public class OnePlayerActivity extends Activity { private PlayerController.Listener mListener = new PlayerController.Listener() { @Override - public void onSessionStateChange(int state) { - mPlaybackState = state; + public void onPlaybackStateChange(PlaybackState state) { + mPlaybackState = state.getState(); boolean enablePlay = false; + StringBuilder statusBuilder = new StringBuilder(); switch (mPlaybackState) { - case Renderer.STATE_PLAYING: - mStatusView.setText("playing"); + case PlaybackState.PLAYSTATE_PLAYING: + statusBuilder.append("playing"); mPlayButton.setText("Pause"); enablePlay = true; break; - case Renderer.STATE_PAUSED: - mStatusView.setText("paused"); + case PlaybackState.PLAYSTATE_PAUSED: + statusBuilder.append("paused"); mPlayButton.setText("Play"); enablePlay = true; break; - case Renderer.STATE_ENDED: - mStatusView.setText("ended"); + case PlaybackState.PLAYSTATE_STOPPED: + statusBuilder.append("ended"); mPlayButton.setText("Play"); enablePlay = true; break; - case Renderer.STATE_ERROR: - mStatusView.setText("error"); + case PlaybackState.PLAYSTATE_ERROR: + statusBuilder.append("error: ").append(state.getErrorMessage()); break; - case Renderer.STATE_PREPARING: - mStatusView.setText("preparing"); + case PlaybackState.PLAYSTATE_BUFFERING: + statusBuilder.append("buffering"); break; - case Renderer.STATE_READY: - mStatusView.setText("ready"); - break; - case Renderer.STATE_STOPPED: - mStatusView.setText("stopped"); + case PlaybackState.PLAYSTATE_NONE: + statusBuilder.append("none"); break; + default: + statusBuilder.append(mPlaybackState); } + statusBuilder.append(" -- At position: ").append(state.getPosition()); + mStatusView.setText(statusBuilder.toString()); mPlayButton.setEnabled(enablePlay); } @Override - public void onPlayerStateChange(int state) { + public void onConnectionStateChange(int state) { if (state == PlayerController.STATE_DISCONNECTED) { setControlsEnabled(false); } else if (state == PlayerController.STATE_CONNECTED) { setControlsEnabled(true); } } + + @Override + public void onMetadataChange(MediaMetadata metadata) { + Log.d(TAG, "Metadata update! Title: " + metadata); + } }; } diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java index 01610cd..573f7ff 100644 --- a/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java +++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java @@ -1,3 +1,18 @@ +/* + * 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 com.android.onemedia; import android.content.Context; @@ -5,9 +20,6 @@ import android.content.Intent; import java.util.ArrayList; -/** - * TODO: Insert description here. (generated by epastern) - */ public class OnePlayerService extends PlayerService { private static final String TAG = "OnePlayerService"; diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java index 3f15db5..e831ec6 100644 --- a/tests/OneMedia/src/com/android/onemedia/PlayerController.java +++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java @@ -1,8 +1,27 @@ +/* + * 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 com.android.onemedia; import android.media.session.MediaController; +import android.media.session.MediaMetadata; import android.media.session.MediaSessionManager; +import android.media.session.PlaybackState; +import android.media.session.TransportController; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; @@ -11,22 +30,23 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.util.Log; -import android.view.KeyEvent; import com.android.onemedia.playback.RequestUtils; public class PlayerController { - private static final String TAG = "PlayerSession"; + private static final String TAG = "PlayerController"; public static final int STATE_DISCONNECTED = 0; public static final int STATE_CONNECTED = 1; protected MediaController mController; protected IPlayerService mBinder; + protected TransportController mTransportControls; private final Intent mServiceIntent; private Context mContext; private Listener mListener; + private TransportListener mTransportListener = new TransportListener(); private SessionCallback mControllerCb; private MediaSessionManager mManager; private Handler mHandler = new Handler(); @@ -52,7 +72,7 @@ public class PlayerController { Log.d(TAG, "Listener set to " + listener + " session is " + mController); if (mListener != null) { mHandler = new Handler(); - mListener.onPlayerStateChange( + mListener.onConnectionStateChange( mController == null ? STATE_DISCONNECTED : STATE_CONNECTED); } } @@ -70,11 +90,15 @@ public class PlayerController { } public void play() { - mController.sendMediaButton(KeyEvent.KEYCODE_MEDIA_PLAY); + if (mTransportControls != null) { + mTransportControls.play(); + } } public void pause() { - mController.sendMediaButton(KeyEvent.KEYCODE_MEDIA_PAUSE); + if (mTransportControls != null) { + mTransportControls.pause(); + } } public void setContent(String source) { @@ -113,10 +137,11 @@ public class PlayerController { } mBinder = null; mController = null; + mTransportControls = null; Log.d(TAG, "Disconnected from PlayerService"); if (mListener != null) { - mListener.onPlayerStateChange(STATE_DISCONNECTED); + mListener.onConnectionStateChange(STATE_DISCONNECTED); } } @@ -125,33 +150,60 @@ public class PlayerController { mBinder = IPlayerService.Stub.asInterface(service); Log.d(TAG, "service is " + service + " binder is " + mBinder); try { - mController = new MediaController(mBinder.getSessionToken()); + mController = MediaController.fromToken(mBinder.getSessionToken()); } catch (RemoteException e) { Log.e(TAG, "Error getting session", e); return; } mController.addCallback(mControllerCb, mHandler); + mTransportControls = mController.getTransportController(); + if (mTransportControls != null) { + mTransportControls.addStateListener(mTransportListener); + } Log.d(TAG, "Ready to use PlayerService"); if (mListener != null) { - mListener.onPlayerStateChange(STATE_CONNECTED); + mListener.onConnectionStateChange(STATE_CONNECTED); + if (mTransportControls != null) { + mListener.onPlaybackStateChange(mTransportControls.getPlaybackState()); + } } } }; private class SessionCallback extends MediaController.Callback { @Override - public void onPlaybackStateChange(int state) { + public void onRouteChanged(Bundle route) { + // TODO + } + } + + private class TransportListener extends TransportController.TransportStateListener { + @Override + public void onPlaybackStateChanged(PlaybackState state) { + if (state == null) { + return; + } + Log.d(TAG, "Received playback state change to state " + state.getState()); if (mListener != null) { - mListener.onSessionStateChange(state); + mListener.onPlaybackStateChange(state); } } + + @Override + public void onMetadataChanged(MediaMetadata metadata) { + if (metadata == null) { + return; + } + Log.d(TAG, "Received metadata change, title is " + + metadata.getString(MediaMetadata.METADATA_KEY_TITLE)); + } } public interface Listener { - public void onSessionStateChange(int state); - - public void onPlayerStateChange(int state); + public void onPlaybackStateChange(PlaybackState state); + public void onMetadataChange(MediaMetadata metadata); + public void onConnectionStateChange(int state); } } diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerService.java b/tests/OneMedia/src/com/android/onemedia/PlayerService.java index 0b2ba8f..0ad6dd1 100644 --- a/tests/OneMedia/src/com/android/onemedia/PlayerService.java +++ b/tests/OneMedia/src/com/android/onemedia/PlayerService.java @@ -1,11 +1,28 @@ +/* + * 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 com.android.onemedia; import android.app.Service; import android.content.Intent; import android.media.session.MediaSessionToken; +import android.media.session.PlaybackState; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.util.Log; import com.android.onemedia.playback.IRequestCallback; import com.android.onemedia.playback.RequestUtils; @@ -18,14 +35,19 @@ public class PlayerService extends Service { private PlayerBinder mBinder; private PlayerSession mSession; private Intent mIntent; + private boolean mStarted = false; private ArrayList<IPlayerCallback> mCbs = new ArrayList<IPlayerCallback>(); @Override public void onCreate() { + Log.d(TAG, "onCreate"); mIntent = onCreateServiceIntent(); - mSession = onCreatePlayerController(); - mSession.createSession(); + if (mSession == null) { + mSession = onCreatePlayerController(); + mSession.createSession(); + mSession.setListener(mPlayerListener); + } } @Override @@ -38,12 +60,31 @@ public class PlayerService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(TAG, "onStartCommand"); return START_STICKY; } @Override public void onDestroy() { + Log.d(TAG, "onDestroy"); mSession.onDestroy(); + mSession = null; + } + + public void onPlaybackStarted() { + if (!mStarted) { + Log.d(TAG, "Starting self"); + startService(onCreateServiceIntent()); + mStarted = true; + } + } + + public void onPlaybackEnded() { + if (mStarted) { + Log.d(TAG, "Stopping self"); + stopSelf(); + mStarted = false; + } } protected Intent onCreateServiceIntent() { @@ -58,6 +99,21 @@ public class PlayerService extends Service { return null; } + private final PlayerSession.Listener mPlayerListener = new PlayerSession.Listener() { + @Override + public void onPlayStateChanged(PlaybackState state) { + switch (state.getState()) { + case PlaybackState.PLAYSTATE_PLAYING: + onPlaybackStarted(); + break; + case PlaybackState.PLAYSTATE_STOPPED: + case PlaybackState.PLAYSTATE_ERROR: + onPlaybackEnded(); + break; + } + } + }; + public class PlayerBinder extends IPlayerService.Stub { @Override public void sendRequest(String action, Bundle params, IRequestCallback cb) { @@ -94,7 +150,6 @@ public class PlayerService extends Service { @Override public MediaSessionToken getSessionToken() throws RemoteException { - // TODO(epastern): Auto-generated method stub return mSession.getSessionToken(); } } diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java index e5fb0d0..a2d7897 100644 --- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java +++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java @@ -1,3 +1,18 @@ +/* + * 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 com.android.onemedia; import android.content.Context; @@ -5,6 +20,8 @@ import android.content.Intent; import android.media.session.MediaSession; import android.media.session.MediaSessionManager; import android.media.session.MediaSessionToken; +import android.media.session.PlaybackState; +import android.media.session.TransportPerformer; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; @@ -14,14 +31,18 @@ import com.android.onemedia.playback.Renderer; import com.android.onemedia.playback.RendererFactory; public class PlayerSession { - private static final String TAG = "PlayerController"; + private static final String TAG = "PlayerSession"; protected MediaSession mSession; protected Context mContext; protected RendererFactory mRendererFactory; protected LocalRenderer mRenderer; - protected ControllerCb mCallback; - protected RenderListener mRenderListener; + protected MediaSession.Callback mCallback; + protected Renderer.Listener mRenderListener; + protected TransportPerformer mPerformer; + + protected PlaybackState mPlaybackState; + protected Listener mListener; public PlayerSession(Context context) { mContext = context; @@ -29,6 +50,9 @@ public class PlayerSession { mRenderer = new LocalRenderer(context, null); mCallback = new ControllerCb(); mRenderListener = new RenderListener(); + mPlaybackState = new PlaybackState(); + mPlaybackState.setActions(PlaybackState.ACTION_PAUSE + | PlaybackState.ACTION_PLAY); mRenderer.registerListener(mRenderListener); } @@ -42,6 +66,10 @@ public class PlayerSession { Log.d(TAG, "Creating session for package " + mContext.getBasePackageName()); mSession = man.createSession("OneMedia"); mSession.addCallback(mCallback); + mPerformer = mSession.setTransportPerformerEnabled(); + mPerformer.addListener(new TransportListener()); + mPerformer.setPlaybackState(mPlaybackState); + mSession.publish(); } public void onDestroy() { @@ -54,6 +82,10 @@ public class PlayerSession { } } + public void setListener(Listener listener) { + mListener = listener; + } + public MediaSessionToken getSessionToken() { return mSession.getSessionToken(); } @@ -66,16 +98,58 @@ public class PlayerSession { mRenderer.setNextContent(request); } - protected class RenderListener implements Renderer.Listener { + public interface Listener { + public void onPlayStateChanged(PlaybackState state); + } + + private class RenderListener implements Renderer.Listener { @Override public void onError(int type, int extra, Bundle extras, Throwable error) { - mSession.setPlaybackState(Renderer.STATE_ERROR); + Log.d(TAG, "Sending onError with type " + type + " and extra " + extra); + mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR); + if (error != null) { + mPlaybackState.setErrorMessage(error.getLocalizedMessage()); + } + mPerformer.setPlaybackState(mPlaybackState); + if (mListener != null) { + mListener.onPlayStateChanged(mPlaybackState); + } } @Override public void onStateChanged(int newState) { - mSession.setPlaybackState(newState); + if (newState != Renderer.STATE_ERROR) { + mPlaybackState.setErrorMessage(null); + } + switch (newState) { + case Renderer.STATE_ENDED: + case Renderer.STATE_STOPPED: + mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED); + break; + case Renderer.STATE_INIT: + case Renderer.STATE_PREPARING: + mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING); + break; + case Renderer.STATE_ERROR: + mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR); + break; + case Renderer.STATE_PAUSED: + mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED); + break; + case Renderer.STATE_PLAYING: + mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING); + break; + default: + mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR); + mPlaybackState.setErrorMessage("unkown state"); + break; + } + mPlaybackState.setPosition(mRenderer.getSeekPosition()); + mPerformer.setPlaybackState(mPlaybackState); + if (mListener != null) { + mListener.onPlayStateChanged(mPlaybackState); + } } @Override @@ -84,7 +158,13 @@ public class PlayerSession { @Override public void onFocusLost() { - mSession.setPlaybackState(Renderer.STATE_PAUSED); + Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED); + mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED); + mPlaybackState.setPosition(mRenderer.getSeekPosition()); + mPerformer.setPlaybackState(mPlaybackState); + if (mListener != null) { + mListener.onPlayStateChanged(mPlaybackState); + } } @Override @@ -93,7 +173,7 @@ public class PlayerSession { } - protected class ControllerCb extends MediaSession.Callback { + private class ControllerCb extends MediaSession.Callback { @Override public void onMediaButton(Intent mediaRequestIntent) { @@ -114,4 +194,16 @@ public class PlayerSession { } } + private class TransportListener extends TransportPerformer.Listener { + @Override + public void onPlay() { + mRenderer.onPlay(); + } + + @Override + public void onPause() { + mRenderer.onPause(); + } + } + } diff --git a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java index 7493366..7f62f66 100644 --- a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java +++ b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java @@ -499,11 +499,12 @@ public class LocalRenderer extends Renderer implements OnPreparedListener, @Override public boolean onPause() { MediaPlayer player = mPlayer; + // If the user paused us make sure we won't start playing again until + // asked to + mPlayOnReady = false; if (player != null && (mState & CAN_PAUSE) != 0) { player.pause(); setState(STATE_PAUSED); - } else if ((mState & CAN_READY_PLAY) != 0) { - mPlayOnReady = false; } else if (!isPaused()) { return false; } |