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

Commit c7ce08aa authored by Chelsea Hao's avatar Chelsea Hao Committed by Android (Google) Code Review
Browse files

Merge "Add `isAvailableAudioSharingMediaBluetoothDevice` to identify device...

Merge "Add `isAvailableAudioSharingMediaBluetoothDevice` to identify device that's available for being set as an active media device and also available for audio sharing." into main
parents fbd5b1ed 3d450124
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -48,9 +48,12 @@ import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class BluetoothUtils {
    private static final String TAG = "BluetoothUtils";
@@ -561,6 +564,68 @@ public class BluetoothUtils {
        return isFilterMatched;
    }

    /**
     * Checks if a given `CachedBluetoothDevice` is available for audio sharing and being switch as
     * active media device.
     *
     * <p>This method determines if the device meets the following criteria to be available:
     *
     * <ol>
     *   <li>Audio sharing session is off.
     *   <li>The device is one of the two connected devices on the LE Broadcast Assistant profile.
     *   <li>The device is not currently active on the LE Audio profile.
     *   <li>There is exactly one other device that is active on the LE Audio profile.
     * </ol>
     *
     * @param cachedDevice The `CachedBluetoothDevice` to check.
     * @param localBluetoothManager The `LocalBluetoothManager` instance, or null if unavailable.
     * @return `true` if the device is available for audio sharing and settings as active, `false`
     *     otherwise.
     */
    @WorkerThread
    public static boolean isAvailableAudioSharingMediaBluetoothDevice(
            CachedBluetoothDevice cachedDevice,
            @Nullable LocalBluetoothManager localBluetoothManager) {
        LocalBluetoothLeBroadcastAssistant assistantProfile =
                Optional.ofNullable(localBluetoothManager)
                        .map(LocalBluetoothManager::getProfileManager)
                        .map(LocalBluetoothProfileManager::getLeAudioBroadcastAssistantProfile)
                        .orElse(null);
        LeAudioProfile leAudioProfile =
                Optional.ofNullable(localBluetoothManager)
                        .map(LocalBluetoothManager::getProfileManager)
                        .map(LocalBluetoothProfileManager::getLeAudioProfile)
                        .orElse(null);
        CachedBluetoothDeviceManager deviceManager =
                Optional.ofNullable(localBluetoothManager)
                        .map(LocalBluetoothManager::getCachedDeviceManager)
                        .orElse(null);
        // If any of the profiles are null, or broadcast is already on, return false
        if (assistantProfile == null
                || leAudioProfile == null
                || deviceManager == null
                || isBroadcasting(localBluetoothManager)) {
            return false;
        }
        Set<Integer> connectedGroupIds =
                assistantProfile.getAllConnectedDevices().stream()
                        .map(deviceManager::findDevice)
                        .filter(Objects::nonNull)
                        .map(CachedBluetoothDevice::getGroupId)
                        .collect(Collectors.toSet());
        Set<Integer> activeGroupIds =
                leAudioProfile.getActiveDevices().stream()
                        .map(deviceManager::findDevice)
                        .filter(Objects::nonNull)
                        .map(CachedBluetoothDevice::getGroupId)
                        .collect(Collectors.toSet());
        int groupId = cachedDevice.getGroupId();
        return activeGroupIds.size() == 1
                && !activeGroupIds.contains(groupId)
                && connectedGroupIds.size() == 2
                && connectedGroupIds.contains(groupId);
    }

    /** Returns if the le audio sharing is enabled. */
    public static boolean isAudioSharingEnabled() {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+114 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.settingslib.bluetooth;

import static com.android.settingslib.bluetooth.BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice;
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_DETERMINING_ADVANCED_DETAILS_HEADER_WITH_METADATA;

import static com.google.common.truth.Truth.assertThat;
@@ -80,6 +81,7 @@ public class BluetoothUtilsTest {
    @Mock private LocalBluetoothProfileManager mProfileManager;
    @Mock private LocalBluetoothManager mLocalBluetoothManager;
    @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
    @Mock private CachedBluetoothDeviceManager mDeviceManager;
    @Mock private BluetoothLeBroadcastReceiveState mLeBroadcastReceiveState;

    private Context mContext;
@@ -104,8 +106,10 @@ public class BluetoothUtilsTest {
        mContext = spy(RuntimeEnvironment.application);
        mSetFlagsRule.disableFlags(FLAG_ENABLE_DETERMINING_ADVANCED_DETAILS_HEADER_WITH_METADATA);
        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mProfileManager);
        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
        when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
        when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
        when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
        when(mA2dpProfile.getProfileId()).thenReturn(BluetoothProfile.A2DP);
        when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO);
        when(mHearingAid.getProfileId()).thenReturn(BluetoothProfile.HEARING_AID);
@@ -766,6 +770,116 @@ public class BluetoothUtilsTest {
                .isEqualTo(mCachedBluetoothDevice);
    }

    @Test
    public void testIsAvailableAudioSharingMediaBluetoothDevice_nullProfiles() {
        when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(null);
        boolean result =
                isAvailableAudioSharingMediaBluetoothDevice(
                        mCachedBluetoothDevice, mLocalBluetoothManager);

        assertThat(result).isFalse();
    }

    @Test
    public void testIsAvailableAudioSharingMediaBluetoothDevice_alreadyBroadcasting() {
        when(mBroadcast.isEnabled(any())).thenReturn(true);

        boolean result =
                isAvailableAudioSharingMediaBluetoothDevice(
                        mCachedBluetoothDevice, mLocalBluetoothManager);

        assertThat(result).isFalse();
    }

    @Test
    public void testIsAvailableAudioSharingMediaBluetoothDevice_availableDevice() {
        when(mCachedBluetoothDevice.getGroupId()).thenReturn(1);
        CachedBluetoothDevice cachedBluetoothDevice2 = mock(CachedBluetoothDevice.class);
        when(cachedBluetoothDevice2.getGroupId()).thenReturn(2);

        BluetoothDevice device1 = mock(BluetoothDevice.class);
        when(mDeviceManager.findDevice(device1)).thenReturn(mCachedBluetoothDevice);
        BluetoothDevice device2 = mock(BluetoothDevice.class);
        when(mDeviceManager.findDevice(device2)).thenReturn(cachedBluetoothDevice2);

        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device1, device2));
        when(mLeAudioProfile.getActiveDevices()).thenReturn(ImmutableList.of(device1));

        boolean result =
                isAvailableAudioSharingMediaBluetoothDevice(
                        cachedBluetoothDevice2, mLocalBluetoothManager);

        assertThat(result).isTrue();
    }

    @Test
    public void testIsAvailableAudioSharingMediaBluetoothDevice_alreadyActive() {
        when(mCachedBluetoothDevice.getGroupId()).thenReturn(1);
        CachedBluetoothDevice cachedBluetoothDevice2 = mock(CachedBluetoothDevice.class);
        when(cachedBluetoothDevice2.getGroupId()).thenReturn(2);

        BluetoothDevice device1 = mock(BluetoothDevice.class);
        when(mDeviceManager.findDevice(device1)).thenReturn(mCachedBluetoothDevice);
        BluetoothDevice device2 = mock(BluetoothDevice.class);
        when(mDeviceManager.findDevice(device2)).thenReturn(cachedBluetoothDevice2);

        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device1, device2));
        when(mLeAudioProfile.getActiveDevices()).thenReturn(ImmutableList.of(device1));

        boolean result =
                isAvailableAudioSharingMediaBluetoothDevice(
                        mCachedBluetoothDevice, mLocalBluetoothManager);

        assertThat(result).isFalse();
    }

    @Test
    public void testIsAvailableAudioSharingMediaBluetoothDevice_notConnected() {
        when(mCachedBluetoothDevice.getGroupId()).thenReturn(1);
        CachedBluetoothDevice cachedBluetoothDevice2 = mock(CachedBluetoothDevice.class);
        when(cachedBluetoothDevice2.getGroupId()).thenReturn(2);

        BluetoothDevice device1 = mock(BluetoothDevice.class);
        when(mDeviceManager.findDevice(device1)).thenReturn(mCachedBluetoothDevice);
        BluetoothDevice device2 = mock(BluetoothDevice.class);
        when(mDeviceManager.findDevice(device2)).thenReturn(cachedBluetoothDevice2);

        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device2));
        when(mLeAudioProfile.getActiveDevices()).thenReturn(ImmutableList.of(device1));

        boolean result =
                isAvailableAudioSharingMediaBluetoothDevice(
                        mCachedBluetoothDevice, mLocalBluetoothManager);

        assertThat(result).isFalse();
    }

    @Test
    public void testIsAvailableAudioSharingMediaBluetoothDevice_moreThanTwoConnected() {
        when(mCachedBluetoothDevice.getGroupId()).thenReturn(1);
        CachedBluetoothDevice cachedBluetoothDevice2 = mock(CachedBluetoothDevice.class);
        when(cachedBluetoothDevice2.getGroupId()).thenReturn(2);
        CachedBluetoothDevice cachedBluetoothDevice3 = mock(CachedBluetoothDevice.class);
        when(cachedBluetoothDevice3.getGroupId()).thenReturn(3);

        BluetoothDevice device1 = mock(BluetoothDevice.class);
        when(mDeviceManager.findDevice(device1)).thenReturn(mCachedBluetoothDevice);
        BluetoothDevice device2 = mock(BluetoothDevice.class);
        when(mDeviceManager.findDevice(device2)).thenReturn(cachedBluetoothDevice2);
        BluetoothDevice device3 = mock(BluetoothDevice.class);
        when(mDeviceManager.findDevice(device3)).thenReturn(cachedBluetoothDevice3);

        when(mAssistant.getAllConnectedDevices())
                .thenReturn(ImmutableList.of(device1, device2, device3));
        when(mLeAudioProfile.getActiveDevices()).thenReturn(ImmutableList.of(device1));

        boolean result =
                isAvailableAudioSharingMediaBluetoothDevice(
                        cachedBluetoothDevice2, mLocalBluetoothManager);

        assertThat(result).isFalse();
    }

    @Test
    public void getAudioDeviceAttributesForSpatialAudio_bleHeadset() {
        String address = "11:22:33:44:55:66";