Update the MediaRouter support demo for new UIs
Updates the MediaRouter support demo for the new material UI spec.
bug:17879842
Change-Id: I3340e65384050fbf561cf506cb5b80028d69d849
diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml
index 703d657..1d087a4 100644
--- a/samples/Support7Demos/AndroidManifest.xml
+++ b/samples/Support7Demos/AndroidManifest.xml
@@ -86,6 +86,14 @@
</intent-filter>
</activity>
+ <activity android:name=".media.SampleMediaRouteSettingsActivity"
+ android:label="@string/sample_media_route_settings_activity"
+ android:theme="@style/Theme.AppCompat.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
<service android:name=".media.SampleMediaRouteProviderService"
android:label="@string/sample_media_route_provider_service"
android:process=":mrp">
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index 789e19e..4b3a28f 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -25,6 +25,7 @@
<string name="sample_media_router_text">This activity demonstrates how to
use MediaRouter from the support library. Select a route from the action bar.</string>
<string name="media_route_menu_title">Play on...</string>
+ <string name="sample_media_route_settings_activity">Sample route settings</string>
<string name="library_tab_text">Library</string>
<string name="playlist_tab_text">Playlist</string>
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
index 806df25..b3c14c2 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
@@ -28,6 +28,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
+import android.support.v4.media.session.MediaSessionCompat;
import android.support.v7.media.MediaRouter.RouteInfo;
import android.support.v7.media.MediaItemStatus;
import android.util.Log;
@@ -56,12 +57,6 @@
private static final String TAG = "LocalPlayer";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final int STATE_IDLE = 0;
- private static final int STATE_PLAY_PENDING = 1;
- private static final int STATE_READY = 2;
- private static final int STATE_PLAYING = 3;
- private static final int STATE_PAUSED = 4;
-
private final Context mContext;
private final Handler mHandler = new Handler();
private MediaPlayer mMediaPlayer;
@@ -109,6 +104,11 @@
}
}
+ @Override
+ public MediaSessionCompat getMediaSession() {
+ return mMediaSession;
+ }
+
// Player
@Override
public void play(final PlaylistItem item) {
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
index 32b1285..ae018ed 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
@@ -16,11 +16,14 @@
package com.example.android.supportv7.media;
-import android.net.Uri;
import android.content.Context;
import android.graphics.Bitmap;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
import android.support.v7.media.MediaControlIntent;
import android.support.v7.media.MediaRouter.RouteInfo;
+import android.util.Log;
/**
* Abstraction of common playback operations of media items, such as play,
@@ -28,7 +31,19 @@
* of media items.
*/
public abstract class Player {
+ private static final String TAG = "SampleMediaRoutePlayer";
+ protected static final int STATE_IDLE = 0;
+ protected static final int STATE_PLAY_PENDING = 1;
+ protected static final int STATE_READY = 2;
+ protected static final int STATE_PLAYING = 3;
+ protected static final int STATE_PAUSED = 4;
+
+ private static final long PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PAUSE
+ | PlaybackStateCompat.ACTION_PLAY;
+
protected Callback mCallback;
+ protected MediaSessionCompat mMediaSession;
+ protected MediaSessionCallback mSessionCallback;
public abstract boolean isRemotePlayback();
public abstract boolean isQueuingSupported();
@@ -71,10 +86,71 @@
} else {
player = new LocalPlayer.OverlayPlayer(context);
}
+ player.initMediaSession(context);
player.connect(route);
return player;
}
+ public MediaSessionCompat getMediaSession() {
+ return mMediaSession;
+ }
+
+ protected void updateMetadata() {
+ MediaMetadataCompat.Builder bob = new MediaMetadataCompat.Builder();
+ bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, getDescription());
+ bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Subtitle of the thing");
+ bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION,
+ "Description of the thing");
+ bob.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, getSnapshot());
+ mMediaSession.setMetadata(bob.build());
+ }
+
+ protected void publishState(int state) {
+ PlaybackStateCompat.Builder bob = new PlaybackStateCompat.Builder();
+ bob.setActions(PLAYBACK_ACTIONS);
+ switch (state) {
+ case STATE_PLAYING:
+ bob.setState(PlaybackStateCompat.STATE_PLAYING, -1, 1);
+ break;
+ case STATE_READY:
+ case STATE_PAUSED:
+ bob.setState(PlaybackStateCompat.STATE_PAUSED, -1, 0);
+ break;
+ case STATE_IDLE:
+ bob.setState(PlaybackStateCompat.STATE_STOPPED, -1, 0);
+ break;
+ }
+ PlaybackStateCompat pbState = bob.build();
+ Log.d(TAG, "Setting state to " + pbState);
+ mMediaSession.setPlaybackState(pbState);
+ if (state != STATE_IDLE) {
+ mMediaSession.setActive(true);
+ } else {
+ mMediaSession.setActive(false);
+ }
+ }
+
+ private void initMediaSession(Context context) {
+ mSessionCallback = new MediaSessionCallback();
+ mMediaSession = new MediaSessionCompat(context, "Support7Demos");
+ mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
+ | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
+ mMediaSession.setCallback(mSessionCallback);
+ updateMetadata();
+ }
+
+ private final class MediaSessionCallback extends MediaSessionCompat.Callback {
+ @Override
+ public void onPlay() {
+ resume();
+ }
+
+ @Override
+ public void onPause() {
+ pause();
+ }
+ }
+
public interface Callback {
void onError();
void onCompletion();
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
index 5020c37..d47c260 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
@@ -140,6 +140,9 @@
}
if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
pause();
+ publishState(STATE_PAUSED);
+ } else {
+ publishState(STATE_PLAYING);
}
if (mCallback != null) {
mCallback.onPlaylistChanged();
@@ -214,6 +217,7 @@
if (mCallback != null) {
mCallback.onPlaylistChanged();
}
+ publishState(STATE_PAUSED);
}
@Override
@@ -239,6 +243,7 @@
if (mCallback != null) {
mCallback.onPlaylistChanged();
}
+ publishState(STATE_PLAYING);
}
@Override
@@ -254,6 +259,7 @@
// ignore if no session
return;
}
+ publishState(STATE_IDLE);
if (DEBUG) {
Log.d(TAG, "stop");
}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java
deleted file mode 100644
index a2cacc3..0000000
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2013 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.example.android.supportv7.media;
-
-import com.example.android.supportv7.R;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.os.Bundle;
-import android.support.v7.app.MediaRouteControllerDialog;
-import android.support.v7.media.MediaRouteSelector;
-import android.support.v7.media.MediaRouter;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-/**
- * This class serves as an example on how to customize the media router control
- * dialog. It is derived from the standard MediaRouteControllerDialog with the
- * following overrides:
- *
- * 1. Shows thumbnail/snapshot of the current item
- *
- * 2. For variable volume routes, only allow volume control via Volume Up/Down
- * keys (to prevent accidental tapping on the volume adjust seekbar that sets
- * volume to maximum)
- *
- * 3. Provides transport control buttons (play/pause, stop)
- */
-public class SampleMediaRouteControllerDialog extends MediaRouteControllerDialog {
- private static final String TAG = "SampleMediaRouteControllerDialog";
- private final SampleMediaRouterActivity mActivity;
- private final SessionManager mSessionManager;
- private final Player mPlayer;
- private ImageButton mPauseResumeButton;
- private ImageButton mStopButton;
- private ImageView mThumbnail;
- private TextView mTextView;
- private LinearLayout mInfoLayout;
- private LinearLayout mVolumeLayout;
-
- public SampleMediaRouteControllerDialog(Context context,
- SessionManager manager, Player player) {
- super(context);
- mActivity = (SampleMediaRouterActivity) context;
- mSessionManager = manager;
- mPlayer = player;
- }
-
- @Override
- public View onCreateMediaControlView(Bundle savedInstanceState) {
- // Thumbnail and Track info
- View v = getLayoutInflater().inflate(R.layout.sample_media_controller, null);
- mInfoLayout = (LinearLayout)v.findViewById(R.id.media_route_info);
- mTextView = (TextView)v.findViewById(R.id.track_info);
- mThumbnail = (ImageView)v.findViewById(R.id.snapshot);
-
- // Transport controls
- mPauseResumeButton = (ImageButton)v.findViewById(R.id.pause_resume_button);
- mPauseResumeButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mActivity != null) {
- mActivity.handleMediaKey(new KeyEvent(KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
- }
- }
- });
-
- mStopButton = (ImageButton)v.findViewById(R.id.stop_button);
- mStopButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mActivity != null) {
- mActivity.handleMediaKey(new KeyEvent(KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_MEDIA_STOP));
- }
- }
- });
-
- // update session status (will callback to updateUi at the end)
- mSessionManager.updateStatus();
- return v;
- }
-
- public void updateUi() {
- String trackInfo = mPlayer.getDescription();
- Bitmap snapshot = mPlayer.getSnapshot();
- if (mPlayer.isRemotePlayback() && !trackInfo.isEmpty() && snapshot != null) {
- mInfoLayout.setVisibility(View.VISIBLE);
- mThumbnail.setImageBitmap(snapshot);
- mTextView.setText(trackInfo);
- } else {
- mInfoLayout.setVisibility(View.GONE);
- }
- // show pause or resume icon depending on current state
- mPauseResumeButton.setImageResource(mSessionManager.isPaused() ?
- R.drawable.ic_media_play : R.drawable.ic_media_pause);
- }
-}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
index 8a20564..2e26630 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
+import android.content.IntentSender;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.media.AudioManager;
@@ -173,6 +174,10 @@
private void publishRoutes() {
Resources r = getContext().getResources();
+ Intent settingsIntent = new Intent(Intent.ACTION_MAIN);
+ settingsIntent.setClass(getContext(), SampleMediaRouteSettingsActivity.class);
+ IntentSender is = PendingIntent.getActivity(getContext(), 99, settingsIntent,
+ Intent.FLAG_ACTIVITY_NEW_TASK).getIntentSender();
MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder(
FIXED_VOLUME_ROUTE_ID,
@@ -183,6 +188,8 @@
.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
.setVolume(VOLUME_MAX)
+ .setCanDisconnect(true)
+ .setSettingsActivity(is)
.build();
MediaRouteDescriptor routeDescriptor2 = new MediaRouteDescriptor.Builder(
@@ -195,6 +202,7 @@
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(VOLUME_MAX)
.setVolume(mVolume)
+ .setSettingsActivity(is)
.build();
MediaRouteDescriptor routeDescriptor3 = new MediaRouteDescriptor.Builder(
@@ -207,6 +215,7 @@
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(VOLUME_MAX)
.setVolume(mVolume)
+ .setCanDisconnect(true)
.build();
MediaRouteDescriptor routeDescriptor4 = new MediaRouteDescriptor.Builder(
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java
new file mode 100644
index 0000000..a1d07fb
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java
@@ -0,0 +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.example.android.supportv7.media;
+
+import android.support.v7.app.ActionBarActivity;
+
+/**
+ * This activity is a dummy settings activity for the
+ * {@link SampleMediaRouteProvider}.
+ */
+public class SampleMediaRouteSettingsActivity extends ActionBarActivity {
+
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
index dfa1416..164831f 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.app.PendingIntent;
@@ -37,6 +38,7 @@
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.MediaRouteActionProvider;
+import android.support.v7.app.MediaRouteButton;
import android.support.v7.app.MediaRouteControllerDialog;
import android.support.v7.app.MediaRouteControllerDialogFragment;
import android.support.v7.app.MediaRouteDiscoveryFragment;
@@ -66,6 +68,7 @@
import android.widget.TabHost.OnTabChangeListener;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
+
import java.io.File;
/**
@@ -93,7 +96,6 @@
private SeekBar mSeekBar;
private boolean mNeedResume;
private boolean mSeeking;
- private SampleMediaRouteControllerDialog mControllerDialog;
private final Handler mHandler = new Handler();
private final Runnable mUpdateSeekRunnable = new Runnable() {
@@ -152,7 +154,6 @@
}
mPlayer.updatePresentation();
mPlayer.release();
- mControllerDialog = null;
}
@Override
@@ -372,6 +373,8 @@
// Set up playback manager and player
mPlayer = Player.create(SampleMediaRouterActivity.this,
mMediaRouter.getSelectedRoute());
+ mMediaRouter.setMediaSessionCompat(mPlayer.getMediaSession());
+
mSessionManager.setPlayer(mPlayer);
mSessionManager.setCallback(new SessionManager.Callback() {
@Override
@@ -520,15 +523,7 @@
mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() {
@Override
public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
- return new MediaRouteControllerDialogFragment() {
- @Override
- public MediaRouteControllerDialog onCreateControllerDialog(
- Context context, Bundle savedInstanceState) {
- mControllerDialog = new SampleMediaRouteControllerDialog(
- context, mSessionManager, mPlayer);
- return mControllerDialog;
- }
- };
+ return new ControllerDialogFragment(mPlayer);
}
});
@@ -564,8 +559,8 @@
updatePlaylist();
updateRouteDescription();
updateButtons();
- if (mControllerDialog != null) {
- mControllerDialog.updateUi();
+ if (mPlayer != null) {
+ mPlayer.updateMetadata();
}
}
@@ -745,4 +740,41 @@
*/
public static class LightWithDarkActionBar extends SampleMediaRouterActivity {
}
+
+ public static class ControllerDialogFragment extends MediaRouteControllerDialogFragment {
+ private MediaRouteControllerDialog mControllerDialog;
+ private Player mPlayer;
+
+ public ControllerDialogFragment() {
+ super();
+ }
+
+ public ControllerDialogFragment(Player player) {
+ mPlayer = player;
+ }
+
+ @Override
+ public MediaRouteControllerDialog onCreateControllerDialog(
+ Context context, Bundle savedInstanceState) {
+ mControllerDialog = super.onCreateControllerDialog(context,
+ savedInstanceState);
+ if (mPlayer != null) {
+ mControllerDialog.setMediaSession(mPlayer.getMediaSession().getSessionToken());
+ }
+ mControllerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ mControllerDialog = null;
+ }
+ });
+ return mControllerDialog;
+ }
+
+ public void setPlayer(Player player) {
+ mPlayer = player;
+ if (mControllerDialog != null) {
+ mControllerDialog.setMediaSession(mPlayer.getMediaSession().getSessionToken());
+ }
+ }
+ }
}