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

Commit ced629eb authored by Haijie Hong's avatar Haijie Hong
Browse files

Make bluetooth profile toggles configurable

BUG: 343317785
Test: atest DeviceSettingRepositoryTest
Flag: com.android.settings.flags.enable_bluetooth_device_details_polish
Change-Id: If623bf23642cc6030bf05a9f76e599ed8d59229f
parent 5783c511
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.settingslib.bluetooth.devicesettings

/** The contract between the device settings provider services and Settings. */
object DeviceSettingContract {
    const val INVISIBLE_PROFILES = "INVISIBLE_PROFILES"
}
+15 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.text.TextUtils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.ActionSwitchPreference
import com.android.settingslib.bluetooth.devicesettings.DeviceSetting
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingContract
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingItem
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingsConfig
@@ -30,6 +31,9 @@ import com.android.settingslib.bluetooth.devicesettings.DeviceSettingHelpPrefere
import com.android.settingslib.bluetooth.devicesettings.MultiTogglePreference
import com.android.settingslib.bluetooth.devicesettings.ToggleInfo
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel.AppProvidedItem
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel.BuiltinItem.BluetoothProfilesItem
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
@@ -103,9 +107,18 @@ class DeviceSettingRepositoryImpl(

    private fun DeviceSettingItem.toModel(): DeviceSettingConfigItemModel {
        return if (!TextUtils.isEmpty(preferenceKey)) {
            DeviceSettingConfigItemModel.BuiltinItem(settingId, preferenceKey!!)
            if (settingId == DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES) {
                BluetoothProfilesItem(
                    settingId,
                    preferenceKey!!,
                    extras.getStringArrayList(DeviceSettingContract.INVISIBLE_PROFILES)
                        ?: emptyList()
                )
            } else {
                CommonBuiltinItem(settingId, preferenceKey!!)
            }
        } else {
            DeviceSettingConfigItemModel.AppProvidedItem(settingId)
            AppProvidedItem(settingId)
        }
    }

+8 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.os.IInterface
import android.text.TextUtils
import android.util.Log
import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
@@ -84,6 +85,10 @@ class DeviceSettingServiceConnection(
                }
                setAction(intentAction)
            }

        fun isValid(): Boolean {
            return !TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(intentAction)
        }
    }

    private var isServiceEnabled =
