summaryrefslogtreecommitdiffstats
path: root/tests/OneMedia
diff options
context:
space:
mode:
authorBart Sears <bsears@google.com>2015-05-07 03:23:20 +0000
committerBart Sears <bsears@google.com>2015-05-07 03:23:20 +0000
commita8cc0584c60cbe7e880895353d95e9b9cc5c1b62 (patch)
tree0a85f88036631df12b74a349e711195d70b40687 /tests/OneMedia
parent2e5a2051de54e64612e1357d4534c7ec851aa508 (diff)
downloadframeworks_base-a8cc0584c60cbe7e880895353d95e9b9cc5c1b62.zip
frameworks_base-a8cc0584c60cbe7e880895353d95e9b9cc5c1b62.tar.gz
frameworks_base-a8cc0584c60cbe7e880895353d95e9b9cc5c1b62.tar.bz2
Revert "Remove incomplete media router API."
This CL has broken all builds on mnc-dev. Reverting until Jeff can take a look at it. This reverts commit 2e5a2051de54e64612e1357d4534c7ec851aa508. Change-Id: Ib9b3569bfebdc7bbfbcb7aee82733b93736c5bb5
Diffstat (limited to 'tests/OneMedia')
-rw-r--r--tests/OneMedia/Android.mk3
-rw-r--r--tests/OneMedia/AndroidManifest.xml9
-rw-r--r--tests/OneMedia/src/com/android/onemedia/PlayerSession.java83
-rw-r--r--tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java47
-rw-r--r--tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java270
5 files changed, 412 insertions, 0 deletions
diff --git a/tests/OneMedia/Android.mk b/tests/OneMedia/Android.mk
index 9fc6403..b7d7f98 100644
--- a/tests/OneMedia/Android.mk
+++ b/tests/OneMedia/Android.mk
@@ -9,6 +9,9 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) \
LOCAL_PACKAGE_NAME := OneMedia
LOCAL_CERTIFICATE := platform
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-media-protocols
+
LOCAL_JAVA_LIBRARIES += org.apache.http.legacy
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
index c6824ec..ef3fad5 100644
--- a/tests/OneMedia/AndroidManifest.xml
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -27,6 +27,15 @@
android:name="com.android.onemedia.OnePlayerService"
android:exported="true"
android:process="com.android.onemedia.service" />
+ <service
+ android:name=".provider.OneMediaRouteProvider"
+ android:permission="android.permission.BIND_MEDIA_ROUTE_SERVICE"
+ android:exported="true"
+ android:process="com.android.onemedia.provider">
+ <intent-filter>
+ <action android:name="android.media.routing.MediaRouteService" />
+ </intent-filter>
+ </service>
</application>
</manifest>
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 2455c9c..141a209 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -19,17 +19,25 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.MediaMetadata;
+import android.media.routing.MediaRouteSelector;
+import android.media.routing.MediaRouter;
+import android.media.routing.MediaRouter.ConnectionRequest;
+import android.media.routing.MediaRouter.DestinationInfo;
+import android.media.routing.MediaRouter.RouteInfo;
import android.media.session.MediaSession;
import android.media.session.MediaSession.QueueItem;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.Bundle;
+import android.support.media.protocols.MediaPlayerProtocol;
+import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.view.KeyEvent;
import com.android.onemedia.playback.LocalRenderer;
+import com.android.onemedia.playback.OneMRPRenderer;
import com.android.onemedia.playback.Renderer;
import com.android.onemedia.playback.RequestUtils;
@@ -40,6 +48,7 @@ public class PlayerSession {
private static final String TAG = "PlayerSession";
protected MediaSession mSession;
+ protected MediaRouter mRouter;
protected Context mContext;
protected Renderer mRenderer;
protected MediaSession.Callback mCallback;
@@ -75,11 +84,22 @@ public class PlayerSession {
.getSystemService(Context.MEDIA_SESSION_SERVICE);
Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
+ mRouter = new MediaRouter(mContext);
+ mRouter.addSelector(new MediaRouteSelector.Builder()
+ .addRequiredProtocol(MediaPlayerProtocol.class)
+ .build());
+ mRouter.addSelector(new MediaRouteSelector.Builder()
+ .setRequiredFeatures(MediaRouter.ROUTE_FEATURE_LIVE_AUDIO)
+ .setOptionalFeatures(MediaRouter.ROUTE_FEATURE_LIVE_VIDEO)
+ .build());
+ mRouter.setRoutingCallback(new RoutingCallback(), null);
+
mSession = new MediaSession(mContext, "OneMedia");
mSession.setCallback(mCallback);
mSession.setPlaybackState(mPlaybackState);
mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS
| MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
+ mSession.setMediaRouter(mRouter);
mSession.setActive(true);
updateMetadata();
}
@@ -97,6 +117,10 @@ public class PlayerSession {
mSession.release();
mSession = null;
}
+ if (mRouter != null) {
+ mRouter.release();
+ mRouter = null;
+ }
}
public void setListener(Listener listener) {
@@ -254,4 +278,63 @@ public class PlayerSession {
mRenderer.onPause();
}
}
+
+ private class RoutingCallback extends MediaRouter.RoutingCallback {
+ @Override
+ public void onConnectionStateChanged(int state) {
+ if (state == MediaRouter.CONNECTION_STATE_CONNECTING) {
+ if (mRenderer != null) {
+ mRenderer.onStop();
+ }
+ mRenderer = null;
+ updateState(PlaybackState.STATE_CONNECTING);
+ return;
+ }
+
+ MediaRouter.ConnectionInfo connection = mRouter.getConnection();
+ if (connection != null) {
+ MediaPlayerProtocol protocol =
+ connection.getProtocolObject(MediaPlayerProtocol.class);
+ if (protocol != null) {
+ Log.d(TAG, "Connected to route using media player protocol");
+
+ protocol.setCallback(new PlayerCallback(), null);
+ mRenderer = new OneMRPRenderer(protocol);
+ updateState(PlaybackState.STATE_NONE);
+ return;
+ }
+ }
+
+ // Use local route
+ mRenderer = new LocalRenderer(mContext, null);
+ mRenderer.registerListener(mRenderListener);
+ updateState(PlaybackState.STATE_NONE);
+ }
+ }
+
+ private class PlayerCallback extends MediaPlayerProtocol.Callback {
+ @Override
+ public void onStatusUpdated(MediaStatus status, Bundle extras) {
+ if (status != null) {
+ Log.d(TAG, "Received status update: " + status.toBundle());
+ switch (status.getPlayerState()) {
+ case MediaStatus.PLAYER_STATE_BUFFERING:
+ updateState(PlaybackState.STATE_BUFFERING);
+ break;
+ case MediaStatus.PLAYER_STATE_IDLE:
+ updateState(PlaybackState.STATE_STOPPED);
+ break;
+ case MediaStatus.PLAYER_STATE_PAUSED:
+ updateState(PlaybackState.STATE_PAUSED);
+ break;
+ case MediaStatus.PLAYER_STATE_PLAYING:
+ updateState(PlaybackState.STATE_PLAYING);
+ break;
+ case MediaStatus.PLAYER_STATE_UNKNOWN:
+ updateState(PlaybackState.STATE_NONE);
+ break;
+ }
+ }
+ }
+ }
}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java
new file mode 100644
index 0000000..55eb92c
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java
@@ -0,0 +1,47 @@
+package com.android.onemedia.playback;
+
+import android.os.Bundle;
+import android.support.media.protocols.MediaPlayerProtocol;
+import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
+
+/**
+ * Renderer for communicating with the OneMRP route
+ */
+public class OneMRPRenderer extends Renderer {
+ private final MediaPlayerProtocol mProtocol;
+
+ public OneMRPRenderer(MediaPlayerProtocol protocol) {
+ super(null, null);
+ mProtocol = protocol;
+ }
+
+ @Override
+ public void setContent(Bundle request) {
+ MediaInfo mediaInfo = new MediaInfo(request.getString(RequestUtils.EXTRA_KEY_SOURCE),
+ MediaInfo.STREAM_TYPE_BUFFERED, "audio/mp3");
+ mProtocol.load(mediaInfo, true, 0, null);
+ }
+
+ @Override
+ public boolean onStop() {
+ mProtocol.stop(null);
+ return true;
+ }
+
+ @Override
+ public boolean onPlay() {
+ mProtocol.play(null);
+ return true;
+ }
+
+ @Override
+ public boolean onPause() {
+ mProtocol.pause(null);
+ return true;
+ }
+
+ @Override
+ public long getSeekPosition() {
+ return -1;
+ }
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
new file mode 100644
index 0000000..5845e48
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
@@ -0,0 +1,270 @@
+/*
+ * 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.provider;
+
+import android.media.routing.MediaRouteSelector;
+import android.media.routing.MediaRouteService;
+import android.media.routing.MediaRouter.ConnectionInfo;
+import android.media.routing.MediaRouter.ConnectionRequest;
+import android.media.routing.MediaRouter.DestinationInfo;
+import android.media.routing.MediaRouter.DiscoveryRequest;
+import android.media.routing.MediaRouter.RouteInfo;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Process;
+import android.support.media.protocols.MediaPlayerProtocol;
+import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
+import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.onemedia.playback.LocalRenderer;
+import com.android.onemedia.playback.Renderer;
+import com.android.onemedia.playback.RequestUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Test of MediaRouteProvider. Show a dummy provider with a simple interface for
+ * playing music.
+ */
+public class OneMediaRouteProvider extends MediaRouteService {
+ private static final String TAG = "OneMRP";
+ private static final boolean DEBUG = true;
+
+ private static final String TEST_DESTINATION_ID = "testDestination";
+ private static final String TEST_ROUTE_ID = "testRoute";
+
+ private Renderer mRenderer;
+ private RenderListener mRenderListener;
+ private PlaybackState mPlaybackState;
+ private Handler mHandler;
+
+ private OneStub mStub;
+
+ @Override
+ public void onCreate() {
+ mHandler = new Handler();
+ 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();
+
+ mRenderer.registerListener(mRenderListener);
+ }
+
+ @Override
+ public ClientSession onCreateClientSession(ClientInfo client) {
+ if (client.getUid() != Process.myUid()) {
+ // for testing purposes, only allow connections from this application
+ // since this provider is not fully featured
+ return null;
+ }
+ return new OneSession(client);
+ }
+
+ private final class OneSession extends ClientSession {
+ private final ClientInfo mClient;
+
+ public OneSession(ClientInfo client) {
+ mClient = client;
+ }
+
+ @Override
+ public boolean onStartDiscovery(DiscoveryRequest req, DiscoveryCallback callback) {
+ for (MediaRouteSelector selector : req.getSelectors()) {
+ if (isMatch(selector)) {
+ DestinationInfo destination = new DestinationInfo.Builder(
+ TEST_DESTINATION_ID, getServiceMetadata(), "OneMedia")
+ .setDescription("Test route from OneMedia app.")
+ .build();
+ ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
+ routes.add(new RouteInfo.Builder(
+ TEST_ROUTE_ID, destination, selector).build());
+ callback.onDestinationFound(destination, routes);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onStopDiscovery() {
+ }
+
+ @Override
+ public boolean onConnect(ConnectionRequest req, ConnectionCallback callback) {
+ if (req.getRoute().getId().equals(TEST_ROUTE_ID)) {
+ mStub = new OneStub();
+ ConnectionInfo connection = new ConnectionInfo.Builder(req.getRoute())
+ .setProtocolStub(MediaPlayerProtocol.class, mStub)
+ .build();
+ callback.onConnected(connection);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onDisconnect() {
+ mStub = null;
+ }
+
+ private boolean isMatch(MediaRouteSelector selector) {
+ if (!selector.containsProtocol(MediaPlayerProtocol.class)) {
+ return false;
+ }
+ for (String protocol : selector.getRequiredProtocols()) {
+ if (!protocol.equals(MediaPlayerProtocol.class.getName())) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private final class OneStub extends MediaPlayerProtocol.Stub {
+ MediaInfo mMediaInfo;
+
+ public OneStub() {
+ super(mHandler);
+ }
+
+ @Override
+ public void onLoad(MediaInfo mediaInfo, boolean autoplay, long playPosition,
+ Bundle extras) {
+ if (DEBUG) {
+ Log.d(TAG, "Attempting to play " + mediaInfo.getContentId());
+ }
+ // look up the route and send a play command to it
+ mMediaInfo = mediaInfo;
+ Bundle bundle = new Bundle();
+ bundle.putString(RequestUtils.EXTRA_KEY_SOURCE, mediaInfo.getContentId());
+ mRenderer.setContent(bundle);
+ }
+
+ @Override
+ public void onPlay(Bundle extras) {
+ mRenderer.onPlay();
+ }
+
+ @Override
+ public void onPause(Bundle extras) {
+ mRenderer.onPause();
+ }
+ }
+
+ private class RenderListener implements Renderer.Listener {
+
+ @Override
+ public void onError(int type, int extra, Bundle extras, Throwable error) {
+ Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
+ sendStatusUpdate(PlaybackState.STATE_ERROR);
+ }
+
+ @Override
+ public void onStateChanged(int newState) {
+ 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;
+ break;
+ case Renderer.STATE_INIT:
+ case Renderer.STATE_PREPARING:
+ pbState = PlaybackState.STATE_BUFFERING;
+ break;
+ case Renderer.STATE_ERROR:
+ pbState = PlaybackState.STATE_ERROR;
+ break;
+ case Renderer.STATE_PAUSED:
+ pbState = PlaybackState.STATE_PAUSED;
+ break;
+ case Renderer.STATE_PLAYING:
+ pbState = PlaybackState.STATE_PLAYING;
+ rate = 1;
+ break;
+ default:
+ pbState = PlaybackState.STATE_ERROR;
+ errorMsg = "unknown state";
+ break;
+ }
+ PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+ bob.setState(pbState, position, rate, SystemClock.elapsedRealtime());
+ bob.setErrorMessage(errorMsg);
+ mPlaybackState = bob.build();
+
+ sendStatusUpdate(mPlaybackState.getState());
+ }
+
+ @Override
+ public void onBufferingUpdate(int percent) {
+ }
+
+ @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
+ mRenderer.onPause();
+ }
+
+ @Override
+ public void onNextStarted() {
+ }
+
+ private void sendStatusUpdate(int state) {
+ if (mStub != null) {
+ MediaStatus status = new MediaStatus(1, mStub.mMediaInfo);
+ switch (state) {
+ case PlaybackState.STATE_BUFFERING:
+ case PlaybackState.STATE_FAST_FORWARDING:
+ case PlaybackState.STATE_REWINDING:
+ case PlaybackState.STATE_SKIPPING_TO_NEXT:
+ case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
+ status.setPlayerState(MediaStatus.PLAYER_STATE_BUFFERING);
+ break;
+ case PlaybackState.STATE_CONNECTING:
+ case PlaybackState.STATE_STOPPED:
+ status.setPlayerState(MediaStatus.PLAYER_STATE_IDLE);
+ break;
+ case PlaybackState.STATE_PAUSED:
+ status.setPlayerState(MediaStatus.PLAYER_STATE_PAUSED);
+ break;
+ case PlaybackState.STATE_PLAYING:
+ status.setPlayerState(MediaStatus.PLAYER_STATE_PLAYING);
+ break;
+ case PlaybackState.STATE_NONE:
+ case PlaybackState.STATE_ERROR:
+ default:
+ status.setPlayerState(MediaStatus.PLAYER_STATE_UNKNOWN);
+ break;
+ }
+ mStub.sendStatusUpdatedEvent(status, null);
+ }
+ }
+ }
+}