Merge "[Audiosharing] Use setBroadcastToUnicastFallbackGroup to set primary" into main
This commit is contained in:
@@ -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.
|
||||
*
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -584,6 +584,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
||||
public void testInCallState_showCallStateTitleAndSetActiveOnDeviceClick() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API);
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
|
||||
BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
|
||||
@@ -609,6 +610,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
||||
public void testInCallState_enableHysteresisFix_setAndSaveActiveOnDeviceClick() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API);
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
|
||||
BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
|
||||
|
@@ -198,6 +198,7 @@ public class AudioSharingDialogHandlerTest {
|
||||
@Test
|
||||
public void handleUserTriggeredDeviceConnected_inCall_setActive() {
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API);
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
|
||||
BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
|
||||
@@ -218,6 +219,7 @@ public class AudioSharingDialogHandlerTest {
|
||||
@Test
|
||||
public void handleUserTriggeredDeviceConnected_inCall_enableHysteresisFix_setAndSaveActive() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API);
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
|
||||
BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
|
||||
@@ -452,6 +454,7 @@ public class AudioSharingDialogHandlerTest {
|
||||
|
||||
@Test
|
||||
public void handleDeviceConnected_inCall_doNothing() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API);
|
||||
when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);
|
||||
setUpBroadcast(true);
|
||||
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of());
|
||||
|
Reference in New Issue
Block a user