@@ -96,7 +101,8 @@ class DeviceSettingServiceConnection(
                    } else if (allStatus.all { it is ServiceConnectionStatus.Connected }) {
                        allStatus
                            .filterIsInstance<
                                ServiceConnectionStatus.Connected<IDeviceSettingsProviderService>
                                ServiceConnectionStatus.Connected<
                                        IDeviceSettingsProviderService>
                            >()
                            .all { it.service.serviceStatus?.enabled == true }
                    } else {
@@ -215,6 +221,7 @@ class DeviceSettingServiceConnection(
                    )
                }
            }
            ?.filter { it.isValid() }
            ?.distinct()
            ?.associateBy(
                { it },
+17 −4
Original line number Diff line number Diff line
@@ -36,10 +36,23 @@ sealed interface DeviceSettingConfigItemModel {
    @DeviceSettingId val settingId: Int

    /** A built-in item in Settings. */
    data class BuiltinItem(
    sealed interface BuiltinItem : DeviceSettingConfigItemModel {
        @DeviceSettingId override val settingId: Int
        val preferenceKey: String

        /** A general built-in item in Settings. */
        data class CommonBuiltinItem(
            @DeviceSettingId override val settingId: Int,
            override val preferenceKey: String,
        ) : BuiltinItem

        /** A bluetooth profiles in Settings. */
        data class BluetoothProfilesItem(
            @DeviceSettingId override val settingId: Int,
        val preferenceKey: String?
    ) : DeviceSettingConfigItemModel
            override val preferenceKey: String,
            val invisibleProfiles: List<String>,
        ) : BuiltinItem
    }

    /** A remote item provided by other apps. */
    data class AppProvidedItem(@DeviceSettingId override val settingId: Int) :
+105 −74
Original line number Diff line number Diff line
@@ -91,7 +91,9 @@ class DeviceSettingRepositoryTest {
        `when`(cachedDevice.address).thenReturn(BLUETOOTH_ADDRESS)
        `when`(
                bluetoothDevice.getMetadata(
                    DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
                    DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS
                )
            )
            .thenReturn(BLUETOOTH_DEVICE_METADATA.toByteArray())

        `when`(configService.queryLocalInterface(anyString())).thenReturn(configService)
@@ -114,7 +116,8 @@ class DeviceSettingRepositoryTest {
                    connection.onServiceConnected(
                        ComponentName(
                            SETTING_PROVIDER_SERVICE_PACKAGE_NAME_1,
                            SETTING_PROVIDER_SERVICE_CLASS_NAME_1),
                            SETTING_PROVIDER_SERVICE_CLASS_NAME_1,
                        ),
                        settingProviderService1,
                    )
                SETTING_PROVIDER_SERVICE_INTENT_ACTION_2 ->
@@ -146,16 +149,24 @@ class DeviceSettingRepositoryTest {
    fun getDeviceSettingsConfig_withMetadata_success() {
        testScope.runTest {
            `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
            `when`(settingProviderService1.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService2.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))

            val config = underTest.getDeviceSettingsConfig(cachedDevice)

            assertConfig(config!!, DEVICE_SETTING_CONFIG)
            assertThat(config.mainItems[0])
                .isInstanceOf(DeviceSettingConfigItemModel.AppProvidedItem::class.java)
            assertThat(config.mainItems[1])
                .isInstanceOf(
                    DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem::class.java
                )
            assertThat(config.mainItems[2])
                .isInstanceOf(
                    DeviceSettingConfigItemModel.BuiltinItem.BluetoothProfilesItem::class.java
                )
        }
    }

@@ -164,15 +175,15 @@ class DeviceSettingRepositoryTest {
        testScope.runTest {
            `when`(
                    bluetoothDevice.getMetadata(
                    DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
                .thenReturn("".toByteArray())
            `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
            `when`(settingProviderService1.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
                        DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS
                    )
            `when`(settingProviderService2.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
                )
                .thenReturn("".toByteArray())
            `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))

            val config = underTest.getDeviceSettingsConfig(cachedDevice)

@@ -184,12 +195,10 @@ class DeviceSettingRepositoryTest {
    fun getDeviceSettingsConfig_providerServiceNotEnabled_returnNull() {
        testScope.runTest {
            `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
            `when`(settingProviderService1.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(false)
            )
            `when`(settingProviderService2.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(false))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))

            val config = underTest.getDeviceSettingsConfig(cachedDevice)

@@ -219,12 +228,10 @@ class DeviceSettingRepositoryTest {
                    .getArgument<IDeviceSettingsListener>(1)
                    .onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
            }
            `when`(settingProviderService1.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService2.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            var setting: DeviceSettingModel? = null

            underTest
@@ -247,12 +254,10 @@ class DeviceSettingRepositoryTest {
                    .getArgument<IDeviceSettingsListener>(1)
                    .onDeviceSettingsChanged(listOf(DEVICE_SETTING_2))
            }
            `when`(settingProviderService1.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService2.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            var setting: DeviceSettingModel? = null

            underTest
@@ -275,12 +280,10 @@ class DeviceSettingRepositoryTest {
                    .getArgument<IDeviceSettingsListener>(1)
                    .onDeviceSettingsChanged(listOf(DEVICE_SETTING_HELP))
            }
            `when`(settingProviderService1.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService2.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            var setting: DeviceSettingModel? = null

            underTest
@@ -324,12 +327,10 @@ class DeviceSettingRepositoryTest {
                    .getArgument<IDeviceSettingsListener>(1)
                    .onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
            }
            `when`(settingProviderService1.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService2.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            var setting: DeviceSettingModel? = null

            underTest
@@ -347,8 +348,10 @@ class DeviceSettingRepositoryTest {
                    DeviceSettingState.Builder()
                        .setSettingId(DeviceSettingId.DEVICE_SETTING_ID_HEADER)
                        .setPreferenceState(
                            ActionSwitchPreferenceState.Builder().setChecked(false).build())
                        .build())
                            ActionSwitchPreferenceState.Builder().setChecked(false).build()
                        )
                        .build(),
                )
        }
    }

@@ -362,12 +365,10 @@ class DeviceSettingRepositoryTest {
                    .getArgument<IDeviceSettingsListener>(1)
                    .onDeviceSettingsChanged(listOf(DEVICE_SETTING_2))
            }
            `when`(settingProviderService1.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService2.serviceStatus).thenReturn(
                DeviceSettingsProviderServiceStatus(true)
            )
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            var setting: DeviceSettingModel? = null

            underTest
@@ -385,8 +386,10 @@ class DeviceSettingRepositoryTest {
                    DeviceSettingState.Builder()
                        .setSettingId(DeviceSettingId.DEVICE_SETTING_ID_ANC)
                        .setPreferenceState(
                            MultiTogglePreferenceState.Builder().setState(2).build())
                        .build())
                            MultiTogglePreferenceState.Builder().setState(2).build()
                        )
                        .build(),
                )
        }
    }

