Commit 620b29a5 authored by Chong Zhang's avatar Chong Zhang
Browse files

media router sample: handle remote volume change

Change-Id: Ie31c24d80b0ae74d68e3ff6f6098d4f0219c391d
(cherry picked from commit 49176917)
parent bc516abe
...@@ -48,7 +48,11 @@ ...@@ -48,7 +48,11 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<receiver android:name="com.example.android.supportv7.media.SampleMediaButtonReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<!-- MediaRouter Support Samples --> <!-- MediaRouter Support Samples -->
<activity android:name=".media.SampleMediaRouterActivity" <activity android:name=".media.SampleMediaRouterActivity"
......
/*
* 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.content.Context;
import android.content.Intent;
import android.content.BroadcastReceiver;
import android.util.Log;
import android.view.KeyEvent;
/**
* Broadcast receiver for handling ACTION_MEDIA_BUTTON.
*
* This is needed to create the RemoteControlClient for controlling
* remote route volume in lock screen. It routes media key events back
* to main app activity SampleMediaRouterActivity.
*/
public class SampleMediaButtonReceiver extends BroadcastReceiver {
private static final String TAG = "SampleMediaButtonReceiver";
private static SampleMediaRouterActivity mActivity;
public static void setActivity(SampleMediaRouterActivity activity) {
mActivity = activity;
}
@Override
public void onReceive(Context context, Intent intent) {
if (mActivity != null && Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
mActivity.handleMediaKey(
(KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
}
}
}
...@@ -23,6 +23,7 @@ import android.content.Intent; ...@@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException; import android.content.IntentFilter.MalformedMimeTypeException;
import android.content.res.Resources; import android.content.res.Resources;
import android.media.AudioManager;
import android.media.MediaRouter; import android.media.MediaRouter;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
...@@ -161,6 +162,7 @@ final class SampleMediaRouteProvider extends MediaRouteProvider { ...@@ -161,6 +162,7 @@ final class SampleMediaRouteProvider extends MediaRouteProvider {
r.getString(R.string.fixed_volume_route_name)) r.getString(R.string.fixed_volume_route_name))
.setDescription(r.getString(R.string.sample_route_description)) .setDescription(r.getString(R.string.sample_route_description))
.addControlFilters(CONTROL_FILTERS) .addControlFilters(CONTROL_FILTERS)
.setPlaybackStream(AudioManager.STREAM_MUSIC)
.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED) .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
.setVolume(VOLUME_MAX) .setVolume(VOLUME_MAX)
...@@ -171,6 +173,7 @@ final class SampleMediaRouteProvider extends MediaRouteProvider { ...@@ -171,6 +173,7 @@ final class SampleMediaRouteProvider extends MediaRouteProvider {
r.getString(R.string.variable_volume_route_name)) r.getString(R.string.variable_volume_route_name))
.setDescription(r.getString(R.string.sample_route_description)) .setDescription(r.getString(R.string.sample_route_description))
.addControlFilters(CONTROL_FILTERS) .addControlFilters(CONTROL_FILTERS)
.setPlaybackStream(AudioManager.STREAM_MUSIC)
.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(VOLUME_MAX) .setVolumeMax(VOLUME_MAX)
...@@ -287,6 +290,9 @@ final class SampleMediaRouteProvider extends MediaRouteProvider { ...@@ -287,6 +290,9 @@ final class SampleMediaRouteProvider extends MediaRouteProvider {
if (volume >= 0 && volume <= VOLUME_MAX) { if (volume >= 0 && volume <= VOLUME_MAX) {
mVolume = volume; mVolume = volume;
Log.d(TAG, mRouteId + ": New volume is " + mVolume); Log.d(TAG, mRouteId + ": New volume is " + mVolume);
AudioManager audioManager =
(AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
publishRoutes(); publishRoutes();
} }
} }
......
...@@ -18,6 +18,7 @@ package com.example.android.supportv7.media; ...@@ -18,6 +18,7 @@ package com.example.android.supportv7.media;
import com.example.android.supportv7.R; import com.example.android.supportv7.R;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
...@@ -26,7 +27,13 @@ import android.content.res.Resources; ...@@ -26,7 +27,13 @@ import android.content.res.Resources;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Presentation; import android.app.Presentation;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.media.MediaMetadataRetriever;
import android.media.RemoteControlClient;
import android.media.RemoteControlClient.MetadataEditor;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.Bundle; import android.os.Bundle;
import android.os.SystemClock; import android.os.SystemClock;
...@@ -44,6 +51,7 @@ import android.support.v7.media.MediaRouteSelector; ...@@ -44,6 +51,7 @@ import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaItemStatus; import android.support.v7.media.MediaItemStatus;
import android.util.Log; import android.util.Log;
import android.view.Gravity; import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
...@@ -193,11 +201,17 @@ public class SampleMediaRouterActivity extends ActionBarActivity { ...@@ -193,11 +201,17 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
} }
playerCB = mRemotePlayer; playerCB = mRemotePlayer;
mRemotePlayer.reset(); mRemotePlayer.reset();
// Create and register the remote control client
registerRCC();
} else { } else {
// Local Playback: // Local Playback:
// Use local player and feed media player one item at a time // Use local player and feed media player one item at a time
player = mLocalPlayer; player = mLocalPlayer;
playerCB = mMediaPlayer; playerCB = mMediaPlayer;
// Unregister the remote control client
unregisterRCC();
} }
if (player != mPlayer || playerCB != mPlayerCB) { if (player != mPlayer || playerCB != mPlayerCB) {
...@@ -301,6 +315,24 @@ public class SampleMediaRouterActivity extends ActionBarActivity { ...@@ -301,6 +315,24 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
} }
}; };
private RemoteControlClient mRemoteControlClient;
private ComponentName mEventReceiver;
private AudioManager mAudioManager;
private PendingIntent mMediaPendingIntent;
private final OnAudioFocusChangeListener mAfChangeListener =
new OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
Log.d(TAG, "onAudioFocusChange: LOSS_TRANSIENT");
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
Log.d(TAG, "onAudioFocusChange: AUDIOFOCUS_GAIN");
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
Log.d(TAG, "onAudioFocusChange: AUDIOFOCUS_LOSS");
}
}
};
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
// Be sure to call the super class. // Be sure to call the super class.
...@@ -471,6 +503,97 @@ public class SampleMediaRouterActivity extends ActionBarActivity { ...@@ -471,6 +503,97 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(SampleMediaRouterActivity.ACTION_STATUS_CHANGE); filter.addAction(SampleMediaRouterActivity.ACTION_STATUS_CHANGE);
registerReceiver(mReceiver, filter); registerReceiver(mReceiver, filter);
// Build the PendingIntent for the remote control client
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mEventReceiver = new ComponentName(getPackageName(),
SampleMediaButtonReceiver.class.getName());
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setComponent(mEventReceiver);
mMediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
}
private void registerRCC() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// Create the RCC and register with AudioManager and MediaRouter
mAudioManager.requestAudioFocus(mAfChangeListener,
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
mAudioManager.registerMediaButtonEventReceiver(mEventReceiver);
mRemoteControlClient = new RemoteControlClient(mMediaPendingIntent);
mAudioManager.registerRemoteControlClient(mRemoteControlClient);
mMediaRouter.addRemoteControlClient(mRemoteControlClient);
SampleMediaButtonReceiver.setActivity(SampleMediaRouterActivity.this);
mRemoteControlClient.setTransportControlFlags(
RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE);
mRemoteControlClient.setPlaybackState(
RemoteControlClient.PLAYSTATE_PLAYING);
}
}
private void unregisterRCC() {
// Unregister the RCC with AudioManager and MediaRouter
if (mRemoteControlClient != null) {
mRemoteControlClient.setTransportControlFlags(0);
mAudioManager.abandonAudioFocus(mAfChangeListener);
mAudioManager.unregisterMediaButtonEventReceiver(mEventReceiver);
mAudioManager.unregisterRemoteControlClient(mRemoteControlClient);
mMediaRouter.removeRemoteControlClient(mRemoteControlClient);
SampleMediaButtonReceiver.setActivity(null);
mRemoteControlClient = null;
}
}
public boolean handleMediaKey(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
{
Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
if (!mPaused) {
mPlayer.pause();
} else {
mPlayer.resume();
}
return true;
}
case KeyEvent.KEYCODE_MEDIA_PLAY:
{
Log.d(TAG, "Received Play event from RemoteControlClient");
if (mPaused) {
mPlayer.resume();
}
return true;
}
case KeyEvent.KEYCODE_MEDIA_PAUSE:
{
Log.d(TAG, "Received Pause event from RemoteControlClient");
if (!mPaused) {
mPlayer.pause();
}
return true;
}
case KeyEvent.KEYCODE_MEDIA_STOP:
{
Log.d(TAG, "Received Stop event from RemoteControlClient");
mPlayer.stop();
clearContent();
return true;
}
default:
break;
}
}
return false;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return handleMediaKey(event) || super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
return handleMediaKey(event) || super.onKeyUp(keyCode, event);
} }
@Override @Override
...@@ -549,6 +672,10 @@ public class SampleMediaRouterActivity extends ActionBarActivity { ...@@ -549,6 +672,10 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
// only enable seek bar when duration is known // only enable seek bar when duration is known
MediaQueueItem item = getCheckedMediaQueueItem(); MediaQueueItem item = getCheckedMediaQueueItem();
mSeekBar.setEnabled(item != null && item.getContentDuration() > 0); mSeekBar.setEnabled(item != null && item.getContentDuration() > 0);
if (mRemoteControlClient != null) {
mRemoteControlClient.setPlaybackState(mPaused ?
RemoteControlClient.PLAYSTATE_PAUSED : RemoteControlClient.PLAYSTATE_PLAYING);
}
} }
private void updateProgress(MediaQueueItem queueItem) { private void updateProgress(MediaQueueItem queueItem) {
...@@ -684,6 +811,13 @@ public class SampleMediaRouterActivity extends ActionBarActivity { ...@@ -684,6 +811,13 @@ public class SampleMediaRouterActivity extends ActionBarActivity {
Log.d(TAG, "LocalPlayer: enqueue, uri=" + uri + ", pos=" + pos); Log.d(TAG, "LocalPlayer: enqueue, uri=" + uri + ", pos=" + pos);
MediaQueueItem playlistItem = mSessionManager.enqueue(mSessionId, uri, null); MediaQueueItem playlistItem = mSessionManager.enqueue(mSessionId, uri, null);
mSessionId = playlistItem.getSessionId(); mSessionId = playlistItem.getSessionId();
// Set remote control client title
if (mPlayListItems.getCount() == 0 && mRemoteControlClient != null) {
RemoteControlClient.MetadataEditor ed = mRemoteControlClient.editMetadata(true);
ed.putString(MediaMetadataRetriever.METADATA_KEY_TITLE,
playlistItem.toString());
ed.apply();
}
mPlayListItems.add(playlistItem); mPlayListItems.add(playlistItem);
if (pos > 0) { if (pos > 0) {
// Seek to initial position if needed // Seek to initial position if needed
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment