Loading res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -1868,6 +1868,8 @@ <string name="bluetooth_device_more_settings_preference_title">More settings</string> <!-- Title for more settings summary. [CHAR LIMIT=50] --> <string name="bluetooth_device_more_settings_preference_summary">Firmware updates, about, and more</string> <!-- Title for bluetooth device tips and support. [CHAR LIMIT=50] --> <string name="bluetooth_device_tip_support">Tips & support</string> <!-- Title of the item to show device MAC address --> <string name="bluetooth_device_mac_address">Device\'s Bluetooth address: <xliff:g id="address">%1$s</xliff:g></string> <!-- Title of the items to show multuple devices MAC address [CHAR LIMIT=NONE]--> src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.kt +7 −1 Original line number Diff line number Diff line Loading @@ -101,6 +101,12 @@ open class BluetoothFeatureProviderImpl : BluetoothFeatureProvider { bluetoothAdapter: BluetoothAdapter, cachedDevice: CachedBluetoothDevice ): DeviceDetailsFragmentFormatter { return DeviceDetailsFragmentFormatterImpl(context, fragment, bluetoothAdapter, cachedDevice) return DeviceDetailsFragmentFormatterImpl( context, fragment, bluetoothAdapter, cachedDevice, Dispatchers.IO ) } } src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt +7 −0 Original line number Diff line number Diff line Loading @@ -66,4 +66,11 @@ sealed interface DeviceSettingPreferenceModel { data class MoreSettingsPreference( @DeviceSettingId override val id: Int, ) : DeviceSettingPreferenceModel /** Models a help button on the top right corner of the fragment. */ data class HelpPreference( @DeviceSettingId override val id: Int, val icon: DeviceSettingIcon, val onClick: (() -> Unit), ) : DeviceSettingPreferenceModel } src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt +27 −1 Original line number Diff line number Diff line Loading @@ -52,10 +52,15 @@ import com.android.settingslib.spa.widget.preference.SwitchPreference import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference import com.android.settingslib.spa.widget.ui.Footer import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.runBlocking /** Handles device details fragment layout according to config. */ Loading @@ -65,6 +70,11 @@ interface DeviceDetailsFragmentFormatter { /** Updates device details fragment layout. */ fun updateLayout(fragmentType: FragmentTypeModel) /** Gets the menu items of the fragment. */ fun getMenuItem( fragmentType: FragmentTypeModel ): Flow<DeviceSettingPreferenceModel.HelpPreference?> } @OptIn(ExperimentalCoroutinesApi::class) Loading @@ -72,7 +82,8 @@ class DeviceDetailsFragmentFormatterImpl( private val context: Context, private val fragment: SettingsPreferenceFragment, bluetoothAdapter: BluetoothAdapter, private val cachedDevice: CachedBluetoothDevice private val cachedDevice: CachedBluetoothDevice, private val backgroundCoroutineContext: CoroutineContext, ) : DeviceDetailsFragmentFormatter { private val repository = featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository( Loading @@ -88,6 +99,7 @@ class DeviceDetailsFragmentFormatterImpl( repository, spatialAudioInteractor, cachedDevice, backgroundCoroutineContext, )) .get(BluetoothDeviceDetailsViewModel::class.java) Loading Loading @@ -135,6 +147,19 @@ class DeviceDetailsFragmentFormatterImpl( fragment.preferenceScreen.addPreference(Preference(context).apply { order = 10000 }) } override fun getMenuItem( fragmentType: FragmentTypeModel ): Flow<DeviceSettingPreferenceModel.HelpPreference?> = flow { val t = viewModel.getHelpItem(fragmentType) t?.let { item -> emitAll( viewModel.getDeviceSetting(cachedDevice, item.settingId).map { it as? DeviceSettingPreferenceModel.HelpPreference }) } ?: emit(null) } @Composable private fun buildPreference(layout: DeviceSettingLayout, row: Int) { val contents by Loading Loading @@ -174,6 +199,7 @@ class DeviceDetailsFragmentFormatterImpl( is DeviceSettingPreferenceModel.MoreSettingsPreference -> { buildMoreSettingsPreference() } is DeviceSettingPreferenceModel.HelpPreference -> {} null -> {} } } Loading src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt +44 −0 Original line number Diff line number Diff line Loading @@ -19,26 +19,65 @@ package com.android.settings.bluetooth.ui.view import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothManager 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 import com.android.settings.bluetooth.BluetoothDetailsProfilesController import com.android.settings.bluetooth.Utils import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel import com.android.settings.bluetooth.ui.model.FragmentTypeModel import com.android.settings.dashboard.DashboardFragment import com.android.settings.overlay.FeatureFactory.Companion.featureFactory import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon import com.android.settingslib.core.AbstractPreferenceController import com.android.settingslib.core.lifecycle.LifecycleObserver import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch class DeviceDetailsMoreSettingsFragment : DashboardFragment() { private lateinit var formatter: DeviceDetailsFragmentFormatter private lateinit var localBluetoothManager: LocalBluetoothManager private lateinit var cachedDevice: CachedBluetoothDevice private lateinit var helpItem: StateFlow<DeviceSettingPreferenceModel.HelpPreference?> // TODO(b/343317785): add metrics category override fun getMetricsCategory(): Int = 0 override fun onPrepareOptionsMenu(menu: Menu) { super.onPrepareOptionsMenu(menu) lifecycleScope.launch { helpItem.filterNotNull().collect { item -> val iconRes = item.icon as? DeviceSettingIcon.ResourceIcon ?: return@collect val item: MenuItem = menu.add(0, MENU_HELP_ITEM_ID, 0, R.string.bluetooth_device_tip_support) item.setIcon(iconRes.resId) item.icon?.setColorFilter( resources.getColor( com.android.settingslib.widget.theme.R.color .settingslib_materialColorOnSurface), PorterDuff.Mode.SRC_ATOP) item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS) } } } override fun onOptionsItemSelected(menuItem: MenuItem): Boolean { if (menuItem.itemId == MENU_HELP_ITEM_ID) { helpItem.value?.let { it.onClick() } return true } return super.onOptionsItemSelected(menuItem) } override fun getPreferenceScreenResId(): Int { return R.xml.bluetooth_device_more_settings_fragment } Loading Loading @@ -78,6 +117,10 @@ class DeviceDetailsMoreSettingsFragment : DashboardFragment() { formatter = featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter( requireContext(), this, bluetoothManager.adapter, cachedDevice) helpItem = formatter .getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment) .stateIn(lifecycleScope, SharingStarted.WhileSubscribed(), initialValue = null) return listOf( BluetoothDetailsProfilesController( context, this, localBluetoothManager, cachedDevice, settingsLifecycle)) Loading @@ -88,5 +131,6 @@ class DeviceDetailsMoreSettingsFragment : DashboardFragment() { companion object { const val TAG: String = "DeviceMoreSettingsFrg" const val KEY_DEVICE_ADDRESS: String = "device_address" const val MENU_HELP_ITEM_ID = Menu.FIRST } } Loading
res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -1868,6 +1868,8 @@ <string name="bluetooth_device_more_settings_preference_title">More settings</string> <!-- Title for more settings summary. [CHAR LIMIT=50] --> <string name="bluetooth_device_more_settings_preference_summary">Firmware updates, about, and more</string> <!-- Title for bluetooth device tips and support. [CHAR LIMIT=50] --> <string name="bluetooth_device_tip_support">Tips & support</string> <!-- Title of the item to show device MAC address --> <string name="bluetooth_device_mac_address">Device\'s Bluetooth address: <xliff:g id="address">%1$s</xliff:g></string> <!-- Title of the items to show multuple devices MAC address [CHAR LIMIT=NONE]-->
src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.kt +7 −1 Original line number Diff line number Diff line Loading @@ -101,6 +101,12 @@ open class BluetoothFeatureProviderImpl : BluetoothFeatureProvider { bluetoothAdapter: BluetoothAdapter, cachedDevice: CachedBluetoothDevice ): DeviceDetailsFragmentFormatter { return DeviceDetailsFragmentFormatterImpl(context, fragment, bluetoothAdapter, cachedDevice) return DeviceDetailsFragmentFormatterImpl( context, fragment, bluetoothAdapter, cachedDevice, Dispatchers.IO ) } }
src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt +7 −0 Original line number Diff line number Diff line Loading @@ -66,4 +66,11 @@ sealed interface DeviceSettingPreferenceModel { data class MoreSettingsPreference( @DeviceSettingId override val id: Int, ) : DeviceSettingPreferenceModel /** Models a help button on the top right corner of the fragment. */ data class HelpPreference( @DeviceSettingId override val id: Int, val icon: DeviceSettingIcon, val onClick: (() -> Unit), ) : DeviceSettingPreferenceModel }
src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt +27 −1 Original line number Diff line number Diff line Loading @@ -52,10 +52,15 @@ import com.android.settingslib.spa.widget.preference.SwitchPreference import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference import com.android.settingslib.spa.widget.ui.Footer import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.runBlocking /** Handles device details fragment layout according to config. */ Loading @@ -65,6 +70,11 @@ interface DeviceDetailsFragmentFormatter { /** Updates device details fragment layout. */ fun updateLayout(fragmentType: FragmentTypeModel) /** Gets the menu items of the fragment. */ fun getMenuItem( fragmentType: FragmentTypeModel ): Flow<DeviceSettingPreferenceModel.HelpPreference?> } @OptIn(ExperimentalCoroutinesApi::class) Loading @@ -72,7 +82,8 @@ class DeviceDetailsFragmentFormatterImpl( private val context: Context, private val fragment: SettingsPreferenceFragment, bluetoothAdapter: BluetoothAdapter, private val cachedDevice: CachedBluetoothDevice private val cachedDevice: CachedBluetoothDevice, private val backgroundCoroutineContext: CoroutineContext, ) : DeviceDetailsFragmentFormatter { private val repository = featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository( Loading @@ -88,6 +99,7 @@ class DeviceDetailsFragmentFormatterImpl( repository, spatialAudioInteractor, cachedDevice, backgroundCoroutineContext, )) .get(BluetoothDeviceDetailsViewModel::class.java) Loading Loading @@ -135,6 +147,19 @@ class DeviceDetailsFragmentFormatterImpl( fragment.preferenceScreen.addPreference(Preference(context).apply { order = 10000 }) } override fun getMenuItem( fragmentType: FragmentTypeModel ): Flow<DeviceSettingPreferenceModel.HelpPreference?> = flow { val t = viewModel.getHelpItem(fragmentType) t?.let { item -> emitAll( viewModel.getDeviceSetting(cachedDevice, item.settingId).map { it as? DeviceSettingPreferenceModel.HelpPreference }) } ?: emit(null) } @Composable private fun buildPreference(layout: DeviceSettingLayout, row: Int) { val contents by Loading Loading @@ -174,6 +199,7 @@ class DeviceDetailsFragmentFormatterImpl( is DeviceSettingPreferenceModel.MoreSettingsPreference -> { buildMoreSettingsPreference() } is DeviceSettingPreferenceModel.HelpPreference -> {} null -> {} } } Loading
src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt +44 −0 Original line number Diff line number Diff line Loading @@ -19,26 +19,65 @@ package com.android.settings.bluetooth.ui.view import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothManager 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 import com.android.settings.bluetooth.BluetoothDetailsProfilesController import com.android.settings.bluetooth.Utils import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel import com.android.settings.bluetooth.ui.model.FragmentTypeModel import com.android.settings.dashboard.DashboardFragment import com.android.settings.overlay.FeatureFactory.Companion.featureFactory import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon import com.android.settingslib.core.AbstractPreferenceController import com.android.settingslib.core.lifecycle.LifecycleObserver import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch class DeviceDetailsMoreSettingsFragment : DashboardFragment() { private lateinit var formatter: DeviceDetailsFragmentFormatter private lateinit var localBluetoothManager: LocalBluetoothManager private lateinit var cachedDevice: CachedBluetoothDevice private lateinit var helpItem: StateFlow<DeviceSettingPreferenceModel.HelpPreference?> // TODO(b/343317785): add metrics category override fun getMetricsCategory(): Int = 0 override fun onPrepareOptionsMenu(menu: Menu) { super.onPrepareOptionsMenu(menu) lifecycleScope.launch { helpItem.filterNotNull().collect { item -> val iconRes = item.icon as? DeviceSettingIcon.ResourceIcon ?: return@collect val item: MenuItem = menu.add(0, MENU_HELP_ITEM_ID, 0, R.string.bluetooth_device_tip_support) item.setIcon(iconRes.resId) item.icon?.setColorFilter( resources.getColor( com.android.settingslib.widget.theme.R.color .settingslib_materialColorOnSurface), PorterDuff.Mode.SRC_ATOP) item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS) } } } override fun onOptionsItemSelected(menuItem: MenuItem): Boolean { if (menuItem.itemId == MENU_HELP_ITEM_ID) { helpItem.value?.let { it.onClick() } return true } return super.onOptionsItemSelected(menuItem) } override fun getPreferenceScreenResId(): Int { return R.xml.bluetooth_device_more_settings_fragment } Loading Loading @@ -78,6 +117,10 @@ class DeviceDetailsMoreSettingsFragment : DashboardFragment() { formatter = featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter( requireContext(), this, bluetoothManager.adapter, cachedDevice) helpItem = formatter .getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment) .stateIn(lifecycleScope, SharingStarted.WhileSubscribed(), initialValue = null) return listOf( BluetoothDetailsProfilesController( context, this, localBluetoothManager, cachedDevice, settingsLifecycle)) Loading @@ -88,5 +131,6 @@ class DeviceDetailsMoreSettingsFragment : DashboardFragment() { companion object { const val TAG: String = "DeviceMoreSettingsFrg" const val KEY_DEVICE_ADDRESS: String = "device_address" const val MENU_HELP_ITEM_ID = Menu.FIRST } }