Handle multiple active bluetooth devices
When dealing with a pair of hearing aid devices are active, a single "selected route" is not sufficient. Instead, this CL introduces activeRoutes which can hold multiple active bluetooth route and deal with them. Bug: 152585170 Test: cts tested & manually w/ A2dp BT devices Change-Id: I2c2b8967d9f221db73f9d3b9332de7c76d07a0f9
This commit is contained in:
@@ -344,6 +344,8 @@ public final class MediaRouter2Manager {
|
||||
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
|
||||
Objects.requireNonNull(route, "route must not be null");
|
||||
|
||||
Log.v(TAG, "Transferring routing session. session= " + sessionInfo + ", route=" + route);
|
||||
|
||||
synchronized (mRoutesLock) {
|
||||
if (!mRoutes.containsKey(route.getId())) {
|
||||
Log.w(TAG, "transfer: Ignoring an unknown route id=" + route.getId());
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.server.media;
|
||||
|
||||
import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_AUDIO;
|
||||
import static android.bluetooth.BluetoothAdapter.STATE_CONNECTED;
|
||||
import static android.bluetooth.BluetoothAdapter.STATE_DISCONNECTED;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -33,6 +35,7 @@ import android.media.AudioManager;
|
||||
import android.media.AudioSystem;
|
||||
import android.media.MediaRoute2Info;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
@@ -48,6 +51,8 @@ import java.util.Objects;
|
||||
|
||||
class BluetoothRouteProvider {
|
||||
private static final String TAG = "BTRouteProvider";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
|
||||
private static BluetoothRouteProvider sInstance;
|
||||
|
||||
@@ -55,7 +60,7 @@ class BluetoothRouteProvider {
|
||||
// Maps hardware address to BluetoothRouteInfo
|
||||
final Map<String, BluetoothRouteInfo> mBluetoothRoutes = new HashMap<>();
|
||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||
BluetoothRouteInfo mSelectedRoute = null;
|
||||
final List<BluetoothRouteInfo> mActiveRoutes = new ArrayList<>();
|
||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||
BluetoothA2dp mA2dpProfile;
|
||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||
@@ -104,7 +109,7 @@ class BluetoothRouteProvider {
|
||||
// Bluetooth on/off broadcasts
|
||||
addEventReceiver(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedReceiver());
|
||||
|
||||
DeviceStateChangedRecevier deviceStateChangedReceiver = new DeviceStateChangedRecevier();
|
||||
DeviceStateChangedReceiver deviceStateChangedReceiver = new DeviceStateChangedReceiver();
|
||||
addEventReceiver(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED, deviceStateChangedReceiver);
|
||||
addEventReceiver(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED, deviceStateChangedReceiver);
|
||||
addEventReceiver(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED,
|
||||
@@ -168,14 +173,16 @@ class BluetoothRouteProvider {
|
||||
|
||||
@Nullable
|
||||
MediaRoute2Info getSelectedRoute() {
|
||||
return (mSelectedRoute == null) ? null : mSelectedRoute.route;
|
||||
// For now, active routes can be multiple only when a pair of hearing aid devices is active.
|
||||
// Let the first active device represent them.
|
||||
return (mActiveRoutes.isEmpty() ? null : mActiveRoutes.get(0).route);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
List<MediaRoute2Info> getTransferableRoutes() {
|
||||
List<MediaRoute2Info> routes = getAllBluetoothRoutes();
|
||||
if (mSelectedRoute != null) {
|
||||
routes.remove(mSelectedRoute.route);
|
||||
for (BluetoothRouteInfo btRoute : mActiveRoutes) {
|
||||
routes.remove(btRoute.route);
|
||||
}
|
||||
return routes;
|
||||
}
|
||||
@@ -185,8 +192,14 @@ class BluetoothRouteProvider {
|
||||
List<MediaRoute2Info> routes = new ArrayList<>();
|
||||
List<String> routeIds = new ArrayList<>();
|
||||
|
||||
MediaRoute2Info selectedRoute = getSelectedRoute();
|
||||
if (selectedRoute != null) {
|
||||
routes.add(selectedRoute);
|
||||
routeIds.add(selectedRoute.getId());
|
||||
}
|
||||
|
||||
for (BluetoothRouteInfo btRoute : mBluetoothRoutes.values()) {
|
||||
// A pair of hearing aid devices or the same hardware address
|
||||
// A pair of hearing aid devices or having the same hardware address
|
||||
if (routeIds.contains(btRoute.route.getId())) {
|
||||
continue;
|
||||
}
|
||||
@@ -225,13 +238,20 @@ class BluetoothRouteProvider {
|
||||
return false;
|
||||
}
|
||||
mVolumeMap.put(routeType, volume);
|
||||
if (mSelectedRoute == null || mSelectedRoute.route.getType() != routeType) {
|
||||
return true;
|
||||
|
||||
boolean shouldNotify = false;
|
||||
for (BluetoothRouteInfo btRoute : mActiveRoutes) {
|
||||
if (btRoute.route.getType() != routeType) {
|
||||
continue;
|
||||
}
|
||||
btRoute.route = new MediaRoute2Info.Builder(btRoute.route)
|
||||
.setVolume(volume)
|
||||
.build();
|
||||
shouldNotify = true;
|
||||
}
|
||||
if (shouldNotify) {
|
||||
notifyBluetoothRoutesUpdated();
|
||||
}
|
||||
mSelectedRoute.route = new MediaRoute2Info.Builder(mSelectedRoute.route)
|
||||
.setVolume(volume)
|
||||
.build();
|
||||
notifyBluetoothRoutesUpdated();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -297,6 +317,53 @@ class BluetoothRouteProvider {
|
||||
btRoute.route = builder.build();
|
||||
}
|
||||
|
||||
private void clearActiveRoutes() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Clearing active routes");
|
||||
}
|
||||
for (BluetoothRouteInfo btRoute : mActiveRoutes) {
|
||||
setRouteConnectionState(btRoute, STATE_DISCONNECTED);
|
||||
}
|
||||
mActiveRoutes.clear();
|
||||
}
|
||||
|
||||
private void addActiveRoute(BluetoothRouteInfo btRoute) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Adding active route: " + btRoute.route);
|
||||
}
|
||||
if (btRoute == null || mActiveRoutes.contains(btRoute)) {
|
||||
return;
|
||||
}
|
||||
setRouteConnectionState(btRoute, STATE_CONNECTED);
|
||||
mActiveRoutes.add(btRoute);
|
||||
}
|
||||
|
||||
private void removeActiveRoute(BluetoothRouteInfo btRoute) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Removing active route: " + btRoute.route);
|
||||
}
|
||||
if (mActiveRoutes.remove(btRoute)) {
|
||||
setRouteConnectionState(btRoute, STATE_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
private void findAndSetActiveHearingAidDevices() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Setting active hearing aid devices");
|
||||
}
|
||||
|
||||
BluetoothHearingAid hearingAidProfile = mHearingAidProfile;
|
||||
if (hearingAidProfile == null) {
|
||||
return;
|
||||
}
|
||||
List<BluetoothDevice> activeDevices = hearingAidProfile.getActiveDevices();
|
||||
for (BluetoothRouteInfo btRoute : mBluetoothRoutes.values()) {
|
||||
if (activeDevices.contains(btRoute.btDevice)) {
|
||||
addActiveRoute(btRoute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface BluetoothRoutesUpdatedListener {
|
||||
void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes);
|
||||
}
|
||||
@@ -333,7 +400,6 @@ class BluetoothRouteProvider {
|
||||
default:
|
||||
return;
|
||||
}
|
||||
//TODO(b/157708273): Handle two active devices in the binaural case.
|
||||
for (BluetoothDevice device : proxy.getConnectedDevices()) {
|
||||
BluetoothRouteInfo btRoute = mBluetoothRoutes.get(device.getAddress());
|
||||
if (btRoute == null) {
|
||||
@@ -341,9 +407,7 @@ class BluetoothRouteProvider {
|
||||
mBluetoothRoutes.put(device.getAddress(), btRoute);
|
||||
}
|
||||
if (activeDevices.contains(device)) {
|
||||
mSelectedRoute = btRoute;
|
||||
setRouteConnectionState(mSelectedRoute,
|
||||
MediaRoute2Info.CONNECTION_STATE_CONNECTED);
|
||||
addActiveRoute(btRoute);
|
||||
}
|
||||
}
|
||||
notifyBluetoothRoutesUpdated();
|
||||
@@ -395,26 +459,23 @@ class BluetoothRouteProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private class DeviceStateChangedRecevier implements BluetoothEventReceiver {
|
||||
private class DeviceStateChangedReceiver implements BluetoothEventReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
|
||||
switch (intent.getAction()) {
|
||||
case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
|
||||
case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
|
||||
if (mSelectedRoute == null
|
||||
|| !mSelectedRoute.btDevice.equals(device)) {
|
||||
if (mSelectedRoute != null) {
|
||||
setRouteConnectionState(mSelectedRoute,
|
||||
MediaRoute2Info.CONNECTION_STATE_DISCONNECTED);
|
||||
}
|
||||
mSelectedRoute = (device == null) ? null
|
||||
: mBluetoothRoutes.get(device.getAddress());
|
||||
if (mSelectedRoute != null) {
|
||||
setRouteConnectionState(mSelectedRoute,
|
||||
MediaRoute2Info.CONNECTION_STATE_CONNECTED);
|
||||
}
|
||||
notifyBluetoothRoutesUpdated();
|
||||
clearActiveRoutes();
|
||||
if (device != null) {
|
||||
addActiveRoute(mBluetoothRoutes.get(device.getAddress()));
|
||||
}
|
||||
notifyBluetoothRoutesUpdated();
|
||||
break;
|
||||
case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
|
||||
clearActiveDevices();
|
||||
if (device != null) {
|
||||
findAndSetActiveHearingAidDevices();
|
||||
}
|
||||
notifyBluetoothRoutesUpdated();
|
||||
break;
|
||||
case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
|
||||
handleConnectionStateChanged(BluetoothProfile.A2DP, intent, device);
|
||||
@@ -444,10 +505,7 @@ class BluetoothRouteProvider {
|
||||
if (btRoute != null) {
|
||||
btRoute.connectedProfiles.delete(profile);
|
||||
if (btRoute.connectedProfiles.size() == 0) {
|
||||
mBluetoothRoutes.remove(device.getAddress());
|
||||
if (mSelectedRoute != null && mSelectedRoute.btDevice.equals(device)) {
|
||||
mSelectedRoute = null;
|
||||
}
|
||||
removeActiveRoute(mBluetoothRoutes.remove(device.getAddress()));
|
||||
notifyBluetoothRoutesUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user