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

Commit 27e4fcc6 authored by Yiyi Shen's avatar Yiyi Shen
Browse files

[Audiosharing] Use setBroadcastToUnicastFallbackGroup to set primary

Flag: com.android.settingslib.flags.adopt_primary_group_management_api
Test: atest
Bug: 381946931
Change-Id: Ib06dd2e202b07b9cdb25b1a671ee4d57246415ba
parent e87733be
Loading
Loading
Loading
Loading
+39 −16
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.settings.connecteddevice.audiosharing;

import static com.android.settingslib.Utils.isAudioModeOngoingCall;

import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothCsipSetCoordinator;
@@ -48,6 +50,7 @@ import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -91,6 +94,7 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP
    Map<Integer, List<BluetoothDevice>> mGroupedConnectedDevices = new HashMap<>();
    private List<AudioSharingDeviceItem> mDeviceItemsInSharingSession = new ArrayList<>();
    private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false);
    private AtomicBoolean mIsAudioModeOngoingCall = new AtomicBoolean(false);

    @VisibleForTesting
    final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
@@ -202,28 +206,15 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP
                                    mDeviceItemsInSharingSession,
                                    pair == null ? -1 : pair.first,
                                    (AudioSharingDeviceItem item) -> {
                                        int currentGroupId =
                                        int currentCallAudioGroupId =
                                                BluetoothUtils.getPrimaryGroupIdForBroadcast(
                                                        mContext.getContentResolver());
                                        int clickedGroupId = item.getGroupId();
                                        if (clickedGroupId == currentGroupId) {
                                        if (clickedGroupId == currentCallAudioGroupId) {
                                            Log.d(TAG, "Skip set call audio device: unchanged");
                                            return;
                                        }
                                        List<BluetoothDevice> devices =
                                                mGroupedConnectedDevices.getOrDefault(
                                                        clickedGroupId, ImmutableList.of());
                                        CachedBluetoothDevice lead =
                                                AudioSharingUtils.getLeadDevice(
                                                        mCacheManager, devices);
                                        if (lead != null) {
                                            String addr = lead.getDevice().getAnonymizedAddress();
                                            Log.d(TAG, "Set call audio device: " + addr);
                                            AudioSharingUtils.setPrimary(mContext, lead);
                                            logCallAudioDeviceChange(currentGroupId, lead);
                                        } else {
                                            Log.d(TAG, "Skip set call audio device: no lead");
                                        }
                                        setCallAudioGroup(clickedGroupId);
                                    });
                        }
                        return true;
