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

Commit 0d072f50 authored by Sungsoo Lim's avatar Sungsoo Lim
Browse files

Handle hearing aid device group in ActiveDeviceManager

Bug: 262669347
Test: atest BluetoothInstrumentationTests
Change-Id: I46c13664fbf93267e8b4d0d1c842eb2ed63d7c5a
parent 8d6d4f23
Loading
Loading
Loading
Loading
+48 −10
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.ArraySet;
import android.util.Log;

import com.android.bluetooth.a2dp.A2dpService;
@@ -50,6 +51,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * The active device manager is responsible for keeping track of the
@@ -140,7 +142,7 @@ class ActiveDeviceManager {
    private List<BluetoothDevice> mPendingLeHearingAidActiveDevice = new ArrayList<>();
    private BluetoothDevice mA2dpActiveDevice = null;
    private BluetoothDevice mHfpActiveDevice = null;
    private BluetoothDevice mHearingAidActiveDevice = null;
    private final Set<BluetoothDevice> mHearingAidActiveDevices = new ArraySet<>();
    private BluetoothDevice mLeAudioActiveDevice = null;
    private BluetoothDevice mLeHearingAidActiveDevice = null;

@@ -247,7 +249,8 @@ class ActiveDeviceManager {
                            break;      // The device is already connected
                        }
                        mA2dpConnectedDevices.add(device);
                        if (mHearingAidActiveDevice == null && mLeHearingAidActiveDevice == null) {
                        if (mHearingAidActiveDevices.isEmpty()
                                && mLeHearingAidActiveDevice == null) {
                            // New connected device: select it as active
                            setA2dpActiveDevice(device);
                            setLeAudioActiveDevice(null);
@@ -313,7 +316,8 @@ class ActiveDeviceManager {
                            break;      // The device is already connected
                        }
                        mHfpConnectedDevices.add(device);
                        if (mHearingAidActiveDevice == null && mLeHearingAidActiveDevice == null) {
                        if (mHearingAidActiveDevices.isEmpty()
                                && mLeHearingAidActiveDevice == null) {
                            // New connected device: select it as active
                            setHfpActiveDevice(device);
                            setLeAudioActiveDevice(null);
@@ -392,7 +396,8 @@ class ActiveDeviceManager {
                                    + "_CHANGED): device " + device + " disconnected");
                        }
                        mHearingAidConnectedDevices.remove(device);
                        if (Objects.equals(mHearingAidActiveDevice, device)) {
                        if (mHearingAidActiveDevices.remove(device)
                                && mHearingAidActiveDevices.isEmpty()) {
                            if (mHearingAidConnectedDevices.isEmpty()) {
                                setHearingAidActiveDevice(null);
                            }
@@ -411,7 +416,17 @@ class ActiveDeviceManager {
                                + "device= " + device);
                    }
                    // Just assign locally the new value
                    mHearingAidActiveDevice = device;
                    final HearingAidService hearingAidService = mFactory.getHearingAidService();
                    if (hearingAidService != null) {
                        long hiSyncId = hearingAidService.getHiSyncId(device);
                        if (getHearingAidActiveHiSyncId() == hiSyncId) {
                            mHearingAidActiveDevices.add(device);
                        } else {
                            mHearingAidActiveDevices.clear();
                            mHearingAidActiveDevices.addAll(
                                    hearingAidService.getConnectedPeerDevices(hiSyncId));
                        }
                    }
                    if (device != null) {
                        setA2dpActiveDevice(null);
                        setHfpActiveDevice(null);
@@ -440,7 +455,8 @@ class ActiveDeviceManager {
                            break;      // The device is already connected
                        }
                        mLeAudioConnectedDevices.add(device);
                        if (mHearingAidActiveDevice == null && mLeHearingAidActiveDevice == null
                        if (mHearingAidActiveDevices.isEmpty()
                                && mLeHearingAidActiveDevice == null
                                && mPendingLeHearingAidActiveDevice.isEmpty()) {
                            // New connected device: select it as active
                            setLeAudioActiveDevice(device);
@@ -708,10 +724,24 @@ class ActiveDeviceManager {
        if (hearingAidService == null) {
            return;
        }

        if (device == null) {
            hearingAidService.setActiveDevice(null);
            mHearingAidActiveDevices.clear();
            return;
        }

        long hiSyncId = hearingAidService.getHiSyncId(device);
        if (getHearingAidActiveHiSyncId() == hiSyncId) {
            mHearingAidActiveDevices.add(device);
            return;
        }

        if (!hearingAidService.setActiveDevice(device)) {
            return;
        }
        mHearingAidActiveDevice = device;
        mHearingAidActiveDevices.clear();
        mHearingAidActiveDevices.addAll(hearingAidService.getConnectedPeerDevices(hiSyncId));
    }

    private void setLeAudioActiveDevice(BluetoothDevice device) {
@@ -863,7 +893,7 @@ class ActiveDeviceManager {
        mHfpActiveDevice = null;

        mHearingAidConnectedDevices.clear();
        mHearingAidActiveDevice = null;
        mHearingAidActiveDevices.clear();

        mLeAudioConnectedDevices.clear();
        mLeAudioActiveDevice = null;
@@ -889,8 +919,8 @@ class ActiveDeviceManager {
    }

    @VisibleForTesting
    BluetoothDevice getHearingAidActiveDevice() {
        return mHearingAidActiveDevice;
    Set<BluetoothDevice> getHearingAidActiveDevices() {
        return mHearingAidActiveDevices;
    }

    @VisibleForTesting
@@ -898,6 +928,14 @@ class ActiveDeviceManager {
        return mLeAudioActiveDevice;
    }

    long getHearingAidActiveHiSyncId() {
        final HearingAidService hearingAidService = mFactory.getHearingAidService();
        if (hearingAidService != null && !mHearingAidActiveDevices.isEmpty()) {
            return hearingAidService.getHiSyncId(mHearingAidActiveDevices.iterator().next());
        }
        return BluetoothHearingAid.HI_SYNC_ID_INVALID;
    }

    /**
     * Called when a wired audio device is connected.
     * It might be called multiple times each time a wired audio device is connected.
+2 −2
Original line number Diff line number Diff line
@@ -567,7 +567,7 @@ public class HearingAidService extends ProfileService {
    }

    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
    long getHiSyncId(BluetoothDevice device) {
    public long getHiSyncId(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
                "Need BLUETOOTH_PRIVILEGED permission");
        if (device == null) {
@@ -863,7 +863,7 @@ public class HearingAidService extends ProfileService {
    }

    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
    private List<BluetoothDevice> getConnectedPeerDevices(long hiSyncId) {
    public List<BluetoothDevice> getConnectedPeerDevices(long hiSyncId) {
        List<BluetoothDevice> result = new ArrayList<>();
        for (BluetoothDevice peerDevice : getConnectedDevices()) {
            if (getHiSyncId(peerDevice) == hiSyncId) {
+36 −2
Original line number Diff line number Diff line
@@ -77,6 +77,8 @@ public class ActiveDeviceManagerTest {
    private ArrayList<BluetoothDevice> mDeviceConnectionStack;
    private BluetoothDevice mMostRecentDevice;
    private ActiveDeviceManager mActiveDeviceManager;
    private long mHearingAidHiSyncId = 1010;

    private static final int TIMEOUT_MS = 1000;

    @Mock private AdapterService mAdapterService;
@@ -130,6 +132,12 @@ public class ActiveDeviceManagerTest {
        when(mHearingAidService.setActiveDevice(any())).thenReturn(true);
        when(mLeAudioService.setActiveDevice(any())).thenReturn(true);

        List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>();
        connectedHearingAidDevices.add(mHearingAidDevice);
        when(mHearingAidService.getHiSyncId(mHearingAidDevice)).thenReturn(mHearingAidHiSyncId);
        when(mHearingAidService.getConnectedPeerDevices(mHearingAidHiSyncId))
                .thenReturn(connectedHearingAidDevices);

        when(mA2dpService.getFallbackDevice()).thenAnswer(invocation -> {
            if (!mDeviceConnectionStack.isEmpty() && Objects.equals(mA2dpDevice,
                    mDeviceConnectionStack.get(mDeviceConnectionStack.size() - 1))) {
@@ -329,6 +337,25 @@ public class ActiveDeviceManagerTest {
        verify(mHeadsetService, never()).setActiveDevice(mHeadsetDevice);
    }

    @Test
    public void twoHearingAidDevicesConnected_WithTheSameHiSyncId() {
        Assume.assumeTrue("Ignore test when HearingAidService is not enabled",
                HearingAidService.isEnabled());

        List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>();
        connectedHearingAidDevices.add(mHearingAidDevice);
        connectedHearingAidDevices.add(mSecondaryAudioDevice);
        when(mHearingAidService.getHiSyncId(mSecondaryAudioDevice))
                .thenReturn(mHearingAidHiSyncId);
        when(mHearingAidService.getConnectedPeerDevices(mHearingAidHiSyncId))
                .thenReturn(connectedHearingAidDevices);

        hearingAidConnected(mHearingAidDevice);
        hearingAidConnected(mSecondaryAudioDevice);
        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice);
        verify(mHearingAidService, never()).setActiveDevice(mSecondaryAudioDevice);
    }

    /**
     * A combo (A2DP + Headset) device is connected. Then a Hearing Aid is connected.
     */
@@ -381,7 +408,7 @@ public class ActiveDeviceManagerTest {
        // Don't call mA2dpService.setActiveDevice()
        verify(mA2dpService, never()).setActiveDevice(mA2dpHeadsetDevice);
        Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getA2dpActiveDevice());
        Assert.assertEquals(null, mActiveDeviceManager.getHearingAidActiveDevice());
        Assert.assertTrue(mActiveDeviceManager.getHearingAidActiveDevices().isEmpty());
    }

    /**
@@ -401,7 +428,7 @@ public class ActiveDeviceManagerTest {
        // Don't call mHeadsetService.setActiveDevice()
        verify(mHeadsetService, never()).setActiveDevice(mA2dpHeadsetDevice);
        Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getHfpActiveDevice());
        Assert.assertEquals(null, mActiveDeviceManager.getHearingAidActiveDevice());
        Assert.assertTrue(mActiveDeviceManager.getHearingAidActiveDevices().isEmpty());
    }

    /**
@@ -594,6 +621,13 @@ public class ActiveDeviceManagerTest {
        hearingAidConnected(mHearingAidDevice);
        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice);

        List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>();
        connectedHearingAidDevices.add(mSecondaryAudioDevice);
        when(mHearingAidService.getHiSyncId(mSecondaryAudioDevice))
                .thenReturn(mHearingAidHiSyncId + 1);
        when(mHearingAidService.getConnectedPeerDevices(mHearingAidHiSyncId + 1))
                .thenReturn(connectedHearingAidDevices);

        hearingAidConnected(mSecondaryAudioDevice);
        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice);