From c55cddc42272672063fc5199f5562845d94851c8 Mon Sep 17 00:00:00 2001 From: Patty Huang Date: Fri, 13 Jan 2023 18:58:27 +0800 Subject: [PATCH] Add LE Audio allow list feature switcher in the developer option menu Add a switcher to enable/disable LE audio allow list feature. The switcher could be enabled by setprop ro.bluetooth.leaudio_allow_list.supported=true Bug: 239768625 Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothLeAudioAllowListPreferenceControllerTest Change-Id: I290da870d952abd20bc25db7924fcc53ac39f880 --- res/values/strings.xml | 5 + res/xml/development_settings.xml | 5 + ...hLeAudioAllowListPreferenceController.java | 129 ++++++++++++++++++ .../DevelopmentSettingsDashboardFragment.java | 11 ++ ...udioAllowListPreferenceControllerTest.java | 106 ++++++++++++++ 5 files changed, 256 insertions(+) create mode 100644 src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 249c2de990d..4b55f5809df 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -365,6 +365,11 @@ Enables Bluetooth LE audio feature if the device supports LE audio hardware capabilities. + + Enable Bluetooth LE audio Allow List + + Enable Bluetooth LE audio allow list feature. + Media devices diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml index b1b90171905..973d5b34def 100644 --- a/res/xml/development_settings.xml +++ b/res/xml/development_settings.xml @@ -324,6 +324,11 @@ android:title="@string/bluetooth_enable_leaudio" android:summary="@string/bluetooth_enable_leaudio_summary" /> + + diff --git a/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceController.java new file mode 100644 index 00000000000..23506b3ccc3 --- /dev/null +++ b/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceController.java @@ -0,0 +1,129 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.development; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; +import android.bluetooth.BluetoothStatusCodes; +import android.content.Context; +import android.os.SystemProperties; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.SwitchPreference; + +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settingslib.development.DeveloperOptionsPreferenceController; + +/** + * Preference controller to control Bluetooth LE audio feature + */ +public class BluetoothLeAudioAllowListPreferenceController + extends DeveloperOptionsPreferenceController + implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { + + private static final String PREFERENCE_KEY = "bluetooth_enable_leaudio_allow_list"; + + private static final String LE_AUDIO_ALLOW_LIST_SWITCH_SUPPORT_PROPERTY = + "ro.bluetooth.leaudio_allow_list.supported"; + @VisibleForTesting + static final String LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY = + "persist.bluetooth.leaudio.enable_allow_list"; + + private static final String LE_AUDIO_DYNAMIC_SWITCH_PROPERTY = + "ro.bluetooth.leaudio_switcher.supported"; + @VisibleForTesting + static final String LE_AUDIO_DYNAMIC_ENABLED_PROPERTY = + "persist.bluetooth.leaudio_switcher.enabled"; + + @VisibleForTesting + BluetoothAdapter mBluetoothAdapter; + + private final DevelopmentSettingsDashboardFragment mFragment; + + @VisibleForTesting + boolean mChanged = false; + + public BluetoothLeAudioAllowListPreferenceController(Context context, + DevelopmentSettingsDashboardFragment fragment) { + super(context); + mFragment = fragment; + mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter(); + } + + @Override + public String getPreferenceKey() { + return PREFERENCE_KEY; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + BluetoothRebootDialog.show(mFragment); + mChanged = true; + return false; + } + + @Override + public void updateState(Preference preference) { + if (mBluetoothAdapter == null) { + return; + } + + int leAudioSupportedState = mBluetoothAdapter.isLeAudioSupported(); + boolean leAudioEnabled = false; + + if ((leAudioSupportedState == BluetoothStatusCodes.FEATURE_SUPPORTED) + || (leAudioSupportedState == BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED + && SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_SWITCH_PROPERTY, false) + && SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY, false))) { + leAudioEnabled = true; + } + + final boolean leAudioAllowListSupport = + SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_SWITCH_SUPPORT_PROPERTY, false); + + if (leAudioEnabled && leAudioAllowListSupport) { + final boolean leAudioAllowListEnabled = + SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false); + ((SwitchPreference) mPreference).setChecked(leAudioAllowListEnabled); + } else { + mPreference.setEnabled(false); + ((SwitchPreference) mPreference).setChecked(false); + } + } + + /** + * Called when the RebootDialog confirm is clicked. + */ + public void onRebootDialogConfirmed() { + if (!mChanged) { + return; + } + + final boolean leAudioAllowListEnabled = + SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false); + SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, + Boolean.toString(!leAudioAllowListEnabled)); + } + + /** + * Called when the RebootDialog cancel is clicked. + */ + public void onRebootDialogCanceled() { + mChanged = false; + } +} diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index d92fb7fd99b..22f831e99ec 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -376,6 +376,11 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra getDevelopmentOptionsController( BluetoothLeAudioPreferenceController.class); leAudioFeatureController.onRebootDialogConfirmed(); + + final BluetoothLeAudioAllowListPreferenceController leAudioAllowListController = + getDevelopmentOptionsController( + BluetoothLeAudioAllowListPreferenceController.class); + leAudioAllowListController.onRebootDialogConfirmed(); } @Override @@ -393,6 +398,11 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra getDevelopmentOptionsController( BluetoothLeAudioPreferenceController.class); leAudioFeatureController.onRebootDialogCanceled(); + + final BluetoothLeAudioAllowListPreferenceController leAudioAllowListController = + getDevelopmentOptionsController( + BluetoothLeAudioAllowListPreferenceController.class); + leAudioAllowListController.onRebootDialogCanceled(); } @Override @@ -551,6 +561,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra controllers.add(new BluetoothAvrcpVersionPreferenceController(context)); controllers.add(new BluetoothMapVersionPreferenceController(context)); controllers.add(new BluetoothLeAudioPreferenceController(context, fragment)); + controllers.add(new BluetoothLeAudioAllowListPreferenceController(context, fragment)); controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment)); controllers.add(new BluetoothLeAudioHwOffloadPreferenceController(context, fragment)); controllers.add(new BluetoothMaxConnectedAudioDevicesPreferenceController(context)); diff --git a/tests/robotests/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceControllerTest.java new file mode 100644 index 00000000000..f4e52bada6a --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceControllerTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.development; + +import static android.bluetooth.BluetoothStatusCodes.FEATURE_SUPPORTED; + +import static com.android.settings.development.BluetoothLeAudioAllowListPreferenceController + .LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothAdapter; +import android.content.Context; +import android.os.SystemProperties; + +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class BluetoothLeAudioAllowListPreferenceControllerTest { + + @Mock + private PreferenceScreen mPreferenceScreen; + @Mock + private DevelopmentSettingsDashboardFragment mFragment; + + @Mock + private BluetoothAdapter mBluetoothAdapter; + + private Context mContext; + private SwitchPreference mPreference; + private BluetoothLeAudioPreferenceController mController; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mPreference = new SwitchPreference(mContext); + mController = spy(new BluetoothLeAudioPreferenceController(mContext, mFragment)); + when(mPreferenceScreen.findPreference(mController.getPreferenceKey())) + .thenReturn(mPreference); + mController.mBluetoothAdapter = mBluetoothAdapter; + mController.displayPreference(mPreferenceScreen); + when(mBluetoothAdapter.isLeAudioSupported()) + .thenReturn(FEATURE_SUPPORTED); + } + + @Test + public void onRebootDialogConfirmedAsLeAudioAllowListDisabled_shouldSwitchStatus() { + SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(false)); + mController.mChanged = true; + + mController.onRebootDialogConfirmed(); + final boolean mode = SystemProperties.getBoolean( + LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false); + assertThat(mode).isFalse(); + } + + + @Test + public void onRebootDialogConfirmedAsLeAudioAllowListEnabled_shouldSwitchStatus() { + SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(true)); + mController.mChanged = true; + + mController.onRebootDialogConfirmed(); + final boolean status = SystemProperties.getBoolean( + LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false); + assertThat(status).isTrue(); + } + + @Test + public void onRebootDialogCanceled_shouldNotSwitchStatus() { + SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(false)); + mController.mChanged = true; + + mController.onRebootDialogCanceled(); + final boolean status = SystemProperties.getBoolean( + LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false); + assertThat(status).isFalse(); + } +}