diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java index 54958d3470965..fd8e03e759f8c 100644 --- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java +++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java @@ -28,10 +28,12 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; +import android.media.AudioSystem; import android.media.MediaRoute2Info; import android.text.TextUtils; import android.util.Slog; import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import com.android.internal.R; @@ -55,6 +57,9 @@ class BluetoothRouteProvider { @SuppressWarnings("WeakerAccess") /* synthetic access */ BluetoothHearingAid mHearingAidProfile; + // Route type -> volume map + private final SparseIntArray mVolumeMap = new SparseIntArray(); + private final Context mContext; private final BluetoothAdapter mBluetoothAdapter; private final BluetoothRoutesUpdatedListener mListener; @@ -192,11 +197,30 @@ class BluetoothRouteProvider { return routes; } - boolean setSelectedRouteVolume(int volume) { - if (mSelectedRoute == null) return false; + /** + * Updates the volume for {@link AudioManager#getDevicesForStream(int) devices}. + * + * @return true if devices can be handled by the provider. + */ + public boolean updateVolumeForDevices(int devices, int volume) { + int routeType; + if ((devices & (AudioSystem.DEVICE_OUT_HEARING_AID)) != 0) { + routeType = MediaRoute2Info.TYPE_HEARING_AID; + } else if ((devices & (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP + | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES + | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) { + routeType = MediaRoute2Info.TYPE_BLUETOOTH_A2DP; + } else { + return false; + } + mVolumeMap.put(routeType, volume); + if (mSelectedRoute == null || mSelectedRoute.route.getType() != routeType) { + return true; + } mSelectedRoute.route = new MediaRoute2Info.Builder(mSelectedRoute.route) .setVolume(volume) .build(); + notifyBluetoothRoutesUpdated(); return true; } @@ -222,6 +246,7 @@ class BluetoothRouteProvider { R.string.bluetooth_a2dp_audio_route_name).toString()) .setType(MediaRoute2Info.TYPE_BLUETOOTH_A2DP) .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) + .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) .build(); newBtRoute.connectedProfiles = new SparseBooleanArray(); return newBtRoute; @@ -240,13 +265,10 @@ class BluetoothRouteProvider { // Update volume when the connection state is changed. MediaRoute2Info.Builder builder = new MediaRoute2Info.Builder(btRoute.route) .setConnectionState(state); - builder.setType(btRoute.connectedProfiles.get(BluetoothProfile.HEARING_AID, false) - ? MediaRoute2Info.TYPE_HEARING_AID : MediaRoute2Info.TYPE_BLUETOOTH_A2DP); + builder.setType(btRoute.getRouteType()); 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); + builder.setVolume(mVolumeMap.get(btRoute.getRouteType(), 0)); } btRoute.route = builder.build(); } @@ -259,6 +281,15 @@ class BluetoothRouteProvider { public BluetoothDevice btDevice; public MediaRoute2Info route; public SparseBooleanArray connectedProfiles; + + @MediaRoute2Info.Type + int getRouteType() { + // Let hearing aid profile have a priority. + if (connectedProfiles.get(BluetoothProfile.HEARING_AID, false)) { + return MediaRoute2Info.TYPE_HEARING_AID; + } + return MediaRoute2Info.TYPE_BLUETOOTH_A2DP; + } } // These callbacks run on the main thread. @@ -285,13 +316,12 @@ class BluetoothRouteProvider { btRoute = createBluetoothRoute(device); mBluetoothRoutes.put(device.getAddress(), btRoute); } + btRoute.connectedProfiles.put(profile, true); if (activeDevices.contains(device)) { mSelectedRoute = btRoute; setRouteConnectionState(mSelectedRoute, MediaRoute2Info.CONNECTION_STATE_CONNECTED); } - - btRoute.connectedProfiles.put(profile, true); } notifyBluetoothRoutesUpdated(); } @@ -348,6 +378,8 @@ class BluetoothRouteProvider { BluetoothDevice.ERROR); BluetoothRouteInfo btRoute = mBluetoothRoutes.get(device.getAddress()); if (bondState == BluetoothDevice.BOND_BONDED && btRoute == null) { + //TODO: The type of the new route is A2DP even when it's HEARING_AID. + // We may determine the type of route when create the route. btRoute = createBluetoothRoute(device); if (mA2dpProfile != null && mA2dpProfile.getConnectedDevices().contains(device)) { btRoute.connectedProfiles.put(BluetoothProfile.A2DP, true); diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index b585b49928cd4..fdee9f86bfafa 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -81,6 +81,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { MediaRoute2Info mDeviceRoute; RoutingSessionInfo mDefaultSessionInfo; final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); + int mDeviceVolume; private final Object mRequestLock = new Object(); @GuardedBy("mRequestLock") @@ -127,8 +128,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { }); updateSessionInfosIfNeeded(); - mContext.registerReceiver(new VolumeChangeReceiver(), - new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); + IntentFilter intentFilter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION); + intentFilter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION); + mContext.registerReceiver(new AudioManagerBroadcastReceiver(), intentFilter); if (mBtRouteProvider != null) { mHandler.post(() -> { @@ -136,6 +138,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { notifyProviderState(); }); } + updateVolume(); } @Override @@ -248,8 +251,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { .setVolumeHandling(mAudioManager.isVolumeFixed() ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) + .setVolume(mDeviceVolume) .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) - .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) .setType(type) .addFeature(FEATURE_LIVE_AUDIO) .addFeature(FEATURE_LIVE_VIDEO) @@ -361,36 +364,43 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } } - private class VolumeChangeReceiver extends BroadcastReceiver { + void updateVolume() { + int devices = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC); + int volume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); + + if (mDefaultRoute.getVolume() != volume) { + mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute) + .setVolume(volume) + .build(); + } + + if (mBtRouteProvider != null && mBtRouteProvider.updateVolumeForDevices(devices, volume)) { + return; + } + if (mDeviceVolume != volume) { + mDeviceVolume = volume; + mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute) + .setVolume(volume) + .build(); + } + publishProviderState(); + } + + private class AudioManagerBroadcastReceiver 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)) { + if (!intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION) + && !intent.getAction().equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) { return; } - final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); + 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) { - if (TextUtils.equals(mDeviceRoute.getId(), mSelectedRouteId)) { - mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute) - .setVolume(newVolume) - .build(); - } else if (mBtRouteProvider != null) { - mBtRouteProvider.setSelectedRouteVolume(newVolume); - } - mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute) - .setVolume(newVolume) - .build(); - publishProviderState(); - } + updateVolume(); } } }