Merge "Check all member devices to determine whether it's LeAudio-only device" into main

This commit is contained in:
Haijie Hong
2024-07-12 07:44:43 +00:00
committed by Android (Google) Code Review
2 changed files with 60 additions and 80 deletions

View File

@@ -43,7 +43,6 @@ import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HeadsetProfile; import com.android.settingslib.bluetooth.HeadsetProfile;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LeAudioProfile; import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile; import com.android.settingslib.bluetooth.LocalBluetoothProfile;
@@ -95,6 +94,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
new HashMap<String, List<CachedBluetoothDevice>>(); new HashMap<String, List<CachedBluetoothDevice>>();
private boolean mIsLeContactSharingEnabled = false; private boolean mIsLeContactSharingEnabled = false;
private boolean mIsLeAudioToggleEnabled = false; private boolean mIsLeAudioToggleEnabled = false;
private boolean mIsLeAudioOnlyDevice = false;
@VisibleForTesting @VisibleForTesting
PreferenceCategory mProfilesContainer; PreferenceCategory mProfilesContainer;
@@ -345,6 +345,11 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
result.remove(mManager.getProfileManager().getA2dpProfile()); result.remove(mManager.getProfileManager().getA2dpProfile());
result.remove(mManager.getProfileManager().getHeadsetProfile()); result.remove(mManager.getProfileManager().getHeadsetProfile());
} }
boolean hearingAidSupported = result.contains(
mManager.getProfileManager().getHearingAidProfile());
if (leAudioSupported && !classicAudioSupported && !hearingAidSupported) {
mIsLeAudioOnlyDevice = true;
}
Log.d(TAG, "getProfiles:Map:" + mProfileDeviceMap); Log.d(TAG, "getProfiles:Map:" + mProfileDeviceMap);
return result; return result;
} }
@@ -513,19 +518,6 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
refresh(); refresh();
} }
private boolean isLeAudioOnlyDevice() {
if (mCachedDevice.getProfiles().stream()
.noneMatch(profile -> profile instanceof LeAudioProfile)) {
return false;
}
return mCachedDevice.getProfiles().stream()
.noneMatch(
profile ->
profile instanceof HearingAidProfile
|| profile instanceof A2dpProfile
|| profile instanceof HeadsetProfile);
}
private void updateLeAudioConfig() { private void updateLeAudioConfig() {
mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI, mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true); SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
@@ -534,7 +526,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
boolean isLeEnabledByDefault = boolean isLeEnabledByDefault =
SystemProperties.getBoolean(LE_AUDIO_CONNECTION_BY_DEFAULT_PROPERTY, true); SystemProperties.getBoolean(LE_AUDIO_CONNECTION_BY_DEFAULT_PROPERTY, true);
mIsLeAudioToggleEnabled = isLeAudioToggleVisible || isLeEnabledByDefault; mIsLeAudioToggleEnabled = isLeAudioToggleVisible || isLeEnabledByDefault;
if (Flags.hideLeAudioToggleForLeAudioOnlyDevice() && isLeAudioOnlyDevice()) { if (Flags.hideLeAudioToggleForLeAudioOnlyDevice() && mIsLeAudioOnlyDevice) {
mIsLeAudioToggleEnabled = false; mIsLeAudioToggleEnabled = false;
Log.d( Log.d(
TAG, TAG,

View File

@@ -90,6 +90,9 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
@Mock @Mock
private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager; private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager;
private @Mock A2dpProfile mA2dpProfile;
private @Mock LeAudioProfile mLeAudioProfile;
@Override @Override
public void setUp() { public void setUp() {
super.setUp(); super.setUp();
@@ -103,11 +106,13 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
mConnectableProfiles = new ArrayList<>(); mConnectableProfiles = new ArrayList<>();
when(mLocalManager.getProfileManager()).thenReturn(mProfileManager); when(mLocalManager.getProfileManager()).thenReturn(mProfileManager);
when(mLocalManager.getCachedDeviceManager()).thenReturn(mCachedBluetoothDeviceManager); when(mLocalManager.getCachedDeviceManager()).thenReturn(mCachedBluetoothDeviceManager);
setUpMockProfiles();
when(mCachedBluetoothDeviceManager.getCachedDevicesCopy()) when(mCachedBluetoothDeviceManager.getCachedDevicesCopy())
.thenReturn(ImmutableList.of(mCachedDevice)); .thenReturn(ImmutableList.of(mCachedDevice));
when(mCachedDevice.getConnectableProfiles()).thenAnswer(invocation -> when(mCachedDevice.getConnectableProfiles())
new ArrayList<>(mConnectableProfiles) .thenAnswer(invocation -> new ArrayList<>(mConnectableProfiles));
); when(mCachedDevice.getProfiles())
.thenAnswer(invocation -> ImmutableList.of(mConnectableProfiles));
setupDevice(mDeviceConfig); setupDevice(mDeviceConfig);
mController = new BluetoothDetailsProfilesController(mContext, mFragment, mLocalManager, mController = new BluetoothDetailsProfilesController(mContext, mFragment, mLocalManager,
@@ -389,21 +394,36 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
assertThat(mDevice.getMessageAccessPermission()).isEqualTo(BluetoothDevice.ACCESS_ALLOWED); assertThat(mDevice.getMessageAccessPermission()).isEqualTo(BluetoothDevice.ACCESS_ALLOWED);
} }
private A2dpProfile addMockA2dpProfile(boolean preferred, boolean supportsHighQualityAudio, private void setUpMockProfiles() {
boolean highQualityAudioEnabled) { when(mA2dpProfile.toString()).thenReturn("A2DP");
A2dpProfile profile = mock(A2dpProfile.class); when(mProfileManager.getProfileByName(eq(mA2dpProfile.toString())))
when(mProfileManager.getProfileByName(eq(profile.toString()))).thenReturn(profile); .thenReturn(mA2dpProfile);
when(profile.getNameResource(mDevice)) when(mA2dpProfile.getNameResource(any()))
.thenReturn(com.android.settingslib.R.string.bluetooth_profile_a2dp); .thenReturn(com.android.settingslib.R.string.bluetooth_profile_a2dp);
when(profile.getHighQualityAudioOptionLabel(mDevice)).thenReturn( when(mA2dpProfile.getHighQualityAudioOptionLabel(any())).thenReturn(
mContext.getString(com.android.settingslib.R mContext.getString(com.android.settingslib.R
.string.bluetooth_profile_a2dp_high_quality_unknown_codec)); .string.bluetooth_profile_a2dp_high_quality_unknown_codec));
when(profile.supportsHighQualityAudio(mDevice)).thenReturn(supportsHighQualityAudio); when(mA2dpProfile.isProfileReady()).thenReturn(true);
when(profile.isHighQualityAudioEnabled(mDevice)).thenReturn(highQualityAudioEnabled); when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
when(profile.isEnabled(mDevice)).thenReturn(preferred);
when(profile.isProfileReady()).thenReturn(true); when(mLeAudioProfile.toString()).thenReturn("LE_AUDIO");
mConnectableProfiles.add(profile); when(mLeAudioProfile.getNameResource(any()))
return profile; .thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
when(mLeAudioProfile.isProfileReady()).thenReturn(true);
when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
}
private void addA2dpProfileToDevice(boolean preferred, boolean supportsHighQualityAudio,
boolean highQualityAudioEnabled) {
when(mA2dpProfile.supportsHighQualityAudio(any())).thenReturn(supportsHighQualityAudio);
when(mA2dpProfile.isHighQualityAudioEnabled(any())).thenReturn(highQualityAudioEnabled);
when(mA2dpProfile.isEnabled(any())).thenReturn(preferred);
mConnectableProfiles.add(mA2dpProfile);
}
private void addLeAudioProfileToDevice(boolean enabled) {
when(mLeAudioProfile.isEnabled(any())).thenReturn(enabled);
mConnectableProfiles.add(mLeAudioProfile);
} }
private SwitchPreferenceCompat getHighQualityAudioPref() { private SwitchPreferenceCompat getHighQualityAudioPref() {
@@ -414,7 +434,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
@Test @Test
public void highQualityAudio_prefIsPresentWhenSupported() { public void highQualityAudio_prefIsPresentWhenSupported() {
setupDevice(makeDefaultDeviceConfig()); setupDevice(makeDefaultDeviceConfig());
addMockA2dpProfile(true, true, true); addA2dpProfileToDevice(true, true, true);
showScreen(mController); showScreen(mController);
SwitchPreferenceCompat pref = getHighQualityAudioPref(); SwitchPreferenceCompat pref = getHighQualityAudioPref();
assertThat(pref.getKey()).isEqualTo( assertThat(pref.getKey()).isEqualTo(
@@ -431,7 +451,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
@Test @Test
public void highQualityAudio_prefIsAbsentWhenNotSupported() { public void highQualityAudio_prefIsAbsentWhenNotSupported() {
setupDevice(makeDefaultDeviceConfig()); setupDevice(makeDefaultDeviceConfig());
addMockA2dpProfile(true, false, false); addA2dpProfileToDevice(true, false, false);
showScreen(mController); showScreen(mController);
assertThat(mProfiles.getPreferenceCount()).isEqualTo(2); assertThat(mProfiles.getPreferenceCount()).isEqualTo(2);
SwitchPreferenceCompat pref = (SwitchPreferenceCompat) mProfiles.getPreference(0); SwitchPreferenceCompat pref = (SwitchPreferenceCompat) mProfiles.getPreference(0);
@@ -444,7 +464,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
@Test @Test
public void highQualityAudio_busyDeviceDisablesSwitch() { public void highQualityAudio_busyDeviceDisablesSwitch() {
setupDevice(makeDefaultDeviceConfig()); setupDevice(makeDefaultDeviceConfig());
addMockA2dpProfile(true, true, true); addA2dpProfileToDevice(true, true, true);
when(mCachedDevice.isBusy()).thenReturn(true); when(mCachedDevice.isBusy()).thenReturn(true);
showScreen(mController); showScreen(mController);
SwitchPreferenceCompat pref = getHighQualityAudioPref(); SwitchPreferenceCompat pref = getHighQualityAudioPref();
@@ -454,17 +474,17 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
@Test @Test
public void highQualityAudio_mediaAudioDisabledAndReEnabled() { public void highQualityAudio_mediaAudioDisabledAndReEnabled() {
setupDevice(makeDefaultDeviceConfig()); setupDevice(makeDefaultDeviceConfig());
A2dpProfile audioProfile = addMockA2dpProfile(true, true, true); addA2dpProfileToDevice(true, true, true);
showScreen(mController); showScreen(mController);
assertThat(mProfiles.getPreferenceCount()).isEqualTo(3); assertThat(mProfiles.getPreferenceCount()).isEqualTo(3);
// Disabling media audio should cause the high quality audio switch to disappear, but not // Disabling media audio should cause the high quality audio switch to disappear, but not
// the regular audio one. // the regular audio one.
SwitchPreferenceCompat audioPref = SwitchPreferenceCompat audioPref =
(SwitchPreferenceCompat) mScreen.findPreference(audioProfile.toString()); (SwitchPreferenceCompat) mScreen.findPreference(mA2dpProfile.toString());
audioPref.performClick(); audioPref.performClick();
verify(audioProfile).setEnabled(mDevice, false); verify(mA2dpProfile).setEnabled(mDevice, false);
when(audioProfile.isEnabled(mDevice)).thenReturn(false); when(mA2dpProfile.isEnabled(mDevice)).thenReturn(false);
mController.onDeviceAttributesChanged(); mController.onDeviceAttributesChanged();
assertThat(audioPref.isVisible()).isTrue(); assertThat(audioPref.isVisible()).isTrue();
SwitchPreferenceCompat highQualityAudioPref = getHighQualityAudioPref(); SwitchPreferenceCompat highQualityAudioPref = getHighQualityAudioPref();
@@ -472,8 +492,8 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
// And re-enabling media audio should make high quality switch to reappear. // And re-enabling media audio should make high quality switch to reappear.
audioPref.performClick(); audioPref.performClick();
verify(audioProfile).setEnabled(mDevice, true); verify(mA2dpProfile).setEnabled(mDevice, true);
when(audioProfile.isEnabled(mDevice)).thenReturn(true); when(mA2dpProfile.isEnabled(mDevice)).thenReturn(true);
mController.onDeviceAttributesChanged(); mController.onDeviceAttributesChanged();
highQualityAudioPref = getHighQualityAudioPref(); highQualityAudioPref = getHighQualityAudioPref();
assertThat(highQualityAudioPref.isVisible()).isTrue(); assertThat(highQualityAudioPref.isVisible()).isTrue();
@@ -482,9 +502,9 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
@Test @Test
public void highQualityAudio_mediaAudioStartsDisabled() { public void highQualityAudio_mediaAudioStartsDisabled() {
setupDevice(makeDefaultDeviceConfig()); setupDevice(makeDefaultDeviceConfig());
A2dpProfile audioProfile = addMockA2dpProfile(false, true, true); addA2dpProfileToDevice(false, true, true);
showScreen(mController); showScreen(mController);
SwitchPreferenceCompat audioPref = mScreen.findPreference(audioProfile.toString()); SwitchPreferenceCompat audioPref = mScreen.findPreference(mA2dpProfile.toString());
SwitchPreferenceCompat highQualityAudioPref = getHighQualityAudioPref(); SwitchPreferenceCompat highQualityAudioPref = getHighQualityAudioPref();
assertThat(audioPref).isNotNull(); assertThat(audioPref).isNotNull();
assertThat(audioPref.isChecked()).isFalse(); assertThat(audioPref.isChecked()).isFalse();
@@ -522,15 +542,9 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_BLUETOOTH_PROFILE_TOGGLE_VISIBILITY_CHECKER); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_BLUETOOTH_PROFILE_TOGGLE_VISIBILITY_CHECKER);
setupDevice(makeDefaultDeviceConfig()); setupDevice(makeDefaultDeviceConfig());
LeAudioProfile leAudioProfile = mock(LeAudioProfile.class); addA2dpProfileToDevice(true, true, true);
when(leAudioProfile.getNameResource(mDevice))
.thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
when(leAudioProfile.isProfileReady()).thenReturn(true);
when(leAudioProfile.toString()).thenReturn("LE_AUDIO");
when(mProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);
when(mFeatureProvider.getInvisibleProfilePreferenceKeys(any(), any())) when(mFeatureProvider.getInvisibleProfilePreferenceKeys(any(), any()))
.thenReturn(ImmutableSet.of("LE_AUDIO")); .thenReturn(ImmutableSet.of("A2DP"));
mConnectableProfiles.add(leAudioProfile);
showScreen(mController); showScreen(mController);
@@ -543,15 +557,9 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_BLUETOOTH_PROFILE_TOGGLE_VISIBILITY_CHECKER); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_BLUETOOTH_PROFILE_TOGGLE_VISIBILITY_CHECKER);
setupDevice(makeDefaultDeviceConfig()); setupDevice(makeDefaultDeviceConfig());
LeAudioProfile leAudioProfile = mock(LeAudioProfile.class); addA2dpProfileToDevice(true, true, true);
when(leAudioProfile.getNameResource(mDevice))
.thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
when(leAudioProfile.isProfileReady()).thenReturn(true);
when(leAudioProfile.toString()).thenReturn("LE_AUDIO");
when(mProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);
when(mFeatureProvider.getInvisibleProfilePreferenceKeys(any(), any())) when(mFeatureProvider.getInvisibleProfilePreferenceKeys(any(), any()))
.thenReturn(ImmutableSet.of("A2DP")); .thenReturn(ImmutableSet.of("LE_AUDIO"));
mConnectableProfiles.add(leAudioProfile);
showScreen(mController); showScreen(mController);
@@ -563,19 +571,8 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
public void classicAudioDeviceWithLeAudio_showLeAudioToggle() { public void classicAudioDeviceWithLeAudio_showLeAudioToggle() {
mSetFlagsRule.enableFlags(Flags.FLAG_HIDE_LE_AUDIO_TOGGLE_FOR_LE_AUDIO_ONLY_DEVICE); mSetFlagsRule.enableFlags(Flags.FLAG_HIDE_LE_AUDIO_TOGGLE_FOR_LE_AUDIO_ONLY_DEVICE);
setupDevice(makeDefaultDeviceConfig()); setupDevice(makeDefaultDeviceConfig());
addLeAudioProfileToDevice(false);
LeAudioProfile leAudioProfile = mock(LeAudioProfile.class); addA2dpProfileToDevice(false, false, false);
when(leAudioProfile.getNameResource(mDevice))
.thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
when(leAudioProfile.isProfileReady()).thenReturn(true);
when(leAudioProfile.toString()).thenReturn("LE_AUDIO");
when(mProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);
mConnectableProfiles.add(leAudioProfile);
when(mCachedDevice.getProfiles())
.thenAnswer(
invocation ->
ImmutableList.of(
leAudioProfile, addMockA2dpProfile(false, false, false)));
showScreen(mController); showScreen(mController);
@@ -587,16 +584,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
public void leAudioOnlyDevice_hideLeAudioToggle() { public void leAudioOnlyDevice_hideLeAudioToggle() {
mSetFlagsRule.enableFlags(Flags.FLAG_HIDE_LE_AUDIO_TOGGLE_FOR_LE_AUDIO_ONLY_DEVICE); mSetFlagsRule.enableFlags(Flags.FLAG_HIDE_LE_AUDIO_TOGGLE_FOR_LE_AUDIO_ONLY_DEVICE);
setupDevice(makeDefaultDeviceConfig()); setupDevice(makeDefaultDeviceConfig());
addLeAudioProfileToDevice(false);
LeAudioProfile leAudioProfile = mock(LeAudioProfile.class);
when(leAudioProfile.getNameResource(mDevice))
.thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
when(leAudioProfile.isProfileReady()).thenReturn(true);
when(leAudioProfile.toString()).thenReturn("LE_AUDIO");
when(mProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);
mConnectableProfiles.add(leAudioProfile);
when(mCachedDevice.getProfiles())
.thenAnswer(invocation -> ImmutableList.of(leAudioProfile));
showScreen(mController); showScreen(mController);