Loading packages/SettingsLib/aconfig/settingslib.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -52,3 +52,13 @@ flag { 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 } } packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +28 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -288,6 +290,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> mLocalNapRoleConnected = true; } } if (enableSetPreferredTransportForLeAudioDevice() && profile instanceof HidProfile) { updatePreferredTransport(); } } else if (profile instanceof MapProfile && newProfileState == BluetoothProfile.STATE_DISCONNECTED) { profile.setEnabled(mDevice, false); Loading @@ -300,12 +306,34 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> 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) { Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java +10 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.bluetooth.BluetoothProfile; import android.content.Context; import android.util.Log; import androidx.annotation.NonNull; import com.android.settingslib.R; import java.util.List; Loading Loading @@ -187,6 +189,14 @@ public class HidProfile implements LocalBluetoothProfile { } } /** 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) { Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +1 −2 Original line number Diff line number Diff line Loading @@ -572,8 +572,7 @@ public class LocalBluetoothProfileManager { return mSapProfile; } @VisibleForTesting HidProfile getHidProfile() { public HidProfile getHidProfile() { return mHidProfile; } Loading packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +34 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -86,6 +88,9 @@ public class CachedBluetoothDeviceTest { private HapClientProfile mHapClientProfile; @Mock private LeAudioProfile mLeAudioProfile; @Mock private HidProfile mHidProfile; @Mock private BluetoothDevice mDevice; @Mock Loading @@ -104,6 +109,7 @@ public class CachedBluetoothDeviceTest { 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()); Loading @@ -118,6 +124,8 @@ public class CachedBluetoothDeviceTest { 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(); Loading Loading @@ -1819,6 +1827,32 @@ public class CachedBluetoothDeviceTest { 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) Loading Loading
packages/SettingsLib/aconfig/settingslib.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -52,3 +52,13 @@ flag { 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 } }
packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +28 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -288,6 +290,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> mLocalNapRoleConnected = true; } } if (enableSetPreferredTransportForLeAudioDevice() && profile instanceof HidProfile) { updatePreferredTransport(); } } else if (profile instanceof MapProfile && newProfileState == BluetoothProfile.STATE_DISCONNECTED) { profile.setEnabled(mDevice, false); Loading @@ -300,12 +306,34 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> 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) { Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java +10 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.bluetooth.BluetoothProfile; import android.content.Context; import android.util.Log; import androidx.annotation.NonNull; import com.android.settingslib.R; import java.util.List; Loading Loading @@ -187,6 +189,14 @@ public class HidProfile implements LocalBluetoothProfile { } } /** 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) { Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +1 −2 Original line number Diff line number Diff line Loading @@ -572,8 +572,7 @@ public class LocalBluetoothProfileManager { return mSapProfile; } @VisibleForTesting HidProfile getHidProfile() { public HidProfile getHidProfile() { return mHidProfile; } Loading
packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +34 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -86,6 +88,9 @@ public class CachedBluetoothDeviceTest { private HapClientProfile mHapClientProfile; @Mock private LeAudioProfile mLeAudioProfile; @Mock private HidProfile mHidProfile; @Mock private BluetoothDevice mDevice; @Mock Loading @@ -104,6 +109,7 @@ public class CachedBluetoothDeviceTest { 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()); Loading @@ -118,6 +124,8 @@ public class CachedBluetoothDeviceTest { 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(); Loading Loading @@ -1819,6 +1827,32 @@ public class CachedBluetoothDeviceTest { 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) Loading