Loading api/current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -11538,6 +11538,7 @@ package android.media { method public abstract void onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo); method public abstract void onRouteUngrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup); method public abstract void onRouteUnselected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo); method public abstract void onRouteVolumeChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo); } public static class MediaRouter.RouteCategory { Loading Loading @@ -11573,6 +11574,8 @@ package android.media { method public int getVolume(); method public int getVolumeHandling(); method public int getVolumeMax(); method public void requestSetVolume(int); method public void requestUpdateVolume(int); method public void setTag(java.lang.Object); field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0 field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1 Loading @@ -11589,6 +11592,7 @@ package android.media { method public void onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo); method public void onRouteUngrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup); method public void onRouteUnselected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo); method public void onRouteVolumeChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo); } public static class MediaRouter.UserRouteInfo extends android.media.MediaRouter.RouteInfo { core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java +42 −43 Original line number Diff line number Diff line Loading @@ -30,8 +30,6 @@ import android.media.MediaRouter; import android.media.MediaRouter.RouteCategory; import android.media.MediaRouter.RouteGroup; import android.media.MediaRouter.RouteInfo; import android.media.MediaRouter.UserRouteInfo; import android.media.RemoteControlClient; import android.os.Bundle; import android.text.TextUtils; import android.view.KeyEvent; Loading Loading @@ -85,7 +83,8 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { final RouteComparator mComparator = new RouteComparator(); final MediaRouterCallback mCallback = new MediaRouterCallback(); private boolean mIgnoreVolumeChanges; private boolean mIgnoreSliderVolumeChanges; private boolean mIgnoreCallbackVolumeChanges; public MediaRouteChooserDialogFragment() { setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog); Loading Loading @@ -126,52 +125,34 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { void updateVolume() { final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes); final boolean defaultAudioSelected = selectedRoute == mRouter.getSystemAudioRoute(); final boolean selectedSystemRoute = selectedRoute.getCategory() == mRouter.getSystemAudioCategory(); mVolumeIcon.setImageResource(defaultAudioSelected ? mVolumeIcon.setImageResource( selectedRoute.getPlaybackType() == RouteInfo.PLAYBACK_TYPE_LOCAL ? R.drawable.ic_audio_vol : R.drawable.ic_media_route_on_holo_dark); mIgnoreVolumeChanges = true; mVolumeSlider.setEnabled(true); if (selectedSystemRoute) { // Use the standard media audio stream mVolumeSlider.setMax(mAudio.getStreamMaxVolume(AudioManager.STREAM_MUSIC)); mVolumeSlider.setProgress(mAudio.getStreamVolume(AudioManager.STREAM_MUSIC)); } else { final RouteInfo firstSelected; if (selectedRoute instanceof RouteGroup) { firstSelected = ((RouteGroup) selectedRoute).getRouteAt(0); } else { firstSelected = selectedRoute; } mIgnoreSliderVolumeChanges = true; RemoteControlClient rcc = null; if (firstSelected instanceof UserRouteInfo) { rcc = ((UserRouteInfo) firstSelected).getRemoteControlClient(); } if (rcc == null) { // No RemoteControlClient? Assume volume can't be controlled. if (selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_FIXED) { // Disable the slider and show it at max volume. mVolumeSlider.setMax(1); mVolumeSlider.setProgress(1); mVolumeSlider.setEnabled(false); } else { // TODO: Connect this to the remote control volume } mVolumeSlider.setEnabled(true); mVolumeSlider.setMax(selectedRoute.getVolumeMax()); mVolumeSlider.setProgress(selectedRoute.getVolume()); } mIgnoreVolumeChanges = false; mIgnoreSliderVolumeChanges = false; } void changeVolume(int newValue) { if (mIgnoreVolumeChanges) return; if (mIgnoreSliderVolumeChanges) return; RouteCategory selectedCategory = mRouter.getSelectedRoute(mRouteTypes).getCategory(); if (selectedCategory == mRouter.getSystemAudioCategory()) { final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes); if (selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_VARIABLE) { final int maxVolume = mAudio.getStreamMaxVolume(AudioManager.STREAM_MUSIC); newValue = Math.max(0, Math.min(newValue, maxVolume)); mAudio.setStreamVolume(AudioManager.STREAM_MUSIC, newValue, 0); selectedRoute.requestSetVolume(newValue); } } Loading Loading @@ -595,7 +576,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { @Override public void onRouteAdded(MediaRouter router, RouteInfo info) { mAdapter.update(); updateVolume(); } @Override Loading @@ -604,7 +584,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { mAdapter.finishGrouping(); } mAdapter.update(); updateVolume(); } @Override Loading @@ -622,6 +601,13 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { mAdapter.update(); } @Override public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { if (!mIgnoreCallbackVolumeChanges) { updateVolume(); } } } class RouteComparator implements Comparator<RouteInfo> { Loading @@ -648,15 +634,25 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) { mVolumeSlider.incrementProgressBy(-1); mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(-1); return true; } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) { mVolumeSlider.incrementProgressBy(1); mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(1); return true; } else { return super.onKeyDown(keyCode, event); } } public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) { return true; } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) { return true; } else { return super.onKeyUp(keyCode, event); } } } /** Loading @@ -675,10 +671,13 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { @Override public void onStartTrackingTouch(SeekBar seekBar) { mIgnoreCallbackVolumeChanges = true; } @Override public void onStopTrackingTouch(SeekBar seekBar) { mIgnoreCallbackVolumeChanges = false; updateVolume(); } } Loading media/java/android/media/MediaRouter.java +192 −4 Original line number Diff line number Diff line Loading @@ -16,7 +16,10 @@ package android.media; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Handler; Loading Loading @@ -87,12 +90,15 @@ public class MediaRouter { } // Called after sStatic is initialized void startMonitoringRoutes() { void startMonitoringRoutes(Context appContext) { mDefaultAudio = new RouteInfo(mSystemCategory); mDefaultAudio.mNameResId = com.android.internal.R.string.default_audio_route_name; mDefaultAudio.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; addRoute(mDefaultAudio); appContext.registerReceiver(new VolumeChangeReceiver(), new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); AudioRoutesInfo newRoutes = null; try { newRoutes = mAudioService.startWatchingRoutes(mRoutesObserver); Loading Loading @@ -190,8 +196,9 @@ public class MediaRouter { public MediaRouter(Context context) { synchronized (Static.class) { if (sStatic == null) { sStatic = new Static(context.getApplicationContext()); sStatic.startMonitoringRoutes(); final Context appContext = context.getApplicationContext(); sStatic = new Static(appContext); sStatic.startMonitoringRoutes(appContext); } } } Loading Loading @@ -578,6 +585,33 @@ public class MediaRouter { } } static void dispatchRouteVolumeChanged(RouteInfo info) { for (CallbackInfo cbi : sStatic.mCallbacks) { if ((cbi.type & info.mSupportedTypes) != 0) { cbi.cb.onRouteVolumeChanged(cbi.router, info); } } } static void systemVolumeChanged(int newValue) { final RouteInfo selectedRoute = sStatic.mSelectedRoute; if (selectedRoute == null) return; if (selectedRoute == sStatic.mBluetoothA2dpRoute || selectedRoute == sStatic.mDefaultAudio) { dispatchRouteVolumeChanged(selectedRoute); } else if (sStatic.mBluetoothA2dpRoute != null) { try { dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudio); } catch (RemoteException e) { Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); } } else { dispatchRouteVolumeChanged(sStatic.mDefaultAudio); } } /** * Information about a media route. */ Loading Loading @@ -735,6 +769,9 @@ public class MediaRouter { } /** * Return the current volume for this route. Depending on the route, this may only * be valid if the route is currently selected. * * @return the volume at which the playback associated with this route is performed * @see UserRouteInfo#setVolume(int) */ Loading @@ -752,6 +789,44 @@ public class MediaRouter { } } /** * Request a volume change for this route. * @param volume value between 0 and getVolumeMax */ public void requestSetVolume(int volume) { if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { try { sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0); } catch (RemoteException e) { Log.e(TAG, "Error setting local stream volume", e); } } else { Log.e(TAG, getClass().getSimpleName() + ".requestSetVolume(): " + "Non-local volume playback on system route? " + "Could not request volume change."); } } /** * Request an incremental volume update for this route. * @param direction Delta to apply to the current volume */ public void requestUpdateVolume(int direction) { if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { try { final int volume = Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0); } catch (RemoteException e) { Log.e(TAG, "Error setting local stream volume", e); } } else { Log.e(TAG, getClass().getSimpleName() + ".requestChangeVolume(): " + "Non-local volume playback on system route? " + "Could not request volume change."); } } /** * @return the maximum volume at which the playback associated with this route is performed * @see UserRouteInfo#setVolumeMax(int) Loading Loading @@ -821,6 +896,8 @@ public class MediaRouter { /** * Information about a route that the application may define and modify. * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. * * @see MediaRouter.RouteInfo */ Loading @@ -830,6 +907,8 @@ public class MediaRouter { UserRouteInfo(RouteCategory category) { super(category); mSupportedTypes = ROUTE_TYPE_USER; mPlaybackType = PLAYBACK_TYPE_REMOTE; mVolumeHandling = PLAYBACK_VOLUME_FIXED; } /** Loading Loading @@ -949,9 +1028,33 @@ public class MediaRouter { * @param volume */ public void setVolume(int volume) { volume = Math.max(0, Math.min(volume, getVolumeMax())); if (mVolume != volume) { mVolume = volume; setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume); dispatchRouteVolumeChanged(this); } } @Override public void requestSetVolume(int volume) { if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { if (mVcb == null) { Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); return; } mVcb.vcb.onVolumeSetRequest(this, volume); } } @Override public void requestUpdateVolume(int direction) { if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { if (mVcb == null) { Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); return; } mVcb.vcb.onVolumeUpdateRequest(this, direction); } } Loading Loading @@ -1018,6 +1121,7 @@ public class MediaRouter { RouteGroup(RouteCategory category) { super(category); mGroup = this; mVolumeHandling = PLAYBACK_VOLUME_FIXED; } CharSequence getName(Resources res) { Loading Loading @@ -1138,6 +1242,45 @@ public class MediaRouter { setIconDrawable(sStatic.mResources.getDrawable(resId)); } @Override public void requestSetVolume(int volume) { final int maxVol = getVolumeMax(); if (maxVol == 0) { return; } final float scaledVolume = (float) volume / maxVol; final int routeCount = getRouteCount(); for (int i = 0; i < routeCount; i++) { final RouteInfo route = getRouteAt(i); final int routeVol = (int) (scaledVolume * route.getVolumeMax()); route.requestSetVolume(routeVol); } if (volume != mVolume) { mVolume = volume; dispatchRouteVolumeChanged(this); } } @Override public void requestUpdateVolume(int direction) { final int maxVol = getVolumeMax(); if (maxVol == 0) { return; } final int routeCount = getRouteCount(); for (int i = 0; i < routeCount; i++) { final RouteInfo route = getRouteAt(i); route.requestUpdateVolume(direction); } final int volume = Math.max(0, Math.min(mVolume + direction, maxVol)); if (volume != mVolume) { mVolume = volume; dispatchRouteVolumeChanged(this); } } void memberNameChanged(RouteInfo info, CharSequence name) { mUpdateName = true; routeUpdated(); Loading @@ -1157,10 +1300,23 @@ public class MediaRouter { return; } int maxVolume = 0; boolean isLocal = true; boolean isFixedVolume = true; for (int i = 0; i < count; i++) { types |= mRoutes.get(i).mSupportedTypes; final RouteInfo route = mRoutes.get(i); types |= route.mSupportedTypes; final int routeMaxVolume = route.getVolumeMax(); if (routeMaxVolume > maxVolume) { maxVolume = routeMaxVolume; } isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; } mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; mSupportedTypes = types; mVolumeMax = maxVolume; mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; super.routeUpdated(); } Loading Loading @@ -1381,6 +1537,14 @@ public class MediaRouter { * @param group The group the route was removed from */ public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); /** * Called when a route's volume changes. * * @param router the MediaRouter reporting the event * @param info The route with altered volume */ public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); } /** Loading Loading @@ -1419,6 +1583,9 @@ public class MediaRouter { public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { } @Override public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { } } static class VolumeCallbackInfo { Loading Loading @@ -1459,4 +1626,25 @@ public class MediaRouter { public abstract void onVolumeSetRequest(RouteInfo info, int volume); } static class VolumeChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); if (streamType != AudioManager.STREAM_MUSIC) { return; } final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); final int oldVolume = intent.getIntExtra( AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); if (newVolume != oldVolume) { systemVolumeChanged(newVolume); } } } } } Loading
api/current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -11538,6 +11538,7 @@ package android.media { method public abstract void onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo); method public abstract void onRouteUngrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup); method public abstract void onRouteUnselected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo); method public abstract void onRouteVolumeChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo); } public static class MediaRouter.RouteCategory { Loading Loading @@ -11573,6 +11574,8 @@ package android.media { method public int getVolume(); method public int getVolumeHandling(); method public int getVolumeMax(); method public void requestSetVolume(int); method public void requestUpdateVolume(int); method public void setTag(java.lang.Object); field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0 field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1 Loading @@ -11589,6 +11592,7 @@ package android.media { method public void onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo); method public void onRouteUngrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup); method public void onRouteUnselected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo); method public void onRouteVolumeChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo); } public static class MediaRouter.UserRouteInfo extends android.media.MediaRouter.RouteInfo {
core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java +42 −43 Original line number Diff line number Diff line Loading @@ -30,8 +30,6 @@ import android.media.MediaRouter; import android.media.MediaRouter.RouteCategory; import android.media.MediaRouter.RouteGroup; import android.media.MediaRouter.RouteInfo; import android.media.MediaRouter.UserRouteInfo; import android.media.RemoteControlClient; import android.os.Bundle; import android.text.TextUtils; import android.view.KeyEvent; Loading Loading @@ -85,7 +83,8 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { final RouteComparator mComparator = new RouteComparator(); final MediaRouterCallback mCallback = new MediaRouterCallback(); private boolean mIgnoreVolumeChanges; private boolean mIgnoreSliderVolumeChanges; private boolean mIgnoreCallbackVolumeChanges; public MediaRouteChooserDialogFragment() { setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog); Loading Loading @@ -126,52 +125,34 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { void updateVolume() { final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes); final boolean defaultAudioSelected = selectedRoute == mRouter.getSystemAudioRoute(); final boolean selectedSystemRoute = selectedRoute.getCategory() == mRouter.getSystemAudioCategory(); mVolumeIcon.setImageResource(defaultAudioSelected ? mVolumeIcon.setImageResource( selectedRoute.getPlaybackType() == RouteInfo.PLAYBACK_TYPE_LOCAL ? R.drawable.ic_audio_vol : R.drawable.ic_media_route_on_holo_dark); mIgnoreVolumeChanges = true; mVolumeSlider.setEnabled(true); if (selectedSystemRoute) { // Use the standard media audio stream mVolumeSlider.setMax(mAudio.getStreamMaxVolume(AudioManager.STREAM_MUSIC)); mVolumeSlider.setProgress(mAudio.getStreamVolume(AudioManager.STREAM_MUSIC)); } else { final RouteInfo firstSelected; if (selectedRoute instanceof RouteGroup) { firstSelected = ((RouteGroup) selectedRoute).getRouteAt(0); } else { firstSelected = selectedRoute; } mIgnoreSliderVolumeChanges = true; RemoteControlClient rcc = null; if (firstSelected instanceof UserRouteInfo) { rcc = ((UserRouteInfo) firstSelected).getRemoteControlClient(); } if (rcc == null) { // No RemoteControlClient? Assume volume can't be controlled. if (selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_FIXED) { // Disable the slider and show it at max volume. mVolumeSlider.setMax(1); mVolumeSlider.setProgress(1); mVolumeSlider.setEnabled(false); } else { // TODO: Connect this to the remote control volume } mVolumeSlider.setEnabled(true); mVolumeSlider.setMax(selectedRoute.getVolumeMax()); mVolumeSlider.setProgress(selectedRoute.getVolume()); } mIgnoreVolumeChanges = false; mIgnoreSliderVolumeChanges = false; } void changeVolume(int newValue) { if (mIgnoreVolumeChanges) return; if (mIgnoreSliderVolumeChanges) return; RouteCategory selectedCategory = mRouter.getSelectedRoute(mRouteTypes).getCategory(); if (selectedCategory == mRouter.getSystemAudioCategory()) { final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes); if (selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_VARIABLE) { final int maxVolume = mAudio.getStreamMaxVolume(AudioManager.STREAM_MUSIC); newValue = Math.max(0, Math.min(newValue, maxVolume)); mAudio.setStreamVolume(AudioManager.STREAM_MUSIC, newValue, 0); selectedRoute.requestSetVolume(newValue); } } Loading Loading @@ -595,7 +576,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { @Override public void onRouteAdded(MediaRouter router, RouteInfo info) { mAdapter.update(); updateVolume(); } @Override Loading @@ -604,7 +584,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { mAdapter.finishGrouping(); } mAdapter.update(); updateVolume(); } @Override Loading @@ -622,6 +601,13 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { mAdapter.update(); } @Override public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { if (!mIgnoreCallbackVolumeChanges) { updateVolume(); } } } class RouteComparator implements Comparator<RouteInfo> { Loading @@ -648,15 +634,25 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) { mVolumeSlider.incrementProgressBy(-1); mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(-1); return true; } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) { mVolumeSlider.incrementProgressBy(1); mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(1); return true; } else { return super.onKeyDown(keyCode, event); } } public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) { return true; } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) { return true; } else { return super.onKeyUp(keyCode, event); } } } /** Loading @@ -675,10 +671,13 @@ public class MediaRouteChooserDialogFragment extends DialogFragment { @Override public void onStartTrackingTouch(SeekBar seekBar) { mIgnoreCallbackVolumeChanges = true; } @Override public void onStopTrackingTouch(SeekBar seekBar) { mIgnoreCallbackVolumeChanges = false; updateVolume(); } } Loading
media/java/android/media/MediaRouter.java +192 −4 Original line number Diff line number Diff line Loading @@ -16,7 +16,10 @@ package android.media; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Handler; Loading Loading @@ -87,12 +90,15 @@ public class MediaRouter { } // Called after sStatic is initialized void startMonitoringRoutes() { void startMonitoringRoutes(Context appContext) { mDefaultAudio = new RouteInfo(mSystemCategory); mDefaultAudio.mNameResId = com.android.internal.R.string.default_audio_route_name; mDefaultAudio.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; addRoute(mDefaultAudio); appContext.registerReceiver(new VolumeChangeReceiver(), new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); AudioRoutesInfo newRoutes = null; try { newRoutes = mAudioService.startWatchingRoutes(mRoutesObserver); Loading Loading @@ -190,8 +196,9 @@ public class MediaRouter { public MediaRouter(Context context) { synchronized (Static.class) { if (sStatic == null) { sStatic = new Static(context.getApplicationContext()); sStatic.startMonitoringRoutes(); final Context appContext = context.getApplicationContext(); sStatic = new Static(appContext); sStatic.startMonitoringRoutes(appContext); } } } Loading Loading @@ -578,6 +585,33 @@ public class MediaRouter { } } static void dispatchRouteVolumeChanged(RouteInfo info) { for (CallbackInfo cbi : sStatic.mCallbacks) { if ((cbi.type & info.mSupportedTypes) != 0) { cbi.cb.onRouteVolumeChanged(cbi.router, info); } } } static void systemVolumeChanged(int newValue) { final RouteInfo selectedRoute = sStatic.mSelectedRoute; if (selectedRoute == null) return; if (selectedRoute == sStatic.mBluetoothA2dpRoute || selectedRoute == sStatic.mDefaultAudio) { dispatchRouteVolumeChanged(selectedRoute); } else if (sStatic.mBluetoothA2dpRoute != null) { try { dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudio); } catch (RemoteException e) { Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); } } else { dispatchRouteVolumeChanged(sStatic.mDefaultAudio); } } /** * Information about a media route. */ Loading Loading @@ -735,6 +769,9 @@ public class MediaRouter { } /** * Return the current volume for this route. Depending on the route, this may only * be valid if the route is currently selected. * * @return the volume at which the playback associated with this route is performed * @see UserRouteInfo#setVolume(int) */ Loading @@ -752,6 +789,44 @@ public class MediaRouter { } } /** * Request a volume change for this route. * @param volume value between 0 and getVolumeMax */ public void requestSetVolume(int volume) { if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { try { sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0); } catch (RemoteException e) { Log.e(TAG, "Error setting local stream volume", e); } } else { Log.e(TAG, getClass().getSimpleName() + ".requestSetVolume(): " + "Non-local volume playback on system route? " + "Could not request volume change."); } } /** * Request an incremental volume update for this route. * @param direction Delta to apply to the current volume */ public void requestUpdateVolume(int direction) { if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { try { final int volume = Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0); } catch (RemoteException e) { Log.e(TAG, "Error setting local stream volume", e); } } else { Log.e(TAG, getClass().getSimpleName() + ".requestChangeVolume(): " + "Non-local volume playback on system route? " + "Could not request volume change."); } } /** * @return the maximum volume at which the playback associated with this route is performed * @see UserRouteInfo#setVolumeMax(int) Loading Loading @@ -821,6 +896,8 @@ public class MediaRouter { /** * Information about a route that the application may define and modify. * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. * * @see MediaRouter.RouteInfo */ Loading @@ -830,6 +907,8 @@ public class MediaRouter { UserRouteInfo(RouteCategory category) { super(category); mSupportedTypes = ROUTE_TYPE_USER; mPlaybackType = PLAYBACK_TYPE_REMOTE; mVolumeHandling = PLAYBACK_VOLUME_FIXED; } /** Loading Loading @@ -949,9 +1028,33 @@ public class MediaRouter { * @param volume */ public void setVolume(int volume) { volume = Math.max(0, Math.min(volume, getVolumeMax())); if (mVolume != volume) { mVolume = volume; setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume); dispatchRouteVolumeChanged(this); } } @Override public void requestSetVolume(int volume) { if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { if (mVcb == null) { Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); return; } mVcb.vcb.onVolumeSetRequest(this, volume); } } @Override public void requestUpdateVolume(int direction) { if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { if (mVcb == null) { Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); return; } mVcb.vcb.onVolumeUpdateRequest(this, direction); } } Loading Loading @@ -1018,6 +1121,7 @@ public class MediaRouter { RouteGroup(RouteCategory category) { super(category); mGroup = this; mVolumeHandling = PLAYBACK_VOLUME_FIXED; } CharSequence getName(Resources res) { Loading Loading @@ -1138,6 +1242,45 @@ public class MediaRouter { setIconDrawable(sStatic.mResources.getDrawable(resId)); } @Override public void requestSetVolume(int volume) { final int maxVol = getVolumeMax(); if (maxVol == 0) { return; } final float scaledVolume = (float) volume / maxVol; final int routeCount = getRouteCount(); for (int i = 0; i < routeCount; i++) { final RouteInfo route = getRouteAt(i); final int routeVol = (int) (scaledVolume * route.getVolumeMax()); route.requestSetVolume(routeVol); } if (volume != mVolume) { mVolume = volume; dispatchRouteVolumeChanged(this); } } @Override public void requestUpdateVolume(int direction) { final int maxVol = getVolumeMax(); if (maxVol == 0) { return; } final int routeCount = getRouteCount(); for (int i = 0; i < routeCount; i++) { final RouteInfo route = getRouteAt(i); route.requestUpdateVolume(direction); } final int volume = Math.max(0, Math.min(mVolume + direction, maxVol)); if (volume != mVolume) { mVolume = volume; dispatchRouteVolumeChanged(this); } } void memberNameChanged(RouteInfo info, CharSequence name) { mUpdateName = true; routeUpdated(); Loading @@ -1157,10 +1300,23 @@ public class MediaRouter { return; } int maxVolume = 0; boolean isLocal = true; boolean isFixedVolume = true; for (int i = 0; i < count; i++) { types |= mRoutes.get(i).mSupportedTypes; final RouteInfo route = mRoutes.get(i); types |= route.mSupportedTypes; final int routeMaxVolume = route.getVolumeMax(); if (routeMaxVolume > maxVolume) { maxVolume = routeMaxVolume; } isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; } mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; mSupportedTypes = types; mVolumeMax = maxVolume; mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; super.routeUpdated(); } Loading Loading @@ -1381,6 +1537,14 @@ public class MediaRouter { * @param group The group the route was removed from */ public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); /** * Called when a route's volume changes. * * @param router the MediaRouter reporting the event * @param info The route with altered volume */ public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); } /** Loading Loading @@ -1419,6 +1583,9 @@ public class MediaRouter { public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { } @Override public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { } } static class VolumeCallbackInfo { Loading Loading @@ -1459,4 +1626,25 @@ public class MediaRouter { public abstract void onVolumeSetRequest(RouteInfo info, int volume); } static class VolumeChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); if (streamType != AudioManager.STREAM_MUSIC) { return; } final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); final int oldVolume = intent.getIntExtra( AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); if (newVolume != oldVolume) { systemVolumeChanged(newVolume); } } } } }