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

Commit 28ba74c4 authored by Charlie Boutier's avatar Charlie Boutier
Browse files

Hearing Aid: Connect route when right HA is connected first

Allow the hearings aid to properly connect to the audio route when the
right hearing aid is connected first.

Add some Unit tests to cover this case.

Bug: 308045084
Bug: 306075809
Test: atest TelecomUnitTests:com.android.server.telecom.tests.BluetoothRouteManagerTest
Test: manual tests with HAs
Test: manual tests with a Bluetooth speaker
Change-Id: I0e59a5f9d50ca69c36d7dad0fd7d9ef44a751829
parent eb6d1f4b
Loading
Loading
Loading
Loading
+36 −7
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -134,7 +135,8 @@ public class BluetoothRouteManager extends StateMachine {
        @Override
        public void enter() {
            BluetoothDevice erroneouslyConnectedDevice = getBluetoothAudioConnectedDevice();
            if (erroneouslyConnectedDevice != null) {
            if (erroneouslyConnectedDevice != null &&
                !erroneouslyConnectedDevice.equals(mHearingAidActiveDeviceCache)) {
                Log.w(LOG_TAG, "Entering AudioOff state but device %s appears to be connected. " +
                        "Switching to audio-on state for that device.", erroneouslyConnectedDevice);
                // change this to just transition to the new audio on state
@@ -252,6 +254,27 @@ public class BluetoothRouteManager extends StateMachine {
            SomeArgs args = (SomeArgs) msg.obj;
            String address = (String) args.arg2;
            boolean switchingBtDevices = !Objects.equals(mDeviceAddress, address);

            if (switchingBtDevices == true) { // check if it is an hearing aid pair
                BluetoothAdapter bluetoothAdapter = mDeviceManager.getBluetoothAdapter();
                if (bluetoothAdapter != null) {
                    List<BluetoothDevice> activeHearingAids =
                      bluetoothAdapter.getActiveDevices(BluetoothProfile.HEARING_AID);
                    for (BluetoothDevice hearingAid : activeHearingAids) {
                        if (hearingAid != null) {
                            String hearingAidAddress = hearingAid.getAddress();
                            if (hearingAidAddress != null) {
                                if (hearingAidAddress.equals(address) ||
                                    hearingAidAddress.equals(mDeviceAddress)) {
                                    switchingBtDevices = false;
                                    break;
                                }
                            }
                        }
                    }

                }
            }
            try {
                switch (msg.what) {
                    case NEW_DEVICE_CONNECTED:
@@ -863,8 +886,13 @@ public class BluetoothRouteManager extends StateMachine {
                : mDeviceManager.isHearingAidSetAsCommunicationDevice();
        if (bluetoothHearingAid != null) {
            if (isHearingAidSetForCommunication) {
                for (BluetoothDevice device : bluetoothAdapter.getActiveDevices(
                        BluetoothProfile.HEARING_AID)) {
                List<BluetoothDevice> hearingAidsActiveDevices = bluetoothAdapter.getActiveDevices(
                        BluetoothProfile.HEARING_AID);
                if (hearingAidsActiveDevices.contains(mHearingAidActiveDeviceCache)) {
                    hearingAidActiveDevice = mHearingAidActiveDeviceCache;
                    activeDevices++;
                } else {
                    for (BluetoothDevice device : hearingAidsActiveDevices) {
                        if (device != null) {
                            hearingAidActiveDevice = device;
                            activeDevices++;
@@ -873,6 +901,7 @@ public class BluetoothRouteManager extends StateMachine {
                    }
                }
            }
        }

        boolean isLeAudioSetForCommunication =
                mFeatureFlags.callAudioCommunicationDeviceRefactor()
+75 −11
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -37,6 +38,8 @@ import android.os.Parcel;
import android.telecom.Log;
import android.test.suitebuilder.annotation.SmallTest;

import android.media.AudioDeviceInfo;

import com.android.internal.os.SomeArgs;
import com.android.server.telecom.CallAudioCommunicationDeviceTracker;
import com.android.server.telecom.TelecomSystem;
@@ -62,7 +65,14 @@ public class BluetoothRouteManagerTest extends TelecomTestCase {
    static final BluetoothDevice DEVICE1 = makeBluetoothDevice("00:00:00:00:00:01");
    static final BluetoothDevice DEVICE2 = makeBluetoothDevice("00:00:00:00:00:02");
    static final BluetoothDevice DEVICE3 = makeBluetoothDevice("00:00:00:00:00:03");
    static final BluetoothDevice HEARING_AID_DEVICE = makeBluetoothDevice("00:00:00:00:00:04");
    static final BluetoothDevice HEARING_AID_DEVICE_LEFT = makeBluetoothDevice("CA:FE:DE:CA:00:01");
    static final BluetoothDevice HEARING_AID_DEVICE_RIGHT =
      makeBluetoothDevice("CA:FE:DE:CA:00:02");
    // See HearingAidService#getActiveDevices
    // Note: It is really important that the left HA is the first one. The left HA is always
    // in the first index (0) and the right one in the second index (1).
    static final BluetoothDevice[] HEARING_AIDS =
      new BluetoothDevice[]{HEARING_AID_DEVICE_LEFT, HEARING_AID_DEVICE_RIGHT};

    @Mock private BluetoothAdapter mBluetoothAdapter;
    @Mock private BluetoothDeviceManager mDeviceManager;
@@ -85,6 +95,59 @@ public class BluetoothRouteManagerTest extends TelecomTestCase {
        super.tearDown();
    }

    @SmallTest
    @Test
    public void testConnectLeftHearingAidWhenLeftIsActive() {
        BluetoothRouteManager sm = setupStateMachine(
                BluetoothRouteManager.AUDIO_OFF_STATE_NAME, HEARING_AID_DEVICE_LEFT);
        sm.onActiveDeviceChanged(HEARING_AID_DEVICE_LEFT,
            BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID);
        when(mDeviceManager.connectAudio(anyString(), anyBoolean())).thenReturn(true);
        when(mDeviceManager.isHearingAidSetAsCommunicationDevice()).thenReturn(true);

        setupConnectedDevices(null, HEARING_AIDS, null, null, HEARING_AIDS, null);
        when(mBluetoothHeadset.getAudioState(nullable(BluetoothDevice.class)))
          .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);

        executeRoutingAction(sm,
            BluetoothRouteManager.NEW_DEVICE_CONNECTED, HEARING_AID_DEVICE_LEFT.getAddress());

        executeRoutingAction(sm,
            BluetoothRouteManager.CONNECT_BT, HEARING_AID_DEVICE_LEFT.getAddress());

        assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
            + ":" + HEARING_AID_DEVICE_LEFT.getAddress(), sm.getCurrentState().getName());

        sm.quitNow();
    }

    @SmallTest
    @Test
    public void testConnectRightHearingAidWhenLeftIsActive() {
        BluetoothRouteManager sm = setupStateMachine(
                BluetoothRouteManager.AUDIO_OFF_STATE_NAME, HEARING_AID_DEVICE_RIGHT);
        sm.onActiveDeviceChanged(HEARING_AID_DEVICE_LEFT,
            BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID);
        when(mDeviceManager.connectAudio(anyString(), anyBoolean())).thenReturn(true);
        when(mDeviceManager.isHearingAidSetAsCommunicationDevice()).thenReturn(true);


        setupConnectedDevices(null, HEARING_AIDS, null, null, HEARING_AIDS, null);
        when(mBluetoothHeadset.getAudioState(nullable(BluetoothDevice.class)))
          .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);

        executeRoutingAction(sm,
            BluetoothRouteManager.NEW_DEVICE_CONNECTED, HEARING_AID_DEVICE_LEFT.getAddress());

        executeRoutingAction(sm,
            BluetoothRouteManager.CONNECT_BT, HEARING_AID_DEVICE_LEFT.getAddress());

        assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
            + ":" + HEARING_AID_DEVICE_LEFT.getAddress(), sm.getCurrentState().getName());

        sm.quitNow();
    }

    @SmallTest
    @Test
    public void testConnectBtRetryWhileNotConnected() {
@@ -113,15 +176,15 @@ public class BluetoothRouteManagerTest extends TelecomTestCase {
        BluetoothRouteManager sm = setupStateMachine(
                BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1);
        setupConnectedDevices(new BluetoothDevice[]{DEVICE1},
                new BluetoothDevice[]{HEARING_AID_DEVICE}, new BluetoothDevice[]{DEVICE2},
                DEVICE1, HEARING_AID_DEVICE, DEVICE2);
                HEARING_AIDS, new BluetoothDevice[]{DEVICE2},
                DEVICE1,  HEARING_AIDS, DEVICE2);
        sm.onActiveDeviceChanged(DEVICE1, BluetoothDeviceManager.DEVICE_TYPE_HEADSET);
        sm.onActiveDeviceChanged(DEVICE2, BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO);
        sm.onActiveDeviceChanged(HEARING_AID_DEVICE,
        sm.onActiveDeviceChanged(HEARING_AID_DEVICE_LEFT,
                BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID);
        executeRoutingAction(sm, BluetoothRouteManager.BT_AUDIO_LOST, DEVICE1.getAddress());

        verifyConnectionAttempt(HEARING_AID_DEVICE, 0);
        verifyConnectionAttempt(HEARING_AID_DEVICE_LEFT, 0);
        verifyConnectionAttempt(DEVICE1, 0);
        verifyConnectionAttempt(DEVICE2, 0);
        assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
@@ -176,11 +239,11 @@ public class BluetoothRouteManagerTest extends TelecomTestCase {
    @Test
    public void testSkipInactiveBtDeviceWhenEvaluateActualState() {
        BluetoothRouteManager sm = setupStateMachine(
                BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, HEARING_AID_DEVICE);
        setupConnectedDevices(null, new BluetoothDevice[]{HEARING_AID_DEVICE},
                null, null, HEARING_AID_DEVICE, null);
                BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, HEARING_AID_DEVICE_LEFT);
        setupConnectedDevices(null, HEARING_AIDS,
                null, null, HEARING_AIDS, null);
        executeRoutingAction(sm, BluetoothRouteManager.BT_AUDIO_LOST,
                HEARING_AID_DEVICE.getAddress());
                HEARING_AID_DEVICE_LEFT.getAddress());
        assertEquals(BluetoothRouteManager.AUDIO_OFF_STATE_NAME, sm.getCurrentState().getName());
        sm.quitNow();
    }
@@ -200,10 +263,11 @@ public class BluetoothRouteManagerTest extends TelecomTestCase {

    private void setupConnectedDevices(BluetoothDevice[] hfpDevices,
            BluetoothDevice[] hearingAidDevices, BluetoothDevice[] leAudioDevices,
            BluetoothDevice hfpActiveDevice, BluetoothDevice hearingAidActiveDevice,
            BluetoothDevice hfpActiveDevice, BluetoothDevice[] hearingAidActiveDevices,
            BluetoothDevice leAudioDevice) {
        if (hfpDevices == null) hfpDevices = new BluetoothDevice[]{};
        if (hearingAidDevices == null) hearingAidDevices = new BluetoothDevice[]{};
        if (hearingAidActiveDevices == null) hearingAidActiveDevices = new BluetoothDevice[]{};
        if (leAudioDevice == null) leAudioDevices = new BluetoothDevice[]{};

        when(mDeviceManager.getNumConnectedDevices()).thenReturn(
@@ -222,7 +286,7 @@ public class BluetoothRouteManagerTest extends TelecomTestCase {
        when(mBluetoothHearingAid.getConnectedDevices())
                .thenReturn(Arrays.asList(hearingAidDevices));
        when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEARING_AID)))
                .thenReturn(Arrays.asList(hearingAidActiveDevice, null));
                .thenReturn(Arrays.asList(hearingAidActiveDevices));
        when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.LE_AUDIO)))
                .thenReturn(Arrays.asList(leAudioDevice, null));
    }