From 717ef72d8dc5e6a2b1a3544f53f161dba6812841 Mon Sep 17 00:00:00 2001 From: Hyundo Moon Date: Thu, 6 Feb 2020 18:44:13 +0900 Subject: [PATCH] Set the current/max volume of system routes Also, this CL makes SystemMediaRoute2Provider publish new route infos when the volumes are changed. MediaRouter2 can get the volume changes from RouteCallback#onRoutesChanged(). Bug: 149005682 Test: atest mediaroutertest and CTS Change-Id: Icfc3b9f3b568e66d55782b11e0d29fec3b9eac6e --- media/java/android/media/MediaRouter2.java | 13 +++--- .../server/media/BluetoothRouteProvider.java | 22 +++++++-- .../media/SystemMediaRoute2Provider.java | 45 +++++++++++++++++++ 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index d7b74df0a5e6a..64186106d2c87 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -471,7 +471,8 @@ public class MediaRouter2 { synchronized (sRouterLock) { for (MediaRoute2Info route : routes) { mRoutes.put(route.getId(), route); - if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { + if (route.isSystemRoute() + || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { addedRoutes.add(route); } } @@ -487,7 +488,8 @@ public class MediaRouter2 { synchronized (sRouterLock) { for (MediaRoute2Info route : routes) { mRoutes.remove(route.getId()); - if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { + if (route.isSystemRoute() + || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { removedRoutes.add(route); } } @@ -503,7 +505,8 @@ public class MediaRouter2 { synchronized (sRouterLock) { for (MediaRoute2Info route : routes) { mRoutes.put(route.getId(), route); - if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { + if (route.isSystemRoute() + || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { changedRoutes.add(route); } } @@ -643,8 +646,8 @@ public class MediaRouter2 { private List filterRoutes(List routes, RouteDiscoveryPreference discoveryRequest) { return routes.stream() - .filter( - route -> route.hasAnyFeatures(discoveryRequest.getPreferredFeatures())) + .filter(route -> route.isSystemRoute() + || route.hasAnyFeatures(discoveryRequest.getPreferredFeatures())) .collect(Collectors.toList()); } diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java index 669f1ac6750cf..647430399bc97 100644 --- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java +++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java @@ -27,6 +27,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.media.AudioManager; import android.media.MediaRoute2Info; import android.text.TextUtils; import android.util.Slog; @@ -55,6 +56,7 @@ class BluetoothRouteProvider { private final Context mContext; private final BluetoothAdapter mBluetoothAdapter; private final BluetoothRoutesUpdatedListener mListener; + private final AudioManager mAudioManager; private final Map mEventReceiverMap = new HashMap<>(); private final IntentFilter mIntentFilter = new IntentFilter(); private final BroadcastReceiver mBroadcastReceiver = new BluetoothBroadcastReceiver(); @@ -82,6 +84,7 @@ class BluetoothRouteProvider { mContext = context; mBluetoothAdapter = btAdapter; mListener = listener; + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); buildBluetoothRoutes(); mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP); @@ -181,12 +184,15 @@ class BluetoothRouteProvider { private BluetoothRouteInfo createBluetoothRoute(BluetoothDevice device) { BluetoothRouteInfo newBtRoute = new BluetoothRouteInfo(); newBtRoute.btDevice = device; + // Current / Max volume will be set when connected. + // TODO: Is there any BT device which has fixed volume? newBtRoute.route = new MediaRoute2Info.Builder(device.getAddress(), device.getName()) .addFeature(MediaRoute2Info.FEATURE_LIVE_AUDIO) .setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED) .setDescription(mContext.getResources().getText( R.string.bluetooth_a2dp_audio_route_name).toString()) .setDeviceType(MediaRoute2Info.DEVICE_TYPE_BLUETOOTH) + .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) .build(); newBtRoute.connectedProfiles = new SparseBooleanArray(); return newBtRoute; @@ -203,10 +209,20 @@ class BluetoothRouteProvider { Slog.w(TAG, "setRouteConnectionStateForDevice: route shouldn't be null"); return; } - if (btRoute.route.getConnectionState() != state) { - btRoute.route = new MediaRoute2Info.Builder(btRoute.route) - .setConnectionState(state).build(); + if (btRoute.route.getConnectionState() == state) { + return; } + + // Update volume when the connection state is changed. + MediaRoute2Info.Builder builder = new MediaRoute2Info.Builder(btRoute.route) + .setConnectionState(state); + + if (state == MediaRoute2Info.CONNECTION_STATE_CONNECTED) { + int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); + int currentVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); + builder.setVolumeMax(maxVolume).setVolume(currentVolume); + } + btRoute.route = builder.build(); } interface BluetoothRoutesUpdatedListener { diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 888f7ce74ba46..b5dcea8bb51e3 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -20,9 +20,11 @@ import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO; import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO; import android.annotation.NonNull; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.media.AudioManager; import android.media.AudioRoutesInfo; import android.media.IAudioRoutesObserver; @@ -107,6 +109,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } }); initializeSessionInfo(); + + mContext.registerReceiver(new VolumeChangeReceiver(), + new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); } @Override @@ -278,4 +283,44 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } mCallback.onSessionUpdated(this, sessionInfo); } + + private class VolumeChangeReceiver extends BroadcastReceiver { + // This will be called in the main thread. + @Override + public void onReceive(Context context, Intent intent) { + if (!intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { + return; + } + + 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) { + String activeBtDeviceAddress = mBtRouteProvider.getActiveDeviceAddress(); + if (!TextUtils.isEmpty(activeBtDeviceAddress)) { + for (int i = mBluetoothRoutes.size() - 1; i >= 0; i--) { + MediaRoute2Info route = mBluetoothRoutes.get(i); + if (TextUtils.equals(activeBtDeviceAddress, route.getId())) { + mBluetoothRoutes.set(i, + new MediaRoute2Info.Builder(route) + .setVolume(newVolume) + .build()); + break; + } + } + } else { + mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute) + .setVolume(newVolume) + .build(); + } + publishRoutes(); + } + } + } }