[Audiosharing] Save user preferred primary headset to SettingsProvider
In hysteresis mode, we will receive plenty of onReceiveStateChanged, e.g. play and pause music, system sounds... The onReceiveStateChanged with BIS >= 1, as a replacement of onSourceAdded, will trigger auto pick logic for primary headset. In some cases, when user change primary headset in Call audio section on audio sharing page under the hysteresis mode, the system sound will later trigger a onReceiveStateChanged with BIS >= 1, then the auto pick logic (always pick the earliest connected headset) is possible to override the user change. Thus here we have to save the user preferred primary headset in SettingsProvider and skip the auto pick if user has made changes.
Test: atest
Bug: 355222285
Flag: com.android.settingslib.flags.audio_sharing_hysteresis_mode_fix
Change-Id: I5ccf743eb685509ffcc3c7a88051726c10fe2567
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java
index 468ac3d..11a337f 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java
@@ -219,7 +219,7 @@
if (lead != null) {
String addr = lead.getDevice().getAnonymizedAddress();
Log.d(TAG, "Set call audio device: " + addr);
- lead.setActive();
+ AudioSharingUtils.setPrimary(mContext, lead);
logCallAudioDeviceChange(currentGroupId, lead);
} else {
Log.d(TAG, "Skip set call audio device: no lead");
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
index db2c7b2..47623e4 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
@@ -390,7 +390,7 @@
Log.d(TAG, "onDeviceClick, set active in call mode");
CachedBluetoothDevice cachedDevice =
((BluetoothDevicePreference) preference).getBluetoothDevice();
- cachedDevice.setActive();
+ AudioSharingUtils.setPrimary(mContext, cachedDevice);
}
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUDIO_SHARING_DEVICE_CLICK,
isCallMode);
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java
index 396144a..0c34487 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java
@@ -192,7 +192,7 @@
// 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.
- cachedDevice.setActive();
+ AudioSharingUtils.setPrimary(mContext, cachedDevice);
}
return;
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
index a662809..592c8eb 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
@@ -21,6 +21,7 @@
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID;
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID;
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED;
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID;
import static java.util.stream.Collectors.toList;
@@ -28,6 +29,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.content.Context;
+import android.provider.Settings;
import android.util.Log;
import android.util.Pair;
import android.widget.Toast;
@@ -44,6 +46,7 @@
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.bluetooth.VolumeControlProfile;
+import com.android.settingslib.flags.Flags;
import java.util.ArrayList;
import java.util.Comparator;
@@ -344,6 +347,27 @@
return vc != null && vc.isProfileReady();
}
+ /** Set {@link CachedBluetoothDevice} as primary device for call audio */
+ public static void setPrimary(@NonNull Context context,
+ @Nullable CachedBluetoothDevice cachedDevice) {
+ if (cachedDevice == null) return;
+ cachedDevice.setActive();
+ if (Flags.audioSharingHysteresisModeFix()) {
+ int groupId = BluetoothUtils.getGroupId(cachedDevice);
+ // TODO: use real key name in SettingsProvider
+ int userPreferredId = Settings.Secure.getInt(
+ context.getContentResolver(),
+ BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ if (groupId != userPreferredId) {
+ Settings.Secure.putInt(
+ context.getContentResolver(),
+ BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
+ groupId);
+ }
+ }
+ }
+
/**
* Build audio sharing dialog log event data
*
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java
index 61bc8aa..0bc0b94 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java
@@ -18,6 +18,7 @@
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE;
import static com.google.common.truth.Truth.assertThat;
@@ -37,6 +38,7 @@
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
@@ -50,6 +52,7 @@
import android.os.Bundle;
import android.os.Looper;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
import android.util.Pair;
import androidx.annotation.NonNull;
@@ -587,6 +590,10 @@
@Test
public void testInCallState_showCallStateTitleAndSetActiveOnDeviceClick() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
mController.displayPreference(mScreen);
mAudioManager.setMode(AudioManager.MODE_IN_CALL);
@@ -599,6 +606,32 @@
BluetoothDevicePreference preference = createBluetoothDevicePreference();
mController.onDeviceClick(preference);
verify(mCachedDevice).setActive();
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID)).isEqualTo(
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ }
+
+ @Test
+ public void testInCallState_enableHysteresisFix_setAndSaveActiveOnDeviceClick() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ mController.displayPreference(mScreen);
+
+ mAudioManager.setMode(AudioManager.MODE_IN_CALL);
+ mController.onAudioModeChanged();
+ shadowOf(Looper.getMainLooper()).idle();
+
+ BluetoothDevicePreference preference = createBluetoothDevicePreference();
+ when(mCachedDevice.getGroupId()).thenReturn(1);
+ mController.onDeviceClick(preference);
+ verify(mCachedDevice).setActive();
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID)).isEqualTo(1);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java
index ad6dd7f..c96a086 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java
@@ -16,6 +16,8 @@
package com.android.settings.connecteddevice.audiosharing;
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -32,6 +34,7 @@
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastMetadata;
@@ -43,6 +46,7 @@
import android.os.Bundle;
import android.os.Looper;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
import android.util.Pair;
import androidx.fragment.app.DialogFragment;
@@ -193,6 +197,10 @@
@Test
public void handleUserTriggeredDeviceConnected_inCall_setActive() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);
setUpBroadcast(true);
ImmutableList<BluetoothDevice> deviceList = ImmutableList.of(mDevice1);
@@ -201,6 +209,29 @@
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ true);
shadowOf(Looper.getMainLooper()).idle();
verify(mCachedDevice1).setActive();
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID)).isEqualTo(
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ }
+
+ @Test
+ public void handleUserTriggeredDeviceConnected_inCall_enableHysteresisFix_setAndSaveActive() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);
+ setUpBroadcast(true);
+ ImmutableList<BluetoothDevice> deviceList = ImmutableList.of(mDevice1);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(deviceList);
+ when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of());
+ mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ true);
+ shadowOf(Looper.getMainLooper()).idle();
+ verify(mCachedDevice1).setActive();
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ BLUETOOTH_LE_BROADCAST_PRIMARY_DEVICE_GROUP_ID,
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID)).isEqualTo(1);
}
@Test