Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a90869f authored by Haijie Hong's avatar Haijie Hong Committed by Android (Google) Code Review
Browse files

Merge "Make bluetooth profile toggles configurable" into main

parents 457ab074 cd7627c9
Loading
Loading
Loading
Loading
+26 −10
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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
@@ -563,7 +576,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
    protected void refresh() {
        ThreadUtils.postOnBackgroundThread(
                () -> {
                    mInvisiblePreferenceKey.set(
                    mAdditionalInvisibleProfiles.set(
                            FeatureFactory.getFeatureFactory()
                                    .getBluetoothFeatureProvider()
                                    .getInvisibleProfilePreferenceKeys(
@@ -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()));
        }
    }

+5 −1
Original line number Diff line number Diff line
@@ -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,
+14 −1
Original line number Diff line number Diff line
@@ -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>()
+19 −5
Original line number Diff line number Diff line
@@ -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
+41 −6
Original line number Diff line number Diff line
@@ -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,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);

@@ -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);
@@ -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