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

Commit 95639b3f authored by Hall Liu's avatar Hall Liu Committed by android-build-merger
Browse files

Merge "Revise BT active device detection"

am: 46d60dd3

Change-Id: I14b8ea8c0976182f80540782dc715e7494118fc5
parents fdfbf6cd 46d60dd3
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);
        }
    }