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

Commit 86a95bf4 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "ActiveDeviceManager: Fix handling disconnect of a streaming set member" into main

parents c197313a 7f23913c
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -1041,6 +1041,23 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
        return false;
    }

    @GuardedBy("mLock")
    private boolean areSameGroupMembers(BluetoothDevice firstDevice, BluetoothDevice secondDevice) {

        if (!Flags.admFixDisconnectOfSetMember()) {
            /* This function shall return false without the fix flag. */
            return false;
        }

        final LeAudioService leAudioService = mFactory.getLeAudioService();
        if (leAudioService == null) {
            Log.e(TAG, "LeAudioService not available");
            return false;
        }

        return leAudioService.getGroupId(firstDevice) == leAudioService.getGroupId(secondDevice);
    }

    /**
     * TODO: This method can return true when a fallback device for an unrelated profile is found.
     * Take disconnected profile as an argument, and find the exact fallback device. Also, split
@@ -1083,6 +1100,13 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
                    setLeAudioActiveDevice(null, hasFallbackDevice);
                } else {
                    Log.d(TAG, "Found a LE hearing aid fallback device: " + device);
                    if (areSameGroupMembers(recentlyRemovedDevice, device)) {
                        Log.d(
                                TAG,
                                "Do nothing, removed device belong to the same group as the"
                                        + " fallback device.");
                        return true;
                    }
                    setLeHearingAidActiveDevice(device);
                    setHearingAidActiveDevice(null, hasFallbackDevice);
                    setA2dpActiveDevice(null, hasFallbackDevice);
@@ -1152,6 +1176,14 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
                setHearingAidActiveDevice(null, true);
            } else {
                Log.d(TAG, "Found a LE audio fallback device: " + device);
                if (areSameGroupMembers(recentlyRemovedDevice, device)) {
                    Log.d(
                            TAG,
                            "Do nothing, removed device belong to the same group as the fallback"
                                    + " device.");
                    return true;
                }

                if (!setLeAudioActiveDevice(device)) {
                    return false;
                }
@@ -1181,6 +1213,14 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
                setHearingAidActiveDevice(null, true);
            } else {
                Log.d(TAG, "Found a LE audio fallback device: " + device);
                if (areSameGroupMembers(recentlyRemovedDevice, device)) {
                    Log.d(
                            TAG,
                            "Do nothing, removed device belong to the same group as the fallback"
                                    + " device.");
                    return true;
                }

                setLeAudioActiveDevice(device);
                if (!Utils.isDualModeAudioEnabled()) {
                    setA2dpActiveDevice(null, true);
+160 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -67,6 +68,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
@@ -87,6 +89,7 @@ public class ActiveDeviceManagerTest {
    private BluetoothDevice mHearingAidDevice;
    private BluetoothDevice mLeAudioDevice;
    private BluetoothDevice mLeAudioDevice2;
    private BluetoothDevice mLeAudioDevice3;
    private BluetoothDevice mLeHearingAidDevice;
    private BluetoothDevice mSecondaryAudioDevice;
    private BluetoothDevice mDualModeAudioDevice;
@@ -146,6 +149,7 @@ public class ActiveDeviceManagerTest {
        mSecondaryAudioDevice = TestUtils.getTestDevice(mAdapter, 6);
        mDualModeAudioDevice = TestUtils.getTestDevice(mAdapter, 7);
        mLeAudioDevice2 = TestUtils.getTestDevice(mAdapter, 8);
        mLeAudioDevice3 = TestUtils.getTestDevice(mAdapter, 9);
        mDeviceConnectionStack = new ArrayList<>();
        mMostRecentDevice = null;
        mOriginalDualModeAudioState = Utils.isDualModeAudioEnabled();
@@ -161,6 +165,7 @@ public class ActiveDeviceManagerTest {

        when(mLeAudioService.getLeadDevice(mLeAudioDevice)).thenReturn(mLeAudioDevice);
        when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice2);
        when(mLeAudioService.getLeadDevice(mLeAudioDevice3)).thenReturn(mLeAudioDevice3);
        when(mLeAudioService.getLeadDevice(mDualModeAudioDevice)).thenReturn(mDualModeAudioDevice);
        when(mLeAudioService.getLeadDevice(mLeHearingAidDevice)).thenReturn(mLeHearingAidDevice);

@@ -839,6 +844,161 @@ public class ActiveDeviceManagerTest {
        verify(mLeAudioService).setActiveDevice(mLeAudioDevice);
    }

    /**
     * One LE Audio set, containing two buds, is connected. When one device got disconnected
     * fallback device should not be set to true active device to fallback device.
     */
    @Test
    @EnableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER)
    public void leAudioSecondDeviceDisconnected_noFallbackDeviceActive_ModeNormal() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);

        InOrder order = inOrder(mLeAudioService);

        int groupId = 1;
        List<BluetoothDevice> groupDevices = List.of(mLeAudioDevice, mLeAudioDevice2);
        when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice);

        leAudioConnected(mLeAudioDevice);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice);

        leAudioConnected(mLeAudioDevice2);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, never()).setActiveDevice(any());

        when(mLeAudioService.getGroupId(any())).thenReturn(groupId);
        when(mLeAudioService.getGroupDevices(groupId)).thenReturn(groupDevices);

        leAudioDisconnected(mLeAudioDevice2);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, never()).setActiveDevice(any());
    }

    /**
     * One LE Audio set, containing two buds, is connected. When one device got disconnected
     * fallback device should not be set to true active device to fallback device.
     */
    @Test
    @EnableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER)
    public void leAudioSecondDeviceDisconnected_noFallbackDeviceActive_ModeInCall() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);

        InOrder order = inOrder(mLeAudioService);

        int groupId = 1;
        List<BluetoothDevice> groupDevices = List.of(mLeAudioDevice, mLeAudioDevice2);
        when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice);

        leAudioConnected(mLeAudioDevice);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice);

        leAudioConnected(mLeAudioDevice2);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, never()).setActiveDevice(any());

        when(mLeAudioService.getGroupId(any())).thenReturn(groupId);
        when(mLeAudioService.getGroupDevices(groupId)).thenReturn(groupDevices);

        leAudioDisconnected(mLeAudioDevice2);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, never()).setActiveDevice(any());
    }

    /**
     * One LE Audio set, containing two buds, is connected. When one device got disconnected
     * fallback device should not be set to true active device to fallback device.
     */
    @Test
    @EnableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER)
    public void twoLeAudioSets_OneSetDisconnected_FallbackToAnotherOne_ModeNormal() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);

        InOrder order = inOrder(mLeAudioService);

        int groupId = 1;
        List<BluetoothDevice> groupDevices = List.of(mLeAudioDevice, mLeAudioDevice2);

        when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice);
        when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(groupId);
        when(mLeAudioService.getGroupId(mLeAudioDevice2)).thenReturn(groupId);
        when(mLeAudioService.getGroupDevices(groupId)).thenReturn(groupDevices);

        int groupId2 = 2;
        List<BluetoothDevice> groupDevicesId2 = List.of(mLeAudioDevice3);

        when(mLeAudioService.getGroupId(mLeAudioDevice3)).thenReturn(groupId2);
        when(mLeAudioService.getGroupDevices(groupId2)).thenReturn(groupDevicesId2);

        leAudioConnected(mLeAudioDevice3);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice3);

        leAudioConnected(mLeAudioDevice);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService).setActiveDevice(mLeAudioDevice);

        leAudioConnected(mLeAudioDevice2);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice2);

        leAudioDisconnected(mLeAudioDevice2);
        mTestLooper.dispatchAll();
        // Should not encrease a number of this call.
        order.verify(mLeAudioService, never()).setActiveDevice(any());

        leAudioDisconnected(mLeAudioDevice);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice3);
    }

    /**
     * One LE Audio set, containing two buds, is connected. When one device got disconnected
     * fallback device should not be set to true active device to fallback device.
     */
    @Test
    @EnableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER)
    public void twoLeAudioSets_OneSetDisconnected_FallbackToAnotherOne_ModeInCall() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);

        InOrder order = inOrder(mLeAudioService);

        int groupId = 1;
        List<BluetoothDevice> groupDevices = List.of(mLeAudioDevice, mLeAudioDevice2);

        when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice);
        when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(groupId);
        when(mLeAudioService.getGroupId(mLeAudioDevice2)).thenReturn(groupId);
        when(mLeAudioService.getGroupDevices(groupId)).thenReturn(groupDevices);

        int groupId2 = 2;
        List<BluetoothDevice> groupDevicesId2 = List.of(mLeAudioDevice3);

        when(mLeAudioService.getGroupId(mLeAudioDevice3)).thenReturn(groupId2);
        when(mLeAudioService.getGroupDevices(groupId2)).thenReturn(groupDevicesId2);

        leAudioConnected(mLeAudioDevice3);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService).setActiveDevice(mLeAudioDevice3);

        leAudioConnected(mLeAudioDevice);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService).setActiveDevice(mLeAudioDevice);

        leAudioConnected(mLeAudioDevice2);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, never()).setActiveDevice(any());

        leAudioDisconnected(mLeAudioDevice2);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, never()).setActiveDevice(any());

        leAudioDisconnected(mLeAudioDevice);
        mTestLooper.dispatchAll();
        order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice3);
    }

    /** A combo (A2DP + Headset) device is connected. Then an LE Audio is connected. */
    @Test
    public void leAudioActive_clearA2dpAndHeadsetActive() {