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

Commit 8f8a30fd authored by Sungsoo Lim's avatar Sungsoo Lim Committed by Gerrit Code Review
Browse files

Merge "Handle hearing aid device group in ActiveDeviceManager"

parents 4862bc06 0d072f50
Loading
Loading
Loading
Loading
+48 −10
Original line number Original line Diff line number Diff line
@@ -38,6 +38,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.util.ArraySet;
import android.util.Log;
import android.util.Log;


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


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


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


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


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


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


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


    @VisibleForTesting
    @VisibleForTesting
@@ -898,6 +928,14 @@ class ActiveDeviceManager {
        return mLeAudioActiveDevice;
        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.
     * Called when a wired audio device is connected.
     * It might be called multiple times each time 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 Original line Diff line number Diff line
@@ -567,7 +567,7 @@ public class HearingAidService extends ProfileService {
    }
    }


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


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

    private static final int TIMEOUT_MS = 1000;
    private static final int TIMEOUT_MS = 1000;


    @Mock private AdapterService mAdapterService;
    @Mock private AdapterService mAdapterService;
@@ -130,6 +132,12 @@ public class ActiveDeviceManagerTest {
        when(mHearingAidService.setActiveDevice(any())).thenReturn(true);
        when(mHearingAidService.setActiveDevice(any())).thenReturn(true);
        when(mLeAudioService.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 -> {
        when(mA2dpService.getFallbackDevice()).thenAnswer(invocation -> {
            if (!mDeviceConnectionStack.isEmpty() && Objects.equals(mA2dpDevice,
            if (!mDeviceConnectionStack.isEmpty() && Objects.equals(mA2dpDevice,
                    mDeviceConnectionStack.get(mDeviceConnectionStack.size() - 1))) {
                    mDeviceConnectionStack.get(mDeviceConnectionStack.size() - 1))) {
@@ -329,6 +337,25 @@ public class ActiveDeviceManagerTest {
        verify(mHeadsetService, never()).setActiveDevice(mHeadsetDevice);
        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.
     * 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()
        // Don't call mA2dpService.setActiveDevice()
        verify(mA2dpService, never()).setActiveDevice(mA2dpHeadsetDevice);
        verify(mA2dpService, never()).setActiveDevice(mA2dpHeadsetDevice);
        Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getA2dpActiveDevice());
        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()
        // Don't call mHeadsetService.setActiveDevice()
        verify(mHeadsetService, never()).setActiveDevice(mA2dpHeadsetDevice);
        verify(mHeadsetService, never()).setActiveDevice(mA2dpHeadsetDevice);
        Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getHfpActiveDevice());
        Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getHfpActiveDevice());
        Assert.assertEquals(null, mActiveDeviceManager.getHearingAidActiveDevice());
        Assert.assertTrue(mActiveDeviceManager.getHearingAidActiveDevices().isEmpty());
    }
    }


    /**
    /**
@@ -594,6 +621,13 @@ public class ActiveDeviceManagerTest {
        hearingAidConnected(mHearingAidDevice);
        hearingAidConnected(mHearingAidDevice);
        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(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);
        hearingAidConnected(mSecondaryAudioDevice);
        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice);
        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice);