Update preferred transport when HID and LeAudio profile are connected
Bug: 330581926
Test: atest CachedBluetoothDeviceTest
Change-Id: Ib7d42a74c4d174ee61efd2fa6eb7eafd963f9c40
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 54c5a14..a6d6eee 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -51,3 +51,13 @@
description: "Hide exclusively managed Bluetooth devices in BT settings menu."
bug: "324475542"
}
+
+flag {
+ name: "enable_set_preferred_transport_for_le_audio_device"
+ namespace: "bluetooth"
+ description: "Enable setting preferred transport for Le Audio device"
+ bug: "330581926"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 4777b0d..04516eb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -16,6 +16,8 @@
package com.android.settingslib.bluetooth;
+import static com.android.settingslib.flags.Flags.enableSetPreferredTransportForLeAudioDevice;
+
import android.annotation.CallbackExecutor;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
@@ -288,6 +290,10 @@
mLocalNapRoleConnected = true;
}
}
+ if (enableSetPreferredTransportForLeAudioDevice()
+ && profile instanceof HidProfile) {
+ updatePreferredTransport();
+ }
} else if (profile instanceof MapProfile
&& newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
profile.setEnabled(mDevice, false);
@@ -300,12 +306,34 @@
mLocalNapRoleConnected = false;
}
+ if (enableSetPreferredTransportForLeAudioDevice()
+ && profile instanceof LeAudioProfile) {
+ updatePreferredTransport();
+ }
+
HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, this, profile, newProfileState);
}
fetchActiveDevices();
}
+ private void updatePreferredTransport() {
+ if (mProfiles.stream().noneMatch(p -> p instanceof LeAudioProfile)
+ || mProfiles.stream().noneMatch(p -> p instanceof HidProfile)) {
+ return;
+ }
+ // Both LeAudioProfile and HidProfile are connectable.
+ if (!mProfileManager
+ .getHidProfile()
+ .setPreferredTransport(
+ mDevice,
+ mProfileManager.getLeAudioProfile().isEnabled(mDevice)
+ ? BluetoothDevice.TRANSPORT_LE
+ : BluetoothDevice.TRANSPORT_BREDR)) {
+ Log.w(TAG, "Fail to set preferred transport");
+ }
+ }
+
@VisibleForTesting
void setProfileConnectedStatus(int profileId, boolean isFailed) {
switch (profileId) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 5b91ac9..b849d44 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -27,6 +27,8 @@
import android.content.Context;
import android.util.Log;
+import androidx.annotation.NonNull;
+
import com.android.settingslib.R;
import java.util.List;
@@ -187,6 +189,14 @@
}
}
+ /** Set preferred transport for the device */
+ public boolean setPreferredTransport(@NonNull BluetoothDevice device, int transport) {
+ if (mService != null) {
+ mService.setPreferredTransport(device, transport);
+ }
+ return false;
+ }
+
protected void finalize() {
Log.d(TAG, "finalize()");
if (mService != null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 79e4c37..4055986 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -572,8 +572,7 @@
return mSapProfile;
}
- @VisibleForTesting
- HidProfile getHidProfile() {
+ public HidProfile getHidProfile() {
return mHidProfile;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 5996dbb..646e9eb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -15,6 +15,8 @@
*/
package com.android.settingslib.bluetooth;
+import static com.android.settingslib.flags.Flags.FLAG_ENABLE_SET_PREFERRED_TRANSPORT_FOR_LE_AUDIO_DEVICE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -86,6 +88,9 @@
private HapClientProfile mHapClientProfile;
@Mock
private LeAudioProfile mLeAudioProfile;
+
+ @Mock
+ private HidProfile mHidProfile;
@Mock
private BluetoothDevice mDevice;
@Mock
@@ -104,6 +109,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TV_MEDIA_OUTPUT_DIALOG);
+ mSetFlagsRule.enableFlags(FLAG_ENABLE_SET_PREFERRED_TRANSPORT_FOR_LE_AUDIO_DEVICE);
mContext = RuntimeEnvironment.application;
mAudioManager = mContext.getSystemService(AudioManager.class);
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
@@ -118,6 +124,8 @@
when(mHearingAidProfile.getProfileId()).thenReturn(BluetoothProfile.HEARING_AID);
when(mLeAudioProfile.isProfileReady()).thenReturn(true);
when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO);
+ when(mHidProfile.isProfileReady()).thenReturn(true);
+ when(mHidProfile.getProfileId()).thenReturn(BluetoothProfile.HID_HOST);
mCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mDevice));
mSubCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mSubDevice));
doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel();
@@ -1819,6 +1827,32 @@
assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse();
}
+ @Test
+ public void leAudioHidDevice_leAudioEnabled_setPreferredTransportToLE() {
+
+ when(mProfileManager.getHidProfile()).thenReturn(mHidProfile);
+ when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
+ when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);
+
+ updateProfileStatus(mHidProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED);
+
+ verify(mHidProfile).setPreferredTransport(mDevice, BluetoothDevice.TRANSPORT_LE);
+ }
+
+ @Test
+ public void leAudioHidDevice_leAudioDisabled_setPreferredTransportToBredr() {
+ when(mProfileManager.getHidProfile()).thenReturn(mHidProfile);
+ when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
+ when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(false);
+
+ updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHidProfile, BluetoothProfile.STATE_CONNECTED);
+
+ verify(mHidProfile).setPreferredTransport(mDevice, BluetoothDevice.TRANSPORT_BREDR);
+ }
+
private HearingAidInfo getLeftAshaHearingAidInfo() {
return new HearingAidInfo.Builder()
.setAshaDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT)