Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7cc3651 authored by Kyunglyul Hyun's avatar Kyunglyul Hyun Committed by Automerger Merge Worker
Browse files

Merge "Handle multiple active bluetooth devices" into rvc-dev am: 4b647272...

Merge "Handle multiple active bluetooth devices" into rvc-dev am: 4b647272 am: 4d65a4c3 am: 1597dfcf

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11947520

Change-Id: Iacfeee00871987b2c37845e8a4be93a5ea7b49bb
parents cf0a496b 1597dfcf
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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());
+92 −34
Original line number Diff line number Diff line
@@ -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;
            }
        mSelectedRoute.route = new MediaRoute2Info.Builder(mSelectedRoute.route)
            btRoute.route = new MediaRoute2Info.Builder(btRoute.route)
                    .setVolume(volume)
                    .build();
            shouldNotify = true;
        }
        if (shouldNotify) {
            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);
                    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();
                    }
                }