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

Commit 2ec06cc5 authored by Yiyi Shen's avatar Yiyi Shen
Browse files

[Audiosharing] Check broadcast id instead of BIS for sink's receive state

In hysteresis mode, headset's BluetoothLeBroadcastReceiveState BIS Sync State could
change back and forth between 0, 1, 2, depending on broadcast playing
state. Thus BIS == 0 does not present that the sink has a valid source.
We check broadcast id in BluetoothLeBroadcastReceiveState instead.

Test: atest
Bug: 355222285
Flag: com.android.settingslib.flags.audio_sharing_hysteresis_mode_fix
Change-Id: Ie1f74d50872cd4a4285ea9dc9da8960706457dae
parent 2c52955a
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -709,6 +709,9 @@ public class BluetoothUtils {
    @WorkerThread
    public static boolean hasConnectedBroadcastSourceForBtDevice(
            @Nullable BluetoothDevice device, @Nullable LocalBluetoothManager localBtManager) {
        if (Flags.audioSharingHysteresisModeFix()) {
            return hasActiveLocalBroadcastSourceForBtDevice(device, localBtManager);
        }
        LocalBluetoothLeBroadcastAssistant assistant =
                localBtManager == null
                        ? null
+26 −37
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import com.android.settingslib.R;
import com.android.settingslib.flags.Flags;

import com.google.common.collect.ImmutableList;

@@ -1134,20 +1135,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to assistant profile is null");
            return;
        }
        List<BluetoothDevice> connectedDevices = mServiceBroadcastAssistant.getConnectedDevices();
        List<BluetoothDevice> devicesInSharing =
                connectedDevices.stream()
                        .filter(
                                bluetoothDevice -> {
                                    List<BluetoothLeBroadcastReceiveState> sourceList =
                                            mServiceBroadcastAssistant.getAllSources(
                                                    bluetoothDevice);
                                    return !sourceList.isEmpty()
                                            && sourceList.stream()
                                                    .anyMatch(BluetoothUtils::isConnected);
                                })
                        .collect(Collectors.toList());
        if (devicesInSharing.isEmpty()) {
        List<BluetoothDevice> devicesInBroadcast = getDevicesInBroadcast();
        if (devicesInBroadcast.isEmpty()) {
            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to no sinks in broadcast");
            return;
        }
@@ -1156,7 +1145,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
        BluetoothDevice targetDevice = null;
        // Find the earliest connected device in sharing session.
        int targetDeviceIdx = -1;
        for (BluetoothDevice device : devicesInSharing) {
        for (BluetoothDevice device : devicesInBroadcast) {
            if (devices.contains(device)) {
                int idx = devices.indexOf(device);
                if (idx > targetDeviceIdx) {
@@ -1169,10 +1158,6 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded, target is null");
            return;
        }
        Log.d(
                TAG,
                "updateFallbackActiveDeviceIfNeeded, set active device: "
                        + targetDevice.getAnonymizedAddress());
        CachedBluetoothDevice targetCachedDevice = mDeviceManager.findDevice(targetDevice);
        if (targetCachedDevice == null) {
            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded, fail to find cached bt device");
@@ -1180,16 +1165,37 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
        }
        int fallbackActiveGroupId = getFallbackActiveGroupId();
        if (fallbackActiveGroupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
                && getGroupId(targetCachedDevice) == fallbackActiveGroupId) {
                && BluetoothUtils.getGroupId(targetCachedDevice) == fallbackActiveGroupId) {
            Log.d(
                    TAG,
                    "Skip updateFallbackActiveDeviceIfNeeded, already is fallback: "
                            + fallbackActiveGroupId);
            return;
        }
        Log.d(
                TAG,
                "updateFallbackActiveDeviceIfNeeded, set active device: "
                        + targetDevice.getAnonymizedAddress());
        targetCachedDevice.setActive();
    }

    private List<BluetoothDevice> getDevicesInBroadcast() {
        boolean hysteresisModeFixEnabled = Flags.audioSharingHysteresisModeFix();
        List<BluetoothDevice> connectedDevices = mServiceBroadcastAssistant.getConnectedDevices();
        return connectedDevices.stream()
                .filter(
                        bluetoothDevice -> {
                            List<BluetoothLeBroadcastReceiveState> sourceList =
                                    mServiceBroadcastAssistant.getAllSources(
                                            bluetoothDevice);
                            return !sourceList.isEmpty() && sourceList.stream().anyMatch(
                                    source -> hysteresisModeFixEnabled
                                            ? BluetoothUtils.isSourceMatched(source, mBroadcastId)
                                            : BluetoothUtils.isConnected(source));
                        })
                .collect(Collectors.toList());
    }

    private int getFallbackActiveGroupId() {
        return Settings.Secure.getInt(
                mContext.getContentResolver(),
@@ -1197,23 +1203,6 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
                BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
    }

    private int getGroupId(CachedBluetoothDevice cachedDevice) {
        int groupId = cachedDevice.getGroupId();
        String anonymizedAddress = cachedDevice.getDevice().getAnonymizedAddress();
        if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
            Log.d(TAG, "getGroupId by CSIP profile for device: " + anonymizedAddress);
            return groupId;
        }
        for (LocalBluetoothProfile profile : cachedDevice.getProfiles()) {
            if (profile instanceof LeAudioProfile) {
                Log.d(TAG, "getGroupId by LEA profile for device: " + anonymizedAddress);
                return ((LeAudioProfile) profile).getGroupId(cachedDevice.getDevice());
            }
        }
        Log.d(TAG, "getGroupId return invalid id for device: " + anonymizedAddress);
        return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
    }

    private void notifyBroadcastStateChange(@BroadcastState int state) {
        if (!mContext.getPackageName().equals(SETTINGS_PKG)) {
            Log.d(TAG, "Skip notifyBroadcastStateChange, not triggered by Settings.");
+106 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.provider.Settings;
import android.util.Pair;

import com.android.internal.R;
import com.android.settingslib.flags.Flags;
import com.android.settingslib.widget.AdaptiveIcon;

import com.google.common.collect.ImmutableList;
@@ -605,6 +606,7 @@ public class BluetoothUtilsTest {

    @Test
    public void testHasConnectedBroadcastSource_leadDeviceConnectedToBroadcastSource() {
        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        CachedBluetoothDevice memberCachedDevice = mock(CachedBluetoothDevice.class);
        BluetoothDevice memberDevice = mock(BluetoothDevice.class);
@@ -630,6 +632,7 @@ public class BluetoothUtilsTest {

    @Test
    public void testHasConnectedBroadcastSource_memberDeviceConnectedToBroadcastSource() {
        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        CachedBluetoothDevice memberCachedDevice = mock(CachedBluetoothDevice.class);
        BluetoothDevice memberDevice = mock(BluetoothDevice.class);
@@ -655,6 +658,7 @@ public class BluetoothUtilsTest {

    @Test
    public void testHasConnectedBroadcastSource_deviceNotConnectedToBroadcastSource() {
        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);

        List<Long> bisSyncState = new ArrayList<>();
@@ -672,6 +676,7 @@ public class BluetoothUtilsTest {

    @Test
    public void testHasConnectedBroadcastSourceForBtDevice_deviceConnectedToBroadcastSource() {
        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
        List<Long> bisSyncState = new ArrayList<>();
        bisSyncState.add(1L);
        when(mLeBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState);
@@ -688,6 +693,7 @@ public class BluetoothUtilsTest {

    @Test
    public void testHasConnectedBroadcastSourceForBtDevice_deviceNotConnectedToBroadcastSource() {
        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
        List<Long> bisSyncState = new ArrayList<>();
        when(mLeBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState);

@@ -701,6 +707,106 @@ public class BluetoothUtilsTest {
                .isFalse();
    }

    @Test
    public void hasConnectedBroadcastSource_hysteresisFix_leadDeviceHasActiveLocalSource() {
        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        CachedBluetoothDevice memberCachedDevice = mock(CachedBluetoothDevice.class);
        BluetoothDevice memberDevice = mock(BluetoothDevice.class);
        when(memberCachedDevice.getDevice()).thenReturn(memberDevice);
        Set<CachedBluetoothDevice> memberCachedDevices = new HashSet<>();
        memberCachedDevices.add(memberCachedDevice);
        when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(memberCachedDevices);


        when(mBroadcast.getLatestBroadcastId()).thenReturn(TEST_BROADCAST_ID);
        when(mLeBroadcastReceiveState.getBroadcastId()).thenReturn(TEST_BROADCAST_ID);

        List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
        sourceList.add(mLeBroadcastReceiveState);
        when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(sourceList);
        when(mAssistant.getAllSources(memberDevice)).thenReturn(Collections.emptyList());

        assertThat(
                BluetoothUtils.hasConnectedBroadcastSource(
                        mCachedBluetoothDevice, mLocalBluetoothManager))
                .isTrue();
    }

    @Test
    public void hasConnectedBroadcastSource_hysteresisFix_memberDeviceHasActiveLocalSource() {
        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        CachedBluetoothDevice memberCachedDevice = mock(CachedBluetoothDevice.class);
        BluetoothDevice memberDevice = mock(BluetoothDevice.class);
        when(memberCachedDevice.getDevice()).thenReturn(memberDevice);
        Set<CachedBluetoothDevice> memberCachedDevices = new HashSet<>();
        memberCachedDevices.add(memberCachedDevice);
        when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(memberCachedDevices);

        when(mBroadcast.getLatestBroadcastId()).thenReturn(TEST_BROADCAST_ID);
        when(mLeBroadcastReceiveState.getBroadcastId()).thenReturn(TEST_BROADCAST_ID);

        List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
        sourceList.add(mLeBroadcastReceiveState);
        when(mAssistant.getAllSources(memberDevice)).thenReturn(sourceList);
        when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(Collections.emptyList());

        assertThat(
                BluetoothUtils.hasConnectedBroadcastSource(
                        mCachedBluetoothDevice, mLocalBluetoothManager))
                .isTrue();
    }

    @Test
    public void hasConnectedBroadcastSource_hysteresisFix_deviceNoActiveLocalSource() {
        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);

        when(mBroadcast.getLatestBroadcastId()).thenReturn(UNKNOWN_VALUE_PLACEHOLDER);

        List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
        sourceList.add(mLeBroadcastReceiveState);
        when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(sourceList);

        assertThat(
                BluetoothUtils.hasConnectedBroadcastSource(
                        mCachedBluetoothDevice, mLocalBluetoothManager))
                .isFalse();
    }

    @Test
    public void hasConnectedBroadcastSourceForBtDevice_hysteresisFix_deviceHasActiveLocalSource() {
        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
        when(mBroadcast.getLatestBroadcastId()).thenReturn(TEST_BROADCAST_ID);
        when(mLeBroadcastReceiveState.getBroadcastId()).thenReturn(TEST_BROADCAST_ID);

        List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
        sourceList.add(mLeBroadcastReceiveState);
        when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(sourceList);

        assertThat(
                BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(
                        mBluetoothDevice, mLocalBluetoothManager))
                .isTrue();
    }

    @Test
    public void hasConnectedBroadcastSourceForBtDevice_hysteresisFix_deviceNoActiveLocalSource() {
        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
        when(mBroadcast.getLatestBroadcastId()).thenReturn(TEST_BROADCAST_ID);
        when(mLeBroadcastReceiveState.getBroadcastId()).thenReturn(UNKNOWN_VALUE_PLACEHOLDER);

        List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
        sourceList.add(mLeBroadcastReceiveState);
        when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(sourceList);

        assertThat(
                BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(
                        mBluetoothDevice, mLocalBluetoothManager))
                .isFalse();
    }

    @Test
    public void testHasActiveLocalBroadcastSourceForBtDevice_hasActiveLocalSource() {
        when(mBroadcast.getLatestBroadcastId()).thenReturn(TEST_BROADCAST_ID);