@@ -269,6 +260,11 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP
        }
    }

    @Override
    public void onAudioModeChanged() {
        mIsAudioModeOngoingCall.set(isAudioModeOngoingCall(mContext));
    }

    /**
     * Initialize the controller.
     *
@@ -311,6 +307,7 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP
                    false,
                    mSettingsObserver);
            mAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
            mIsAudioModeOngoingCall.set(isAudioModeOngoingCall(mContext));
            mCallbacksRegistered.set(true);
        }
    }
@@ -333,6 +330,32 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP
        }
    }

    private void setCallAudioGroup(int groupId) {
        List<BluetoothDevice> devices =
                mGroupedConnectedDevices.getOrDefault(
                        groupId, ImmutableList.of());
        CachedBluetoothDevice lead =
                AudioSharingUtils.getLeadDevice(
                        mCacheManager, devices);
        if (lead != null) {
            String addr = lead.getDevice().getAnonymizedAddress();
            Log.d(TAG, "Set call audio device: " + addr);
            if (Flags.adoptPrimaryGroupManagementApi() && !mIsAudioModeOngoingCall.get()) {
                LeAudioProfile leaProfile = mBtManager == null ? null
                        : mBtManager.getProfileManager().getLeAudioProfile();
                if (leaProfile != null) {
                    leaProfile.setBroadcastToUnicastFallbackGroup(groupId);
                }
            } else {
                lead.setActive();
            }
            AudioSharingUtils.setUserPreferredPrimary(mContext, lead);
            logCallAudioDeviceChange(groupId, lead);
        } else {
            Log.d(TAG, "Skip set call audio device: no lead");
        }
    }

    /**
     * Update the preference summary: current headset for call audio.
     *
+2 −1
Original line number Diff line number Diff line
@@ -389,7 +389,8 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
            Log.d(TAG, "onDeviceClick, set active in call mode");
            CachedBluetoothDevice cachedDevice =
                    ((BluetoothDevicePreference) preference).getBluetoothDevice();
            AudioSharingUtils.setPrimary(mContext, cachedDevice);
            cachedDevice.setActive();
            AudioSharingUtils.setUserPreferredPrimary(mContext, cachedDevice);
        }
        mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUDIO_SHARING_DEVICE_CLICK,
                isCallMode);
+2 −1
Original line number Diff line number Diff line
@@ -192,7 +192,8 @@ public class AudioSharingDialogHandler {
                    // If this method is called with user triggered, e.g. manual click on the
                    // "Connected devices" page, we need call setActive for the device, since user
                    // intend to switch active device for the call.
                    AudioSharingUtils.setPrimary(mContext, cachedDevice);
                    cachedDevice.setActive();
                    AudioSharingUtils.setUserPreferredPrimary(mContext, cachedDevice);
                }
                return;
            }
+2 −3
Original line number Diff line number Diff line
@@ -346,11 +346,10 @@ public class AudioSharingUtils {
        return vc != null && vc.isProfileReady();
    }

    /** Set {@link CachedBluetoothDevice} as primary device for call audio */
    public static void setPrimary(
    /** Set {@link CachedBluetoothDevice} as user preferred primary device for call audio */
    public static void setUserPreferredPrimary(
            @NonNull Context context, @Nullable CachedBluetoothDevice cachedDevice) {
        if (cachedDevice == null) return;
        cachedDevice.setActive();
        if (BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(context)) {
            int groupId = BluetoothUtils.getGroupId(cachedDevice);
            // TODO: use real key name in SettingsProvider
+38 −8
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -67,6 +68,7 @@ import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -77,7 +79,6 @@ import com.android.settingslib.flags.Flags;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;

import org.junit.After;
import org.junit.Before;
@@ -89,8 +90,10 @@ import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowListView;
import org.robolectric.shadows.androidx.fragment.FragmentController;

import java.util.ArrayList;
@@ -483,19 +486,46 @@ public class AudioSharingCallAudioPreferenceControllerTest {
        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
        assertThat(dialog.isShowing()).isTrue();
        assertThat(dialog.getListView().getCount()).isEqualTo(2);
        ArrayList<View> outViews = new ArrayList<>();
        dialog.getListView()
                .findViewsWithText(outViews, TEST_DEVICE_NAME1, View.FIND_VIEWS_WITH_TEXT);
        assertThat(outViews.size()).isEqualTo(1);
        View view = Iterables.getOnlyElement(outViews);
        assertThat(view instanceof CheckedTextView).isTrue();
        assertThat(((CheckedTextView) view).isChecked()).isTrue();
        ShadowListView listView = Shadows.shadowOf(dialog.getListView());
        View view1 = listView.findItemContainingText(TEST_DEVICE_NAME1);
        assertThat(view1).isNotNull();
        assertThat(view1 instanceof CheckedTextView).isTrue();
        assertThat(((CheckedTextView) view1).isChecked()).isTrue();
        View view2 = listView.findItemContainingText(TEST_DEVICE_NAME2);
        assertThat(view2).isNotNull();
        assertThat(view2 instanceof CheckedTextView).isTrue();
        assertThat(((CheckedTextView) view2).isChecked()).isFalse();

        verify(mFeatureFactory.metricsFeatureProvider)
                .visible(
                        /* context= */ eq(null),
                        /* source= */ anyInt(),
                        eq(SettingsEnums.DIALOG_AUDIO_SHARING_CALL_AUDIO),
                        /* latency= */ anyInt());

        LeAudioProfile leAudioProfile = mock(LeAudioProfile.class);
        when(mBtProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);

        // Perform click to switch call audio device by set active
        mSetFlagsRule.disableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API);
        int index = listView.findIndexOfItemContainingText(TEST_DEVICE_NAME2);
        listView.performItemClick(index);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(((CheckedTextView) view1).isChecked()).isFalse();
        assertThat(((CheckedTextView) view2).isChecked()).isTrue();
        verify(mCachedDevice3).setActive();
        verify(leAudioProfile, never()).setBroadcastToUnicastFallbackGroup(TEST_DEVICE_GROUP_ID2);

        // Perform click to switch call audio device with API
        mSetFlagsRule.enableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API);
        Settings.Secure.putInt(mContentResolver, TEST_SETTINGS_KEY, TEST_DEVICE_GROUP_ID2);
        index = listView.findIndexOfItemContainingText(TEST_DEVICE_NAME1);
        listView.performItemClick(index);
        shadowOf(Looper.getMainLooper()).idle();
        assertThat(((CheckedTextView) view1).isChecked()).isTrue();
        assertThat(((CheckedTextView) view2).isChecked()).isFalse();
        verify(mCachedDevice1, never()).setActive();
        verify(leAudioProfile).setBroadcastToUnicastFallbackGroup(TEST_DEVICE_GROUP_ID1);
    }

    @Test
Loading