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

Commit 46d60dd3 authored by Hall Liu's avatar Hall Liu Committed by Gerrit Code Review
Browse files

Merge "Revise BT active device detection"

parents 9beab998 54e7645a
Loading
Loading
Loading
Loading
+23 −11
Original line number Diff line number Diff line
@@ -450,6 +450,7 @@ public class BluetoothRouteManager extends StateMachine {
    // Tracks the active devices in the BT stack (HFP or hearing aid).
    private BluetoothDevice mHfpActiveDeviceCache = null;
    private BluetoothDevice mHearingAidActiveDeviceCache = null;
    private BluetoothDevice mMostRecentlyReportedActiveDevice = null;

    public BluetoothRouteManager(Context context, TelecomSystem.SyncRoot lock,
            BluetoothDeviceManager deviceManager, Timeouts.Adapter timeoutsAdapter) {
@@ -588,6 +589,9 @@ public class BluetoothRouteManager extends StateMachine {
        } else {
            mHfpActiveDeviceCache = device;
        }

        if (device != null) mMostRecentlyReportedActiveDevice = device;

        boolean isActiveDevicePresent = mHearingAidActiveDeviceCache != null
                || mHfpActiveDeviceCache != null;

@@ -690,30 +694,38 @@ public class BluetoothRouteManager extends StateMachine {
        BluetoothHeadsetProxy bluetoothHeadset = mDeviceManager.getHeadsetService();
        BluetoothHearingAid bluetoothHearingAid = mDeviceManager.getHearingAidService();

        BluetoothDevice hfpActiveDevice = null;
        BluetoothDevice hearingAidActiveDevice = null;

        if (bluetoothHeadset == null && bluetoothHearingAid == null) {
            Log.i(this, "getBluetoothAudioConnectedDevice: no service available.");
            return null;
        }

        if (bluetoothHeadset != null) {
            for (BluetoothDevice device : bluetoothHeadset.getConnectedDevices()) {
                boolean isAudioOn = bluetoothHeadset.getAudioState(device)
                        != BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
                Log.v(this, "isBluetoothAudioConnected: ==> isAudioOn = " + isAudioOn
                        + "for headset: " + device);
                if (isAudioOn) {
                    return device;
                }
            }
            hfpActiveDevice = bluetoothHeadset.getActiveDevice();
        }

        if (bluetoothHearingAid != null) {
            for (BluetoothDevice device : bluetoothHearingAid.getActiveDevices()) {
                if (device != null) {
                    return device;
                    hearingAidActiveDevice = device;
                    break;
                }
            }
        }
        return null;

        // Return the active device reported by either HFP or hearing aid. If both are reporting
        // active devices, go with the most recent one as reported by the receiver.
        if (hfpActiveDevice != null) {
            if (hearingAidActiveDevice != null) {
                Log.i(this, "Both HFP and hearing aid are reporting active devices. Going with"
                        + " the most recently reported active device: %s");
                return mMostRecentlyReportedActiveDevice;
            }
            return hfpActiveDevice;
        }
        return hearingAidActiveDevice;
    }

    /**
+1 −1
Original line number Diff line number Diff line
@@ -136,7 +136,7 @@ public class BluetoothStateReceiver extends BroadcastReceiver {
        boolean isHearingAid =
                BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED.equals(intent.getAction());
        Log.i(LOG_TAG, "Device %s is now the preferred BT device for %s", device,
                isHearingAid ? "heading aid" : "HFP");
                isHearingAid ? "hearing aid" : "HFP");

        mBluetoothRouteManager.onActiveDeviceChanged(device, isHearingAid);
        if (isHearingAid) {
+45 −15
Original line number Diff line number Diff line
@@ -38,7 +38,9 @@ import org.junit.runners.JUnit4;
import org.mockito.Mock;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -55,6 +57,7 @@ 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");

    @Mock private BluetoothDeviceManager mDeviceManager;
    @Mock private BluetoothHeadsetProxy mHeadsetProxy;
@@ -73,7 +76,7 @@ public class BluetoothRouteManagerTest extends TelecomTestCase {
    public void testConnectHfpRetryWhileNotConnected() {
        BluetoothRouteManager sm = setupStateMachine(
                BluetoothRouteManager.AUDIO_OFF_STATE_NAME, null);
        setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null);
        setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null, null, null);
        when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                nullable(ContentResolver.class))).thenReturn(0L);
        when(mHeadsetProxy.connectAudio()).thenReturn(false);
@@ -90,12 +93,31 @@ public class BluetoothRouteManagerTest extends TelecomTestCase {
        sm.quitNow();
    }

    @SmallTest
    @Test
    public void testAmbiguousActiveDevice() {
        BluetoothRouteManager sm = setupStateMachine(
                BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1);
        setupConnectedDevices(new BluetoothDevice[]{DEVICE1},
                new BluetoothDevice[]{HEARING_AID_DEVICE}, DEVICE1, HEARING_AID_DEVICE);
        sm.onActiveDeviceChanged(DEVICE1, false);
        sm.onActiveDeviceChanged(HEARING_AID_DEVICE, true);
        executeRoutingAction(sm, BluetoothRouteManager.BT_AUDIO_LOST, DEVICE1.getAddress());

        verifyConnectionAttempt(HEARING_AID_DEVICE, 0);
        verifyConnectionAttempt(DEVICE1, 0);
        assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
                        + ":" + HEARING_AID_DEVICE.getAddress(),
                sm.getCurrentState().getName());
        sm.quitNow();
    }

    @SmallTest
    @Test
    public void testConnectHfpRetryWhileConnectedToAnotherDevice() {
        BluetoothRouteManager sm = setupStateMachine(
                BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1);
        setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null);
        setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null, null, null);
        when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                nullable(ContentResolver.class))).thenReturn(0L);
        when(mHeadsetProxy.connectAudio()).thenReturn(false);
@@ -127,18 +149,26 @@ public class BluetoothRouteManagerTest extends TelecomTestCase {
        return sm;
    }

    private void setupConnectedDevices(BluetoothDevice[] devices, BluetoothDevice activeDevice) {
        when(mDeviceManager.getNumConnectedDevices()).thenReturn(devices.length);
        when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices));
        when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices));
        when(mHeadsetProxy.getAudioState(any(BluetoothDevice.class)))
                .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
        when(mBluetoothHearingAid.getConnectedDevices()).thenReturn(Collections.emptyList());
        when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(null, null));
        if (activeDevice != null) {
            when(mHeadsetProxy.getAudioState(eq(activeDevice)))
                    .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED);
        }
    private void setupConnectedDevices(BluetoothDevice[] hfpDevices,
            BluetoothDevice[] hearingAidDevices,
            BluetoothDevice hfpActiveDevice, BluetoothDevice hearingAidActiveDevice) {
        if (hfpDevices == null) hfpDevices = new BluetoothDevice[]{};
        if (hearingAidDevices == null) hearingAidDevices = new BluetoothDevice[]{};

        when(mDeviceManager.getNumConnectedDevices()).thenReturn(
                hfpDevices.length + hearingAidDevices.length);
        List<BluetoothDevice> allDevices = Stream.concat(
                Arrays.stream(hfpDevices), Arrays.stream(hearingAidDevices))
                .collect(Collectors.toList());

        when(mDeviceManager.getConnectedDevices()).thenReturn(allDevices);
        when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(hfpDevices));
        when(mHeadsetProxy.getActiveDevice()).thenReturn(hfpActiveDevice);

        when(mBluetoothHearingAid.getConnectedDevices())
                .thenReturn(Arrays.asList(hearingAidDevices));
        when(mBluetoothHearingAid.getActiveDevices())
                .thenReturn(Arrays.asList(hearingAidActiveDevice, null));
    }

    static void executeRoutingAction(BluetoothRouteManager brm, int message, String
+8 −7
Original line number Diff line number Diff line
@@ -265,9 +265,8 @@ public class BluetoothRouteTransitionTests extends TelecomTestCase {
                SomeArgs args = SomeArgs.obtain();
                args.arg1 = Log.createSubsession();
                args.arg2 = mParams.initialDevice.getAddress();
                when(mHeadsetProxy.getActiveDevice()).thenReturn(null);
                sm.sendMessage(BluetoothRouteManager.BT_AUDIO_LOST, args);
                when(mHeadsetProxy.getAudioState(eq(mParams.initialDevice)))
                        .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
                return true;
            }).when(mDeviceManager).disconnectAudio();
        }
@@ -278,9 +277,14 @@ public class BluetoothRouteTransitionTests extends TelecomTestCase {
            sm.onActiveDeviceChanged(mParams.messageDevice,
                    mParams.hearingAidBtDevices.contains(mParams.messageDevice));
        } else if (mParams.messageType == BluetoothRouteManager.LOST_DEVICE) {
            sm.onDeviceLost(mParams.messageDevice.getAddress());
            sm.onActiveDeviceChanged(null,
                    mParams.hearingAidBtDevices.contains(mParams.messageDevice));
            if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) {
                when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(null, null));
            } else {
                when(mHeadsetProxy.getActiveDevice()).thenReturn(null);
            }
            sm.onDeviceLost(mParams.messageDevice.getAddress());
        } else {
            executeRoutingAction(sm, mParams.messageType,
                    mParams.messageDevice == null ? null : mParams.messageDevice.getAddress());
@@ -335,11 +339,8 @@ public class BluetoothRouteTransitionTests extends TelecomTestCase {
        when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices));
        when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices));
        when(mHeadsetProxy.getActiveDevice()).thenReturn(activeDevice);
        when(mHeadsetProxy.getAudioState(any(BluetoothDevice.class)))
                .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
        if (audioOnDevice != null) {
            when(mHeadsetProxy.getAudioState(eq(audioOnDevice)))
                    .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED);
            when(mHeadsetProxy.getActiveDevice()).thenReturn(audioOnDevice);
        }
    }