Merge "Handle multiple active bluetooth devices" into rvc-dev am: 4b6472722e am: 8444f9f5b1
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11947520 Change-Id: I4fc6cfb0dc06025070c497a09014adb1e1bc6a7e
This commit is contained in:
@@ -344,6 +344,8 @@ public final class MediaRouter2Manager {
|
|||||||
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
|
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
|
||||||
Objects.requireNonNull(route, "route must not be null");
|
Objects.requireNonNull(route, "route must not be null");
|
||||||
|
|
||||||
|
Log.v(TAG, "Transferring routing session. session= " + sessionInfo + ", route=" + route);
|
||||||
|
|
||||||
synchronized (mRoutesLock) {
|
synchronized (mRoutesLock) {
|
||||||
if (!mRoutes.containsKey(route.getId())) {
|
if (!mRoutes.containsKey(route.getId())) {
|
||||||
Log.w(TAG, "transfer: Ignoring an unknown route id=" + route.getId());
|
Log.w(TAG, "transfer: Ignoring an unknown route id=" + route.getId());
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package com.android.server.media;
|
package com.android.server.media;
|
||||||
|
|
||||||
import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_AUDIO;
|
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.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
@@ -33,6 +35,7 @@ import android.media.AudioManager;
|
|||||||
import android.media.AudioSystem;
|
import android.media.AudioSystem;
|
||||||
import android.media.MediaRoute2Info;
|
import android.media.MediaRoute2Info;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseBooleanArray;
|
import android.util.SparseBooleanArray;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
@@ -48,6 +51,8 @@ import java.util.Objects;
|
|||||||
|
|
||||||
class BluetoothRouteProvider {
|
class BluetoothRouteProvider {
|
||||||
private static final String TAG = "BTRouteProvider";
|
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 final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
|
||||||
private static BluetoothRouteProvider sInstance;
|
private static BluetoothRouteProvider sInstance;
|
||||||
|
|
||||||
@@ -55,7 +60,7 @@ class BluetoothRouteProvider {
|
|||||||
// Maps hardware address to BluetoothRouteInfo
|
// Maps hardware address to BluetoothRouteInfo
|
||||||
final Map<String, BluetoothRouteInfo> mBluetoothRoutes = new HashMap<>();
|
final Map<String, BluetoothRouteInfo> mBluetoothRoutes = new HashMap<>();
|
||||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||||
BluetoothRouteInfo mSelectedRoute = null;
|
final List<BluetoothRouteInfo> mActiveRoutes = new ArrayList<>();
|
||||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||||
BluetoothA2dp mA2dpProfile;
|
BluetoothA2dp mA2dpProfile;
|
||||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||||
@@ -104,7 +109,7 @@ class BluetoothRouteProvider {
|
|||||||
// Bluetooth on/off broadcasts
|
// Bluetooth on/off broadcasts
|
||||||
addEventReceiver(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedReceiver());
|
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_ACTIVE_DEVICE_CHANGED, deviceStateChangedReceiver);
|
||||||
addEventReceiver(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED, deviceStateChangedReceiver);
|
addEventReceiver(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED, deviceStateChangedReceiver);
|
||||||
addEventReceiver(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED,
|
addEventReceiver(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED,
|
||||||
@@ -168,14 +173,16 @@ class BluetoothRouteProvider {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
MediaRoute2Info getSelectedRoute() {
|
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
|
@NonNull
|
||||||
List<MediaRoute2Info> getTransferableRoutes() {
|
List<MediaRoute2Info> getTransferableRoutes() {
|
||||||
List<MediaRoute2Info> routes = getAllBluetoothRoutes();
|
List<MediaRoute2Info> routes = getAllBluetoothRoutes();
|
||||||
if (mSelectedRoute != null) {
|
for (BluetoothRouteInfo btRoute : mActiveRoutes) {
|
||||||
routes.remove(mSelectedRoute.route);
|
routes.remove(btRoute.route);
|
||||||
}
|
}
|
||||||
return routes;
|
return routes;
|
||||||
}
|
}
|
||||||
@@ -185,8 +192,14 @@ class BluetoothRouteProvider {
|
|||||||
List<MediaRoute2Info> routes = new ArrayList<>();
|
List<MediaRoute2Info> routes = new ArrayList<>();
|
||||||
List<String> routeIds = 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()) {
|
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())) {
|
if (routeIds.contains(btRoute.route.getId())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -225,13 +238,20 @@ class BluetoothRouteProvider {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mVolumeMap.put(routeType, volume);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,6 +317,53 @@ class BluetoothRouteProvider {
|
|||||||
btRoute.route = builder.build();
|
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 {
|
interface BluetoothRoutesUpdatedListener {
|
||||||
void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes);
|
void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes);
|
||||||
}
|
}
|
||||||
@@ -333,7 +400,6 @@ class BluetoothRouteProvider {
|
|||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//TODO(b/157708273): Handle two active devices in the binaural case.
|
|
||||||
for (BluetoothDevice device : proxy.getConnectedDevices()) {
|
for (BluetoothDevice device : proxy.getConnectedDevices()) {
|
||||||
BluetoothRouteInfo btRoute = mBluetoothRoutes.get(device.getAddress());
|
BluetoothRouteInfo btRoute = mBluetoothRoutes.get(device.getAddress());
|
||||||
if (btRoute == null) {
|
if (btRoute == null) {
|
||||||
@@ -341,9 +407,7 @@ class BluetoothRouteProvider {
|
|||||||
mBluetoothRoutes.put(device.getAddress(), btRoute);
|
mBluetoothRoutes.put(device.getAddress(), btRoute);
|
||||||
}
|
}
|
||||||
if (activeDevices.contains(device)) {
|
if (activeDevices.contains(device)) {
|
||||||
mSelectedRoute = btRoute;
|
addActiveRoute(btRoute);
|
||||||
setRouteConnectionState(mSelectedRoute,
|
|
||||||
MediaRoute2Info.CONNECTION_STATE_CONNECTED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notifyBluetoothRoutesUpdated();
|
notifyBluetoothRoutesUpdated();
|
||||||
@@ -395,26 +459,23 @@ class BluetoothRouteProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DeviceStateChangedRecevier implements BluetoothEventReceiver {
|
private class DeviceStateChangedReceiver implements BluetoothEventReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
|
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
|
||||||
switch (intent.getAction()) {
|
switch (intent.getAction()) {
|
||||||
case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
|
case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
|
||||||
case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
|
clearActiveRoutes();
|
||||||
if (mSelectedRoute == null
|
if (device != null) {
|
||||||
|| !mSelectedRoute.btDevice.equals(device)) {
|
addActiveRoute(mBluetoothRoutes.get(device.getAddress()));
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
notifyBluetoothRoutesUpdated();
|
||||||
|
break;
|
||||||
|
case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
|
||||||
|
clearActiveDevices();
|
||||||
|
if (device != null) {
|
||||||
|
findAndSetActiveHearingAidDevices();
|
||||||
|
}
|
||||||
|
notifyBluetoothRoutesUpdated();
|
||||||
break;
|
break;
|
||||||
case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
|
case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
|
||||||
handleConnectionStateChanged(BluetoothProfile.A2DP, intent, device);
|
handleConnectionStateChanged(BluetoothProfile.A2DP, intent, device);
|
||||||
@@ -444,10 +505,7 @@ class BluetoothRouteProvider {
|
|||||||
if (btRoute != null) {
|
if (btRoute != null) {
|
||||||
btRoute.connectedProfiles.delete(profile);
|
btRoute.connectedProfiles.delete(profile);
|
||||||
if (btRoute.connectedProfiles.size() == 0) {
|
if (btRoute.connectedProfiles.size() == 0) {
|
||||||
mBluetoothRoutes.remove(device.getAddress());
|
removeActiveRoute(mBluetoothRoutes.remove(device.getAddress()));
|
||||||
if (mSelectedRoute != null && mSelectedRoute.btDevice.equals(device)) {
|
|
||||||
mSelectedRoute = null;
|
|
||||||
}
|
|
||||||
notifyBluetoothRoutesUpdated();
|
notifyBluetoothRoutesUpdated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user