From c00f64fbb98fe49ec1e3393e3335b55719aa2594 Mon Sep 17 00:00:00 2001 From: RoboErik Date: Tue, 11 Nov 2014 16:31:22 -0800 Subject: [PATCH] Update the MediaRouter support demo for new UIs Updates the MediaRouter support demo for the new material UI spec. bug:17879842 Change-Id: I3340e65384050fbf561cf506cb5b80028d69d849 --- samples/Support7Demos/AndroidManifest.xml | 8 ++ samples/Support7Demos/res/values/strings.xml | 1 + .../android/supportv7/media/LocalPlayer.java | 12 +- .../android/supportv7/media/Player.java | 78 ++++++++++- .../android/supportv7/media/RemotePlayer.java | 6 + .../SampleMediaRouteControllerDialog.java | 121 ------------------ .../media/SampleMediaRouteProvider.java | 9 ++ .../SampleMediaRouteSettingsActivity.java | 27 ++++ .../media/SampleMediaRouterActivity.java | 58 +++++++-- 9 files changed, 179 insertions(+), 141 deletions(-) delete mode 100644 samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java create mode 100644 samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml index 703d657d2..1d087a470 100644 --- a/samples/Support7Demos/AndroidManifest.xml +++ b/samples/Support7Demos/AndroidManifest.xml @@ -86,6 +86,14 @@ + + + + + + diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml index 789e19ef8..4b3a28fd7 100644 --- a/samples/Support7Demos/res/values/strings.xml +++ b/samples/Support7Demos/res/values/strings.xml @@ -25,6 +25,7 @@ This activity demonstrates how to use MediaRouter from the support library. Select a route from the action bar. Play on... + Sample route settings Library Playlist 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 806df257d..b3c14c26b 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.Build; 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 @@ public abstract class LocalPlayer extends Player implements 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 @@ public abstract class LocalPlayer extends Player implements } } + @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 32b128588..ae018ed41 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 @@ import android.support.v7.media.MediaRouter.RouteInfo; * 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 @@ public abstract class Player { } 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 5020c371b..d47c26069 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 @@ public class RemotePlayer extends Player { } if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) { pause(); + publishState(STATE_PAUSED); + } else { + publishState(STATE_PLAYING); } if (mCallback != null) { mCallback.onPlaylistChanged(); @@ -214,6 +217,7 @@ public class RemotePlayer extends Player { if (mCallback != null) { mCallback.onPlaylistChanged(); } + publishState(STATE_PAUSED); } @Override @@ -239,6 +243,7 @@ public class RemotePlayer extends Player { if (mCallback != null) { mCallback.onPlaylistChanged(); } + publishState(STATE_PLAYING); } @Override @@ -254,6 +259,7 @@ public class RemotePlayer extends Player { // 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 a2cacc3f0..000000000 --- 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 8a205649f..2e26630dc 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.Context; 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 @@ final class SampleMediaRouteProvider extends MediaRouteProvider { 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 @@ final class SampleMediaRouteProvider extends MediaRouteProvider { .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 @@ final class SampleMediaRouteProvider extends MediaRouteProvider { .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) .setVolumeMax(VOLUME_MAX) .setVolume(mVolume) + .setSettingsActivity(is) .build(); MediaRouteDescriptor routeDescriptor3 = new MediaRouteDescriptor.Builder( @@ -207,6 +215,7 @@ final class SampleMediaRouteProvider extends MediaRouteProvider { .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 000000000..a1d07fb56 --- /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 dfa14163c..164831ffd 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 com.example.android.supportv7.R; 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.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.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.TabSpec; import android.widget.TabHost.OnTabChangeListener; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; + import java.io.File; /** @@ -93,7 +96,6 @@ public class SampleMediaRouterActivity extends ActionBarActivity { 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 @@ public class SampleMediaRouterActivity extends ActionBarActivity { } mPlayer.updatePresentation(); mPlayer.release(); - mControllerDialog = null; } @Override @@ -372,6 +373,8 @@ public class SampleMediaRouterActivity extends ActionBarActivity { // 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 @@ public class SampleMediaRouterActivity extends ActionBarActivity { 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 @@ public class SampleMediaRouterActivity extends ActionBarActivity { updatePlaylist(); updateRouteDescription(); updateButtons(); - if (mControllerDialog != null) { - mControllerDialog.updateUi(); + if (mPlayer != null) { + mPlayer.updateMetadata(); } } @@ -745,4 +740,41 @@ public class SampleMediaRouterActivity extends ActionBarActivity { */ 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()); + } + } + } }