@@ -437,7 +440,7 @@ class DeviceSettingRepositoryTest {

    private fun assertConfig(
        actual: DeviceSettingConfigModel,
        serviceResponse: DeviceSettingsConfig
        serviceResponse: DeviceSettingsConfig,
    ) {
        assertThat(actual.mainItems.size).isEqualTo(serviceResponse.mainContentItems.size)
        for (i in 0..<actual.mainItems.size) {
@@ -451,7 +454,7 @@ class DeviceSettingRepositoryTest {

    private fun assertConfigItem(
        actual: DeviceSettingConfigItemModel,
        serviceResponse: DeviceSettingItem
        serviceResponse: DeviceSettingItem,
    ) {
        assertThat(actual.settingId).isEqualTo(serviceResponse.settingId)
    }
@@ -485,24 +488,43 @@ class DeviceSettingRepositoryTest {
                "</DEVICE_SETTINGS_CONFIG_ACTION>"
        val DEVICE_INFO = DeviceInfo.Builder().setBluetoothAddress(BLUETOOTH_ADDRESS).build()
        const val DEVICE_SETTING_ID_HELP = 12345
        val DEVICE_SETTING_ITEM_1 =
        val DEVICE_SETTING_APP_PROVIDED_ITEM_1 =
            DeviceSettingItem(
                DeviceSettingId.DEVICE_SETTING_ID_HEADER,
                SETTING_PROVIDER_SERVICE_PACKAGE_NAME_1,
                SETTING_PROVIDER_SERVICE_CLASS_NAME_1,
                SETTING_PROVIDER_SERVICE_INTENT_ACTION_1)
        val DEVICE_SETTING_ITEM_2 =
                SETTING_PROVIDER_SERVICE_INTENT_ACTION_1,
            )
        val DEVICE_SETTING_APP_PROVIDED_ITEM_2 =
            DeviceSettingItem(
                DeviceSettingId.DEVICE_SETTING_ID_ANC,
                SETTING_PROVIDER_SERVICE_PACKAGE_NAME_2,
                SETTING_PROVIDER_SERVICE_CLASS_NAME_2,
                SETTING_PROVIDER_SERVICE_INTENT_ACTION_2)
                SETTING_PROVIDER_SERVICE_INTENT_ACTION_2,
            )
        val DEVICE_SETTING_BUILT_IN_ITEM =
            DeviceSettingItem(
                DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_AUDIO_DEVICE_TYPE_GROUP,
                "",
                "",
                "",
                "device_type",
            )
        val DEVICE_SETTING_BUILT_IN_BT_PROFILES_ITEM =
            DeviceSettingItem(
                DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES,
                "",
                "",
                "",
                "bluetooth_profiles",
            )
        val DEVICE_SETTING_HELP_ITEM =
            DeviceSettingItem(
                DEVICE_SETTING_ID_HELP,
                SETTING_PROVIDER_SERVICE_PACKAGE_NAME_2,
                SETTING_PROVIDER_SERVICE_CLASS_NAME_2,
                SETTING_PROVIDER_SERVICE_INTENT_ACTION_2)
                SETTING_PROVIDER_SERVICE_INTENT_ACTION_2,
            )
        val DEVICE_SETTING_1 =
            DeviceSetting.Builder()
                .setSettingId(DeviceSettingId.DEVICE_SETTING_ID_HEADER)
@@ -511,7 +533,8 @@ class DeviceSettingRepositoryTest {
                        .setTitle("title1")
                        .setHasSwitch(true)
                        .setAllowedChangingState(true)
                        .build())
                        .build()
                )
                .build()
        val DEVICE_SETTING_2 =
            DeviceSetting.Builder()
@@ -524,22 +547,30 @@ class DeviceSettingRepositoryTest {
                            ToggleInfo.Builder()
                                .setLabel("label1")
                                .setIcon(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
                                .build())
                                .build()
                        )
                        .addToggleInfo(
                            ToggleInfo.Builder()
                                .setLabel("label2")
                                .setIcon(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
                                .build())
                        .build())
                                .build()
        val DEVICE_SETTING_HELP = DeviceSetting.Builder()
                        )
                        .build()
                )
                .build()
        val DEVICE_SETTING_HELP =
            DeviceSetting.Builder()
                .setSettingId(DEVICE_SETTING_ID_HELP)
                .setPreference(DeviceSettingHelpPreference.Builder().setIntent(Intent()).build())
                .build()
        val DEVICE_SETTING_CONFIG =
            DeviceSettingsConfig(
                listOf(DEVICE_SETTING_ITEM_1),
                listOf(DEVICE_SETTING_ITEM_2),
                listOf(
                    DEVICE_SETTING_APP_PROVIDED_ITEM_1,
                    DEVICE_SETTING_BUILT_IN_ITEM,
                    DEVICE_SETTING_BUILT_IN_BT_PROFILES_ITEM,
                ),
                listOf(DEVICE_SETTING_APP_PROVIDED_ITEM_2),
                DEVICE_SETTING_HELP_ITEM,
            )
    }