();
private RemotePlaybackClient mClient;
@@ -318,11 +320,12 @@ public class RemotePlayer extends Player {
}
@Override
- public void updateStatistics() {
+ public void updateTrackInfo() {
// clear stats info first
- mStatsInfo = "";
+ mTrackInfo = "";
+ mSnapshot = null;
- Intent intent = new Intent(SampleMediaRouteProvider.ACTION_GET_STATISTICS);
+ Intent intent = new Intent(SampleMediaRouteProvider.ACTION_GET_TRACK_INFO);
intent.addCategory(SampleMediaRouteProvider.CATEGORY_SAMPLE_ROUTE);
if (mRoute != null && mRoute.supportsControlRequest(intent)) {
@@ -333,9 +336,9 @@ public class RemotePlayer extends Player {
Log.d(TAG, "getStatistics: succeeded: data=" + data);
}
if (data != null) {
- int playbackCount = data.getInt(
- SampleMediaRouteProvider.DATA_PLAYBACK_COUNT, -1);
- mStatsInfo = "Total playback count: " + playbackCount;
+ mTrackInfo = data.getString(SampleMediaRouteProvider.TRACK_INFO_DESC);
+ mSnapshot = data.getParcelable(
+ SampleMediaRouteProvider.TRACK_INFO_SNAPSHOT);
}
}
@@ -350,8 +353,13 @@ public class RemotePlayer extends Player {
}
@Override
- public String getStatistics() {
- return mStatsInfo;
+ public String getDescription() {
+ return mTrackInfo;
+ }
+
+ @Override
+ public Bitmap getSnapshot() {
+ return mSnapshot;
}
private void enqueueInternal(final PlaylistItem item) {
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java
new file mode 100644
index 000000000..a2cacc3f0
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java
@@ -0,0 +1,121 @@
+/*
+ * 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 c1cc3c008..8a205649f 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.content.res.Resources;
+import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaRouter;
import android.net.Uri;
@@ -66,22 +67,27 @@ final class SampleMediaRouteProvider extends MediaRouteProvider {
/**
* A custom media control intent action for special requests that are
* supported by this provider's routes.
- *
- * This particular request is designed to return a bundle of not very
- * interesting statistics for demonstration purposes.
*
*
- * @see #DATA_PLAYBACK_COUNT
+ * @see #TRACK_INFO_DESC
+ * @see #TRACK_INFO_SNAPSHOT
*/
- public static final String ACTION_GET_STATISTICS =
- "com.example.android.supportv7.media.ACTION_GET_STATISTICS";
+ public static final String ACTION_GET_TRACK_INFO =
+ "com.example.android.supportv7.media.ACTION_GET_TRACK_INFO";
/**
- * {@link #ACTION_GET_STATISTICS} result data: Number of times the
- * playback action was invoked.
+ * {@link #ACTION_GET_TRACK_INFO} result data: a string of information about
+ * the currently playing media item
*/
- public static final String DATA_PLAYBACK_COUNT =
- "com.example.android.supportv7.media.EXTRA_PLAYBACK_COUNT";
+ public static final String TRACK_INFO_DESC =
+ "com.example.android.supportv7.media.EXTRA_TRACK_INFO_DESC";
+
+ /**
+ * {@link #ACTION_GET_TRACK_INFO} result data: a bitmap containing a snapshot
+ * of the currently playing media item
+ */
+ public static final String TRACK_INFO_SNAPSHOT =
+ "com.example.android.supportv7.media.EXTRA_TRACK_INFO_SNAPSHOT";
private static final ArrayList CONTROL_FILTERS_BASIC;
private static final ArrayList CONTROL_FILTERS_QUEUING;
@@ -90,7 +96,7 @@ final class SampleMediaRouteProvider extends MediaRouteProvider {
static {
IntentFilter f1 = new IntentFilter();
f1.addCategory(CATEGORY_SAMPLE_ROUTE);
- f1.addAction(ACTION_GET_STATISTICS);
+ f1.addAction(ACTION_GET_TRACK_INFO);
IntentFilter f2 = new IntentFilter();
f2.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
@@ -245,6 +251,7 @@ final class SampleMediaRouteProvider extends MediaRouteProvider {
handleStatusChange(item);
}
});
+ setVolumeInternal(mVolume);
Log.d(TAG, mRouteId + ": Controller created");
}
@@ -315,10 +322,14 @@ final class SampleMediaRouteProvider extends MediaRouteProvider {
return success;
}
- if (action.equals(ACTION_GET_STATISTICS)
+ if (action.equals(ACTION_GET_TRACK_INFO)
&& intent.hasCategory(CATEGORY_SAMPLE_ROUTE)) {
Bundle data = new Bundle();
- data.putInt(DATA_PLAYBACK_COUNT, mEnqueueCount);
+ PlaylistItem item = mSessionManager.getCurrentItem();
+ if (item != null) {
+ data.putString(TRACK_INFO_DESC, item.toString());
+ data.putParcelable(TRACK_INFO_SNAPSHOT, mPlayer.getSnapshot());
+ }
if (callback != null) {
callback.onResult(data);
}
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 b1c8c9c49..dfa14163c 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
@@ -37,7 +37,10 @@ import android.support.v4.app.FragmentManager;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.MediaRouteActionProvider;
+import android.support.v7.app.MediaRouteControllerDialog;
+import android.support.v7.app.MediaRouteControllerDialogFragment;
import android.support.v7.app.MediaRouteDiscoveryFragment;
+import android.support.v7.app.MediaRouteDialogFactory;
import android.support.v7.media.MediaControlIntent;
import android.support.v7.media.MediaRouter;
import android.support.v7.media.MediaRouter.Callback;
@@ -88,9 +91,9 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
private ImageButton mPauseResumeButton;
private ImageButton mStopButton;
private SeekBar mSeekBar;
- private boolean mPaused;
private boolean mNeedResume;
private boolean mSeeking;
+ private SampleMediaRouteControllerDialog mControllerDialog;
private final Handler mHandler = new Handler();
private final Runnable mUpdateSeekRunnable = new Runnable() {
@@ -143,12 +146,13 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
PlaylistItem item = getCheckedPlaylistItem();
if (item != null) {
- long pos = item.getPosition() + (mPaused ?
+ long pos = item.getPosition() + (mSessionManager.isPaused() ?
0 : (SystemClock.elapsedRealtime() - item.getTimestamp()));
mSessionManager.suspend(pos);
}
mPlayer.updatePresentation();
mPlayer.release();
+ mControllerDialog = null;
}
@Override
@@ -271,7 +275,7 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
spec2.setIndicator(tabName);
spec2.setContent(R.id.tab2);
- tabName = getResources().getString(R.string.statistics_tab_text);
+ tabName = getResources().getString(R.string.info_tab_text);
TabSpec spec3=tabHost.newTabSpec(tabName);
spec3.setIndicator(tabName);
spec3.setContent(R.id.tab3);
@@ -312,11 +316,10 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
mPauseResumeButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- mPaused = !mPaused;
- if (mPaused) {
- mSessionManager.pause();
- } else {
+ if (mSessionManager.isPaused()) {
mSessionManager.resume();
+ } else {
+ mSessionManager.pause();
}
}
});
@@ -325,7 +328,6 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
mStopButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- mPaused = false;
mSessionManager.stop();
}
});
@@ -421,19 +423,17 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
{
Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
- mPaused = !mPaused;
- if (mPaused) {
- mSessionManager.pause();
- } else {
+ if (mSessionManager.isPaused()) {
mSessionManager.resume();
+ } else {
+ mSessionManager.pause();
}
return true;
}
case KeyEvent.KEYCODE_MEDIA_PLAY:
{
Log.d(TAG, "Received Play event from RemoteControlClient");
- if (mPaused) {
- mPaused = false;
+ if (mSessionManager.isPaused()) {
mSessionManager.resume();
}
return true;
@@ -441,8 +441,7 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
case KeyEvent.KEYCODE_MEDIA_PAUSE:
{
Log.d(TAG, "Received Pause event from RemoteControlClient");
- if (!mPaused) {
- mPaused = true;
+ if (!mSessionManager.isPaused()) {
mSessionManager.pause();
}
return true;
@@ -450,7 +449,6 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
case KeyEvent.KEYCODE_MEDIA_STOP:
{
Log.d(TAG, "Received Stop event from RemoteControlClient");
- mPaused = false;
mSessionManager.stop();
return true;
}
@@ -480,7 +478,7 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
@Override
public void onPause() {
// pause media player for local playback case only
- if (!mPlayer.isRemotePlayback() && !mPaused) {
+ if (!mPlayer.isRemotePlayback() && !mSessionManager.isPaused()) {
mNeedResume = true;
mSessionManager.pause();
}
@@ -502,7 +500,6 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
// Unregister the remote control client
unregisterRCC();
- mPaused = false;
mSessionManager.stop();
mPlayer.release();
super.onDestroy();
@@ -520,6 +517,20 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
MediaRouteActionProvider mediaRouteActionProvider =
(MediaRouteActionProvider)MenuItemCompat.getActionProvider(mediaRouteMenuItem);
mediaRouteActionProvider.setRouteSelector(mSelector);
+ 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 true to show the menu.
return true;
@@ -541,7 +552,7 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
}
} else {
long position = item.getPosition();
- long timeDelta = mPaused ? 0 :
+ long timeDelta = mSessionManager.isPaused() ? 0 :
(SystemClock.elapsedRealtime() - item.getTimestamp());
progress = (int)(100.0 * (position + timeDelta) / duration);
}
@@ -553,6 +564,9 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
updatePlaylist();
updateRouteDescription();
updateButtons();
+ if (mControllerDialog != null) {
+ mControllerDialog.updateUi();
+ }
}
private void updatePlaylist() {
@@ -563,29 +577,24 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
mPlayListView.invalidate();
}
-
private void updateRouteDescription() {
RouteInfo route = mMediaRouter.getSelectedRoute();
mInfoTextView.setText("Currently selected route:"
+ "\nName: " + route.getName()
+ "\nProvider: " + route.getProvider().getPackageName()
- + "\nDescription: " + route.getDescription()
- + "\nStatistics: " + mSessionManager.getStatistics());
+ + "\nDescription: " + route.getDescription());
}
private void updateButtons() {
MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute();
// show pause or resume icon depending on current state
- mPauseResumeButton.setImageResource(mPaused ?
+ mPauseResumeButton.setImageResource(mSessionManager.isPaused() ?
R.drawable.ic_media_play : R.drawable.ic_media_pause);
- // disable pause/resume/stop if no session
- mPauseResumeButton.setEnabled(mSessionManager.hasSession());
- mStopButton.setEnabled(mSessionManager.hasSession());
// only enable seek bar when duration is known
PlaylistItem item = getCheckedPlaylistItem();
mSeekBar.setEnabled(item != null && item.getDuration() > 0);
if (mRemoteControlClient != null) {
- mRemoteControlClient.setPlaybackState(mPaused ?
+ mRemoteControlClient.setPlaybackState(mSessionManager.isPaused() ?
RemoteControlClient.PLAYSTATE_PAUSED :
RemoteControlClient.PLAYSTATE_PLAYING);
}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
index 23f2a89c7..1c00192de 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
@@ -50,6 +50,10 @@ public class SessionManager implements Player.Callback {
mName = name;
}
+ public boolean isPaused() {
+ return hasSession() && mPaused;
+ }
+
public boolean hasSession() {
return mSessionValid;
}
@@ -62,12 +66,6 @@ public class SessionManager implements Player.Callback {
return mPlaylist.isEmpty() ? null : mPlaylist.get(0);
}
- // Get the cached statistic info from the player (will not update it)
- public String getStatistics() {
- checkPlayer();
- return mPlayer.getStatistics();
- }
-
// Returns the cached playlist (note this is not responsible for updating it)
public List getPlaylist() {
return mPlaylist;
@@ -81,7 +79,7 @@ public class SessionManager implements Player.Callback {
checkPlayer();
// update the statistics first, so that the stats string is valid when
// onPlaylistReady() gets called in the end
- mPlayer.updateStatistics();
+ mPlayer.updateTrackInfo();
if (mPlaylist.isEmpty()) {
// If queue is empty, don't forget to call onPlaylistReady()!
@@ -179,7 +177,10 @@ public class SessionManager implements Player.Callback {
if (DEBUG) {
log("pause");
}
- checkPlayerAndSession();
+ if (!mSessionValid) {
+ return;
+ }
+ checkPlayer();
mPaused = true;
updatePlaybackState();
}
@@ -188,7 +189,10 @@ public class SessionManager implements Player.Callback {
if (DEBUG) {
log("resume");
}
- checkPlayerAndSession();
+ if (!mSessionValid) {
+ return;
+ }
+ checkPlayer();
mPaused = false;
updatePlaybackState();
}
@@ -197,7 +201,10 @@ public class SessionManager implements Player.Callback {
if (DEBUG) {
log("stop");
}
- checkPlayerAndSession();
+ if (!mSessionValid) {
+ return;
+ }
+ checkPlayer();
mPlayer.stop();
mPlaylist.clear();
mPaused = false;