Merge "Update the MediaRouter support demo for new UIs" into lmp-mr1-dev

This commit is contained in:
RoboErik
2014-11-24 23:04:29 +00:00
committed by Android (Google) Code Review
9 changed files with 179 additions and 141 deletions

View File

@@ -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">

View File

@@ -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>

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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");
}

View File

@@ -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);
}
}

View File

@@ -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(

View File

@@ -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 {
}

View File

@@ -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());
}
}
}
}