Make bluetooth profile toggles configurable
BUG: 343317785 Test: atest BluetoothDetailsProfilesControllerTest Flag: com.android.settings.flags.enable_bluetooth_device_details_polish Change-Id: I5aea110f7a42ffee20a56dbd9d5621f44311cc66
This commit is contained in:
@@ -26,6 +26,7 @@ import android.sysprop.BluetoothProperties;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
@@ -52,7 +53,9 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -82,7 +85,9 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
||||
private static final String LE_AUDIO_TOGGLE_VISIBLE_PROPERTY =
|
||||
"persist.bluetooth.leaudio.toggle_visible";
|
||||
|
||||
private final AtomicReference<Set<String>> mInvisiblePreferenceKey = new AtomicReference<>();
|
||||
private Set<String> mInvisibleProfiles = Collections.emptySet();
|
||||
private final AtomicReference<Set<String>> mAdditionalInvisibleProfiles =
|
||||
new AtomicReference<>();
|
||||
|
||||
private LocalBluetoothManager mManager;
|
||||
private LocalBluetoothProfileManager mProfileManager;
|
||||
@@ -96,13 +101,21 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
||||
@VisibleForTesting
|
||||
PreferenceCategory mProfilesContainer;
|
||||
|
||||
public BluetoothDetailsProfilesController(Context context, PreferenceFragmentCompat fragment,
|
||||
LocalBluetoothManager manager, CachedBluetoothDevice device, Lifecycle lifecycle) {
|
||||
public BluetoothDetailsProfilesController(
|
||||
Context context,
|
||||
PreferenceFragmentCompat fragment,
|
||||
LocalBluetoothManager manager,
|
||||
CachedBluetoothDevice device,
|
||||
Lifecycle lifecycle,
|
||||
@Nullable List<String> invisibleProfiles) {
|
||||
super(context, fragment, device, lifecycle);
|
||||
mManager = manager;
|
||||
mProfileManager = mManager.getProfileManager();
|
||||
mCachedDevice = device;
|
||||
mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice);
|
||||
if (invisibleProfiles != null) {
|
||||
mInvisibleProfiles = Set.copyOf(invisibleProfiles);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -564,7 +577,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
||||
protected void refresh() {
|
||||
ThreadUtils.postOnBackgroundThread(
|
||||
() -> {
|
||||
mInvisiblePreferenceKey.set(
|
||||
mAdditionalInvisibleProfiles.set(
|
||||
FeatureFactory.getFeatureFactory()
|
||||
.getBluetoothFeatureProvider()
|
||||
.getInvisibleProfilePreferenceKeys(
|
||||
@@ -605,12 +618,15 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
||||
mProfilesContainer.addPreference(preference);
|
||||
}
|
||||
|
||||
Set<String> invisibleKeys = mInvisiblePreferenceKey.get();
|
||||
if (invisibleKeys != null) {
|
||||
for (int i = 0; i < mProfilesContainer.getPreferenceCount(); ++i) {
|
||||
Preference pref = mProfilesContainer.getPreference(i);
|
||||
pref.setVisible(pref.isVisible() && !invisibleKeys.contains(pref.getKey()));
|
||||
}
|
||||
Set<String> additionalInvisibleProfiles = mAdditionalInvisibleProfiles.get();
|
||||
HashSet<String> combinedInvisibleProfiles = new HashSet<>(mInvisibleProfiles);
|
||||
if (additionalInvisibleProfiles != null) {
|
||||
combinedInvisibleProfiles.addAll(additionalInvisibleProfiles);
|
||||
}
|
||||
Log.i(TAG, "Invisible profiles: " + combinedInvisibleProfiles);
|
||||
for (int i = 0; i < mProfilesContainer.getPreferenceCount(); ++i) {
|
||||
Preference pref = mProfilesContainer.getPreference(i);
|
||||
pref.setVisible(pref.isVisible() && !combinedInvisibleProfiles.contains(pref.getKey()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -419,12 +419,16 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
||||
|
||||
@Override
|
||||
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||
List<String> invisibleProfiles = List.of();
|
||||
if (Flags.enableBluetoothDeviceDetailsPolish()) {
|
||||
mFormatter =
|
||||
FeatureFactory.getFeatureFactory()
|
||||
.getBluetoothFeatureProvider()
|
||||
.getDeviceDetailsFragmentFormatter(
|
||||
requireContext(), this, mBluetoothAdapter, mCachedDevice);
|
||||
invisibleProfiles =
|
||||
mFormatter.getInvisibleBluetoothProfiles(
|
||||
FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
|
||||
}
|
||||
ArrayList<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
|
||||
@@ -444,7 +448,7 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
||||
controllers.add(new BluetoothDetailsSpatialAudioController(context, this, mCachedDevice,
|
||||
lifecycle));
|
||||
controllers.add(new BluetoothDetailsProfilesController(context, this, mManager,
|
||||
mCachedDevice, lifecycle));
|
||||
mCachedDevice, lifecycle, invisibleProfiles));
|
||||
controllers.add(new BluetoothDetailsMacAddressController(context, this, mCachedDevice,
|
||||
lifecycle));
|
||||
controllers.add(new StylusDevicesController(context, mInputDevice, mCachedDevice,
|
||||
|
@@ -43,6 +43,7 @@ import com.android.settings.core.SubSettingLauncher
|
||||
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
|
||||
import com.android.settings.spa.preference.ComposePreference
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
||||
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
|
||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
|
||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
|
||||
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
||||
@@ -68,6 +69,9 @@ interface DeviceDetailsFragmentFormatter {
|
||||
/** Gets keys of visible preferences in built-in preference in xml. */
|
||||
fun getVisiblePreferenceKeys(fragmentType: FragmentTypeModel): List<String>?
|
||||
|
||||
/** Updates device details fragment layout. */
|
||||
fun getInvisibleBluetoothProfiles(fragmentType: FragmentTypeModel): List<String>?
|
||||
|
||||
/** Updates device details fragment layout. */
|
||||
fun updateLayout(fragmentType: FragmentTypeModel)
|
||||
|
||||
@@ -108,13 +112,22 @@ class DeviceDetailsFragmentFormatterImpl(
|
||||
viewModel
|
||||
.getItems(fragmentType)
|
||||
?.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
|
||||
?.mapNotNull { it.preferenceKey }
|
||||
?.map { it.preferenceKey }
|
||||
}
|
||||
|
||||
override fun getInvisibleBluetoothProfiles(fragmentType: FragmentTypeModel): List<String>? =
|
||||
runBlocking {
|
||||
viewModel
|
||||
.getItems(fragmentType)
|
||||
?.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem.BluetoothProfilesItem>()
|
||||
?.first()?.invisibleProfiles
|
||||
}
|
||||
|
||||
/** Updates bluetooth device details fragment layout. */
|
||||
override fun updateLayout(fragmentType: FragmentTypeModel) = runBlocking {
|
||||
val items = viewModel.getItems(fragmentType) ?: return@runBlocking
|
||||
val layout = viewModel.getLayout(fragmentType) ?: return@runBlocking
|
||||
|
||||
val prefKeyToSettingId =
|
||||
items
|
||||
.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
|
||||
|
@@ -22,7 +22,6 @@ import android.content.Context
|
||||
import android.graphics.PorterDuff
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.android.settings.R
|
||||
@@ -63,8 +62,10 @@ class DeviceDetailsMoreSettingsFragment : DashboardFragment() {
|
||||
item.icon?.setColorFilter(
|
||||
resources.getColor(
|
||||
com.android.settingslib.widget.theme.R.color
|
||||
.settingslib_materialColorOnSurface),
|
||||
PorterDuff.Mode.SRC_ATOP)
|
||||
.settingslib_materialColorOnSurface
|
||||
),
|
||||
PorterDuff.Mode.SRC_ATOP,
|
||||
)
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
|
||||
}
|
||||
}
|
||||
@@ -116,14 +117,27 @@ class DeviceDetailsMoreSettingsFragment : DashboardFragment() {
|
||||
}
|
||||
formatter =
|
||||
featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(
|
||||
requireContext(), this, bluetoothManager.adapter, cachedDevice)
|
||||
requireContext(),
|
||||
this,
|
||||
bluetoothManager.adapter,
|
||||
cachedDevice,
|
||||
)
|
||||
helpItem =
|
||||
formatter
|
||||
.getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
|
||||
.stateIn(lifecycleScope, SharingStarted.WhileSubscribed(), initialValue = null)
|
||||
return listOf(
|
||||
BluetoothDetailsProfilesController(
|
||||
context, this, localBluetoothManager, cachedDevice, settingsLifecycle))
|
||||
context,
|
||||
this,
|
||||
localBluetoothManager,
|
||||
cachedDevice,
|
||||
settingsLifecycle,
|
||||
formatter.getInvisibleBluetoothProfiles(
|
||||
FragmentTypeModel.DeviceDetailsMoreSettingsFragment
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getLogTag(): String = TAG
|
||||
|
@@ -120,11 +120,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
|
||||
.thenAnswer(invocation -> ImmutableList.of(mConnectableProfiles));
|
||||
|
||||
setupDevice(mDeviceConfig);
|
||||
mController = new BluetoothDetailsProfilesController(mContext, mFragment, mLocalManager,
|
||||
mCachedDevice, mLifecycle);
|
||||
mProfiles.setKey(mController.getPreferenceKey());
|
||||
mController.mProfilesContainer = mProfiles;
|
||||
mScreen.addPreference(mProfiles);
|
||||
initController(List.of());
|
||||
BluetoothProperties.le_audio_allow_list(Lists.newArrayList(LE_DEVICE_MODEL));
|
||||
}
|
||||
|
||||
@@ -554,6 +550,36 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
|
||||
|
||||
@Test
|
||||
public void prefKeyInBlockingList_hideToggle() {
|
||||
initController(List.of("A2DP"));
|
||||
setupDevice(makeDefaultDeviceConfig());
|
||||
|
||||
addA2dpProfileToDevice(true, true, true);
|
||||
when(mFeatureProvider.getInvisibleProfilePreferenceKeys(any(), any()))
|
||||
.thenReturn(ImmutableSet.of());
|
||||
|
||||
showScreen(mController);
|
||||
|
||||
List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
|
||||
assertThat(switches.get(0).isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prefKeyNotInBlockingList_showToggle() {
|
||||
initController(List.of());
|
||||
setupDevice(makeDefaultDeviceConfig());
|
||||
|
||||
addA2dpProfileToDevice(true, true, true);
|
||||
when(mFeatureProvider.getInvisibleProfilePreferenceKeys(any(), any()))
|
||||
.thenReturn(ImmutableSet.of());
|
||||
|
||||
showScreen(mController);
|
||||
|
||||
List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
|
||||
assertThat(switches.get(0).isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prefKeyInFeatureProviderBlockingList_hideToggle() {
|
||||
setupDevice(makeDefaultDeviceConfig());
|
||||
|
||||
addA2dpProfileToDevice(true, true, true);
|
||||
@@ -567,7 +593,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prefKeyNotInBlockingList_showToggle() {
|
||||
public void prefKeyNotInFeatureProviderBlockingList_showToggle() {
|
||||
setupDevice(makeDefaultDeviceConfig());
|
||||
|
||||
addA2dpProfileToDevice(true, true, true);
|
||||
@@ -627,4 +653,13 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
|
||||
assertThat(switches.getFirst().getTitle()).isEqualTo(
|
||||
mContext.getString(mLeAudioProfile.getNameResource(mDevice)));
|
||||
}
|
||||
|
||||
private void initController(List<String> invisibleProfiles) {
|
||||
mController = new BluetoothDetailsProfilesController(mContext, mFragment, mLocalManager,
|
||||
mCachedDevice, mLifecycle, invisibleProfiles);
|
||||
mProfiles.setKey(mController.getPreferenceKey());
|
||||
mController.mProfilesContainer = mProfiles;
|
||||
mScreen.removeAll();
|
||||
mScreen.addPreference(mProfiles);
|
||||
}
|
||||
}
|
||||
|
@@ -122,10 +122,11 @@ class DeviceDetailsFragmentFormatterTest {
|
||||
.thenReturn(
|
||||
DeviceSettingConfigModel(
|
||||
listOf(
|
||||
DeviceSettingConfigItemModel.BuiltinItem(
|
||||
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
|
||||
DeviceSettingId.DEVICE_SETTING_ID_HEADER,
|
||||
"bluetooth_device_header"),
|
||||
DeviceSettingConfigItemModel.BuiltinItem(
|
||||
"bluetooth_device_header"
|
||||
),
|
||||
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
|
||||
DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS, "action_buttons"),
|
||||
),
|
||||
listOf(),
|
||||
@@ -203,10 +204,10 @@ class DeviceDetailsFragmentFormatterTest {
|
||||
.thenReturn(
|
||||
DeviceSettingConfigModel(
|
||||
listOf(
|
||||
DeviceSettingConfigItemModel.BuiltinItem(
|
||||
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
|
||||
DeviceSettingId.DEVICE_SETTING_ID_HEADER,
|
||||
"bluetooth_device_header"),
|
||||
DeviceSettingConfigItemModel.BuiltinItem(
|
||||
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
|
||||
DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
|
||||
"keyboard_settings"),
|
||||
),
|
||||
@@ -227,12 +228,12 @@ class DeviceDetailsFragmentFormatterTest {
|
||||
.thenReturn(
|
||||
DeviceSettingConfigModel(
|
||||
listOf(
|
||||
DeviceSettingConfigItemModel.BuiltinItem(
|
||||
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
|
||||
DeviceSettingId.DEVICE_SETTING_ID_HEADER,
|
||||
"bluetooth_device_header"),
|
||||
DeviceSettingConfigItemModel.AppProvidedItem(
|
||||
DeviceSettingId.DEVICE_SETTING_ID_ANC),
|
||||
DeviceSettingConfigItemModel.BuiltinItem(
|
||||
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
|
||||
DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
|
||||
"keyboard_settings"),
|
||||
),
|
||||
|
@@ -282,10 +282,10 @@ class BluetoothDeviceDetailsViewModelTest {
|
||||
|
||||
private companion object {
|
||||
val BUILTIN_SETTING_ITEM_1 =
|
||||
DeviceSettingConfigItemModel.BuiltinItem(
|
||||
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
|
||||
DeviceSettingId.DEVICE_SETTING_ID_HEADER, "bluetooth_device_header")
|
||||
val BUILDIN_SETTING_ITEM_2 =
|
||||
DeviceSettingConfigItemModel.BuiltinItem(
|
||||
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
|
||||
DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS, "action_buttons")
|
||||
val SETTING_ITEM_HELP = DeviceSettingConfigItemModel.AppProvidedItem(12345)
|
||||
}
|
||||
|
Reference in New Issue
Block a user