Loading src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java +26 −10 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -81,7 +84,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; Loading @@ -95,13 +100,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 Loading Loading @@ -563,7 +576,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll protected void refresh() { ThreadUtils.postOnBackgroundThread( () -> { mInvisiblePreferenceKey.set( mAdditionalInvisibleProfiles.set( FeatureFactory.getFeatureFactory() .getBluetoothFeatureProvider() .getInvisibleProfilePreferenceKeys( Loading Loading @@ -604,12 +617,15 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll mProfilesContainer.addPreference(preference); } Set<String> invisibleKeys = mInvisiblePreferenceKey.get(); if (invisibleKeys != null) { 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() && !invisibleKeys.contains(pref.getKey())); } pref.setVisible(pref.isVisible() && !combinedInvisibleProfiles.contains(pref.getKey())); } } Loading src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java +5 −1 Original line number Diff line number Diff line Loading @@ -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<>(); Loading @@ -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, Loading src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt +14 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading Loading @@ -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>() Loading src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt +19 −5 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) } } Loading Loading @@ -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 Loading tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java +41 −6 Original line number Diff line number Diff line Loading @@ -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)); } Loading Loading @@ -554,11 +550,12 @@ 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("A2DP")); .thenReturn(ImmutableSet.of()); showScreen(mController); Loading @@ -568,6 +565,35 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont @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); when(mFeatureProvider.getInvisibleProfilePreferenceKeys(any(), any())) .thenReturn(ImmutableSet.of("A2DP")); showScreen(mController); List<SwitchPreferenceCompat> switches = getProfileSwitches(false); assertThat(switches.get(0).isVisible()).isFalse(); } @Test public void prefKeyNotInFeatureProviderBlockingList_showToggle() { setupDevice(makeDefaultDeviceConfig()); addA2dpProfileToDevice(true, true, true); Loading Loading @@ -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); } } Loading
src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java +26 −10 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -81,7 +84,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; Loading @@ -95,13 +100,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 Loading Loading @@ -563,7 +576,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll protected void refresh() { ThreadUtils.postOnBackgroundThread( () -> { mInvisiblePreferenceKey.set( mAdditionalInvisibleProfiles.set( FeatureFactory.getFeatureFactory() .getBluetoothFeatureProvider() .getInvisibleProfilePreferenceKeys( Loading Loading @@ -604,12 +617,15 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll mProfilesContainer.addPreference(preference); } Set<String> invisibleKeys = mInvisiblePreferenceKey.get(); if (invisibleKeys != null) { 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() && !invisibleKeys.contains(pref.getKey())); } pref.setVisible(pref.isVisible() && !combinedInvisibleProfiles.contains(pref.getKey())); } } Loading
src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java +5 −1 Original line number Diff line number Diff line Loading @@ -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<>(); Loading @@ -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, Loading
src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt +14 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading Loading @@ -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>() Loading
src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt +19 −5 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) } } Loading Loading @@ -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 Loading
tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java +41 −6 Original line number Diff line number Diff line Loading @@ -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)); } Loading Loading @@ -554,11 +550,12 @@ 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("A2DP")); .thenReturn(ImmutableSet.of()); showScreen(mController); Loading @@ -568,6 +565,35 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont @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); when(mFeatureProvider.getInvisibleProfilePreferenceKeys(any(), any())) .thenReturn(ImmutableSet.of("A2DP")); showScreen(mController); List<SwitchPreferenceCompat> switches = getProfileSwitches(false); assertThat(switches.get(0).isVisible()).isFalse(); } @Test public void prefKeyNotInFeatureProviderBlockingList_showToggle() { setupDevice(makeDefaultDeviceConfig()); addA2dpProfileToDevice(true, true, true); Loading Loading @@ -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); } }