Loading res/xml/mobile_network_settings.xml +1 −5 Original line number Original line Diff line number Diff line Loading @@ -85,13 +85,9 @@ android:summary="@string/auto_data_switch_summary" android:summary="@string/auto_data_switch_summary" settings:controller="com.android.settings.network.telephony.AutoDataSwitchPreferenceController"/> settings:controller="com.android.settings.network.telephony.AutoDataSwitchPreferenceController"/> <com.android.settingslib.RestrictedSwitchPreference <com.android.settings.spa.preference.ComposePreference android:key="button_roaming_key" android:key="button_roaming_key" android:title="@string/roaming" android:title="@string/roaming" android:persistent="false" android:summaryOn="@string/roaming_enable" android:summaryOff="@string/roaming_disable" settings:userRestriction="no_data_roaming" settings:controller="com.android.settings.network.telephony.RoamingPreferenceController"/> settings:controller="com.android.settings.network.telephony.RoamingPreferenceController"/> <Preference <Preference Loading src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepository.kt +17 −20 Original line number Original line Diff line number Diff line Loading @@ -23,10 +23,10 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.settings.network.telephony.CarrierConfigRepository import com.android.settings.network.telephony.SimSlotRepository import com.android.settings.network.telephony.SimSlotRepository import com.android.settings.network.telephony.ims.ImsMmTelRepository import com.android.settings.network.telephony.ims.ImsMmTelRepository import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl import com.android.settings.network.telephony.safeGetConfig import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow Loading @@ -39,7 +39,9 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import kotlinx.coroutines.launch @OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class) class SimStatusDialogRepository @JvmOverloads constructor( class SimStatusDialogRepository @JvmOverloads constructor( private val context: Context, private val context: Context, private val simSlotRepository: SimSlotRepository = SimSlotRepository(context), private val simSlotRepository: SimSlotRepository = SimSlotRepository(context), private val signalStrengthRepository: SignalStrengthRepository = private val signalStrengthRepository: SignalStrengthRepository = Loading @@ -48,7 +50,7 @@ class SimStatusDialogRepository @JvmOverloads constructor( ImsMmTelRepositoryImpl(context, subId) ImsMmTelRepositoryImpl(context, subId) }, }, ) { ) { private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!! private val carrierConfigRepository = CarrierConfigRepository(context) data class SimStatusDialogInfo( data class SimStatusDialogInfo( val signalStrength: String? = null, val signalStrength: String? = null, Loading @@ -73,7 +75,8 @@ class SimStatusDialogRepository @JvmOverloads constructor( } } private fun simStatusDialogInfoBySlotFlow(simSlotIndex: Int): Flow<SimStatusDialogInfo> = private fun simStatusDialogInfoBySlotFlow(simSlotIndex: Int): Flow<SimStatusDialogInfo> = simSlotRepository.subIdInSimSlotFlow(simSlotIndex) simSlotRepository .subIdInSimSlotFlow(simSlotIndex) .flatMapLatest { subId -> .flatMapLatest { subId -> if (SubscriptionManager.isValidSubscriptionId(subId)) { if (SubscriptionManager.isValidSubscriptionId(subId)) { simStatusDialogInfoFlow(subId) simStatusDialogInfoFlow(subId) Loading @@ -99,22 +102,16 @@ class SimStatusDialogRepository @JvmOverloads constructor( } } private fun showUpFlow(subId: Int) = flow { private fun showUpFlow(subId: Int) = flow { val config = carrierConfigManager.safeGetConfig( val visibility = keys = listOf( carrierConfigRepository.transformConfig(subId) { CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, SimStatusDialogVisibility( CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, signalStrengthShowUp = ), getBoolean( subId = subId, CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL), ) imsRegisteredShowUp = val visibility = SimStatusDialogVisibility( getBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL), signalStrengthShowUp = config.getBoolean( CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, true, // by default we show the signal strength in sim status ), imsRegisteredShowUp = config.getBoolean( CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL ), ) ) } emit(visibility) emit(visibility) } } } } src/com/android/settings/network/telephony/CarrierConfigManagerExt.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ import androidx.core.os.persistableBundleOf /** /** * Gets the configuration values of the specified config keys applied. * Gets the configuration values of the specified config keys applied. */ */ @Deprecated("Use CarrierConfigRepository instead") fun CarrierConfigManager.safeGetConfig( fun CarrierConfigManager.safeGetConfig( keys: List<String>, keys: List<String>, subId: Int = SubscriptionManager.getDefaultSubscriptionId(), subId: Int = SubscriptionManager.getDefaultSubscriptionId(), Loading src/com/android/settings/network/telephony/CarrierConfigRepository.kt 0 → 100644 +217 −0 Original line number Original line 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.settings.network.telephony import android.content.Context import android.os.PersistableBundle import android.telephony.CarrierConfigManager import android.telephony.SubscriptionManager import android.util.Log import androidx.annotation.VisibleForTesting import java.util.concurrent.ConcurrentHashMap import kotlinx.atomicfu.atomic import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asExecutor class CarrierConfigRepository(private val context: Context) { private val carrierConfigManager: CarrierConfigManager? = context.getSystemService(CarrierConfigManager::class.java) private enum class KeyType { BOOLEAN, INT, STRING } interface CarrierConfigAccessor { fun getBoolean(key: String): Boolean fun getInt(key: String): Int fun getString(key: String): String? } private class Accessor(private val cache: ConfigCache) : CarrierConfigAccessor { private val keysToRetrieve = mutableMapOf<String, KeyType>() override fun getBoolean(key: String): Boolean { check(key.endsWith("_bool")) { "Boolean key should ends with _bool" } val value = cache[key] return if (value == null) { keysToRetrieve += key to KeyType.BOOLEAN DefaultConfig.getBoolean(key) } else { check(value is BooleanConfigValue) { "Boolean value type wrong" } value.value } } override fun getInt(key: String): Int { check(key.endsWith("_int")) { "Int key should ends with _int" } val value = cache[key] return if (value == null) { keysToRetrieve += key to KeyType.INT DefaultConfig.getInt(key) } else { check(value is IntConfigValue) { "Int value type wrong" } value.value } } override fun getString(key: String): String? { check(key.endsWith("_string")) { "String key should ends with _string" } val value = cache[key] return if (value == null) { keysToRetrieve += key to KeyType.STRING DefaultConfig.getString(key) } else { check(value is StringConfigValue) { "String value type wrong" } value.value } } fun getKeysToRetrieve(): Map<String, KeyType> = keysToRetrieve } /** * Gets the configuration values for the given [subId]. * * Configuration values could be accessed in [block]. Note: [block] could be called multiple * times, so it should be pure function without side effort. */ fun <T> transformConfig(subId: Int, block: CarrierConfigAccessor.() -> T): T { val perSubCache = getPerSubCache(subId) val accessor = Accessor(perSubCache) val result = accessor.block() val keysToRetrieve = accessor.getKeysToRetrieve() // If all keys found in the first pass, no need to collect again if (keysToRetrieve.isEmpty()) return result perSubCache.update(subId, keysToRetrieve) return accessor.block() } /** Gets the configuration boolean for the given [subId] and [key]. */ fun getBoolean(subId: Int, key: String): Boolean = transformConfig(subId) { getBoolean(key) } /** Gets the configuration int for the given [subId] and [key]. */ fun getInt(subId: Int, key: String): Int = transformConfig(subId) { getInt(key) } /** Gets the configuration string for the given [subId] and [key]. */ fun getString(subId: Int, key: String): String? = transformConfig(subId) { getString(key) } private fun ConfigCache.update(subId: Int, keysToRetrieve: Map<String, KeyType>) { val config = safeGetConfig(subId, keysToRetrieve.keys) ?: return for ((key, type) in keysToRetrieve) { when (type) { KeyType.BOOLEAN -> this[key] = BooleanConfigValue(config.getBoolean(key)) KeyType.INT -> this[key] = IntConfigValue(config.getInt(key)) KeyType.STRING -> this[key] = StringConfigValue(config.getString(key)) } } } /** Gets the configuration values of the specified config keys applied. */ private fun safeGetConfig(subId: Int, keys: Collection<String>): PersistableBundle? { if (carrierConfigManager == null || !SubscriptionManager.isValidSubscriptionId(subId)) { return null } tryRegisterListener(context) return try { carrierConfigManager.getConfigForSubId(subId, *keys.toTypedArray()) } catch (e: Exception) { Log.e(TAG, "safeGetConfig: exception", e) // The CarrierConfigLoader (the service implemented the CarrierConfigManager) hasn't // been initialized yet. This may occurs during very early phase of phone booting up // or when Phone process has been restarted. // Settings should not assume Carrier config loader (and any other system services // as well) are always available. If not available, use default value instead. null } } companion object { private const val TAG = "CarrierConfigRepository" private val DefaultConfig = CarrierConfigManager.getDefaultConfig() /** Cache of config values for each subscription. */ private val Cache = ConcurrentHashMap<Int, ConfigCache>() private fun getPerSubCache(subId: Int) = Cache.computeIfAbsent(subId) { ConcurrentHashMap() } /** To make sure the registerCarrierConfigChangeListener is only called once. */ private val ListenerRegistered = atomic(false) private fun tryRegisterListener(context: Context) { if (ListenerRegistered.compareAndSet(expect = false, update = true)) { val carrierConfigManager = context.applicationContext.getSystemService(CarrierConfigManager::class.java) if (carrierConfigManager != null) { carrierConfigManager.registerCarrierConfigChangeListener() } else { ListenerRegistered.getAndSet(false) } } } private fun CarrierConfigManager.registerCarrierConfigChangeListener() { val executor = Dispatchers.Default.asExecutor() registerCarrierConfigChangeListener(executor) { _, subId, _, _ -> Log.d(TAG, "[$subId] onCarrierConfigChanged") Cache.remove(subId) } } @VisibleForTesting fun resetForTest() { Cache.clear() ListenerRegistered.getAndSet(false) } @VisibleForTesting fun setBooleanForTest(subId: Int, key: String, value: Boolean) { check(key.endsWith("_bool")) { "Boolean key should ends with _bool" } getPerSubCache(subId)[key] = BooleanConfigValue(value) } @VisibleForTesting fun setIntForTest(subId: Int, key: String, value: Int) { check(key.endsWith("_int")) { "Int key should ends with _int" } getPerSubCache(subId)[key] = IntConfigValue(value) } @VisibleForTesting fun setStringForTest(subId: Int, key: String, value: String) { check(key.endsWith("_string")) { "String key should ends with _string" } getPerSubCache(subId)[key] = StringConfigValue(value) } } } private sealed interface ConfigValue private data class BooleanConfigValue(val value: Boolean) : ConfigValue private data class IntConfigValue(val value: Int) : ConfigValue private data class StringConfigValue(val value: String?) : ConfigValue private typealias ConfigCache = ConcurrentHashMap<String, ConfigValue> src/com/android/settings/network/telephony/MobileDataRepository.kt +12 −0 Original line number Original line Diff line number Diff line Loading @@ -118,6 +118,18 @@ class MobileDataRepository( } } } } /** Creates an instance of a cold Flow for whether data roaming is enabled of given [subId]. */ fun isDataRoamingEnabledFlow(subId: Int): Flow<Boolean> { if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false) val telephonyManager = context.telephonyManager(subId) return mobileSettingsGlobalChangedFlow(Settings.Global.DATA_ROAMING, subId) .map { telephonyManager.isDataRoamingEnabled } .distinctUntilChanged() .conflate() .onEach { Log.d(TAG, "[$subId] isDataRoamingEnabledFlow: $it") } .flowOn(Dispatchers.Default) } private companion object { private companion object { private const val TAG = "MobileDataRepository" private const val TAG = "MobileDataRepository" } } Loading Loading
res/xml/mobile_network_settings.xml +1 −5 Original line number Original line Diff line number Diff line Loading @@ -85,13 +85,9 @@ android:summary="@string/auto_data_switch_summary" android:summary="@string/auto_data_switch_summary" settings:controller="com.android.settings.network.telephony.AutoDataSwitchPreferenceController"/> settings:controller="com.android.settings.network.telephony.AutoDataSwitchPreferenceController"/> <com.android.settingslib.RestrictedSwitchPreference <com.android.settings.spa.preference.ComposePreference android:key="button_roaming_key" android:key="button_roaming_key" android:title="@string/roaming" android:title="@string/roaming" android:persistent="false" android:summaryOn="@string/roaming_enable" android:summaryOff="@string/roaming_disable" settings:userRestriction="no_data_roaming" settings:controller="com.android.settings.network.telephony.RoamingPreferenceController"/> settings:controller="com.android.settings.network.telephony.RoamingPreferenceController"/> <Preference <Preference Loading
src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepository.kt +17 −20 Original line number Original line Diff line number Diff line Loading @@ -23,10 +23,10 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.settings.network.telephony.CarrierConfigRepository import com.android.settings.network.telephony.SimSlotRepository import com.android.settings.network.telephony.SimSlotRepository import com.android.settings.network.telephony.ims.ImsMmTelRepository import com.android.settings.network.telephony.ims.ImsMmTelRepository import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl import com.android.settings.network.telephony.safeGetConfig import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow Loading @@ -39,7 +39,9 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import kotlinx.coroutines.launch @OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class) class SimStatusDialogRepository @JvmOverloads constructor( class SimStatusDialogRepository @JvmOverloads constructor( private val context: Context, private val context: Context, private val simSlotRepository: SimSlotRepository = SimSlotRepository(context), private val simSlotRepository: SimSlotRepository = SimSlotRepository(context), private val signalStrengthRepository: SignalStrengthRepository = private val signalStrengthRepository: SignalStrengthRepository = Loading @@ -48,7 +50,7 @@ class SimStatusDialogRepository @JvmOverloads constructor( ImsMmTelRepositoryImpl(context, subId) ImsMmTelRepositoryImpl(context, subId) }, }, ) { ) { private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!! private val carrierConfigRepository = CarrierConfigRepository(context) data class SimStatusDialogInfo( data class SimStatusDialogInfo( val signalStrength: String? = null, val signalStrength: String? = null, Loading @@ -73,7 +75,8 @@ class SimStatusDialogRepository @JvmOverloads constructor( } } private fun simStatusDialogInfoBySlotFlow(simSlotIndex: Int): Flow<SimStatusDialogInfo> = private fun simStatusDialogInfoBySlotFlow(simSlotIndex: Int): Flow<SimStatusDialogInfo> = simSlotRepository.subIdInSimSlotFlow(simSlotIndex) simSlotRepository .subIdInSimSlotFlow(simSlotIndex) .flatMapLatest { subId -> .flatMapLatest { subId -> if (SubscriptionManager.isValidSubscriptionId(subId)) { if (SubscriptionManager.isValidSubscriptionId(subId)) { simStatusDialogInfoFlow(subId) simStatusDialogInfoFlow(subId) Loading @@ -99,22 +102,16 @@ class SimStatusDialogRepository @JvmOverloads constructor( } } private fun showUpFlow(subId: Int) = flow { private fun showUpFlow(subId: Int) = flow { val config = carrierConfigManager.safeGetConfig( val visibility = keys = listOf( carrierConfigRepository.transformConfig(subId) { CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, SimStatusDialogVisibility( CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, signalStrengthShowUp = ), getBoolean( subId = subId, CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL), ) imsRegisteredShowUp = val visibility = SimStatusDialogVisibility( getBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL), signalStrengthShowUp = config.getBoolean( CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, true, // by default we show the signal strength in sim status ), imsRegisteredShowUp = config.getBoolean( CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL ), ) ) } emit(visibility) emit(visibility) } } } }
src/com/android/settings/network/telephony/CarrierConfigManagerExt.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ import androidx.core.os.persistableBundleOf /** /** * Gets the configuration values of the specified config keys applied. * Gets the configuration values of the specified config keys applied. */ */ @Deprecated("Use CarrierConfigRepository instead") fun CarrierConfigManager.safeGetConfig( fun CarrierConfigManager.safeGetConfig( keys: List<String>, keys: List<String>, subId: Int = SubscriptionManager.getDefaultSubscriptionId(), subId: Int = SubscriptionManager.getDefaultSubscriptionId(), Loading
src/com/android/settings/network/telephony/CarrierConfigRepository.kt 0 → 100644 +217 −0 Original line number Original line 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.settings.network.telephony import android.content.Context import android.os.PersistableBundle import android.telephony.CarrierConfigManager import android.telephony.SubscriptionManager import android.util.Log import androidx.annotation.VisibleForTesting import java.util.concurrent.ConcurrentHashMap import kotlinx.atomicfu.atomic import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asExecutor class CarrierConfigRepository(private val context: Context) { private val carrierConfigManager: CarrierConfigManager? = context.getSystemService(CarrierConfigManager::class.java) private enum class KeyType { BOOLEAN, INT, STRING } interface CarrierConfigAccessor { fun getBoolean(key: String): Boolean fun getInt(key: String): Int fun getString(key: String): String? } private class Accessor(private val cache: ConfigCache) : CarrierConfigAccessor { private val keysToRetrieve = mutableMapOf<String, KeyType>() override fun getBoolean(key: String): Boolean { check(key.endsWith("_bool")) { "Boolean key should ends with _bool" } val value = cache[key] return if (value == null) { keysToRetrieve += key to KeyType.BOOLEAN DefaultConfig.getBoolean(key) } else { check(value is BooleanConfigValue) { "Boolean value type wrong" } value.value } } override fun getInt(key: String): Int { check(key.endsWith("_int")) { "Int key should ends with _int" } val value = cache[key] return if (value == null) { keysToRetrieve += key to KeyType.INT DefaultConfig.getInt(key) } else { check(value is IntConfigValue) { "Int value type wrong" } value.value } } override fun getString(key: String): String? { check(key.endsWith("_string")) { "String key should ends with _string" } val value = cache[key] return if (value == null) { keysToRetrieve += key to KeyType.STRING DefaultConfig.getString(key) } else { check(value is StringConfigValue) { "String value type wrong" } value.value } } fun getKeysToRetrieve(): Map<String, KeyType> = keysToRetrieve } /** * Gets the configuration values for the given [subId]. * * Configuration values could be accessed in [block]. Note: [block] could be called multiple * times, so it should be pure function without side effort. */ fun <T> transformConfig(subId: Int, block: CarrierConfigAccessor.() -> T): T { val perSubCache = getPerSubCache(subId) val accessor = Accessor(perSubCache) val result = accessor.block() val keysToRetrieve = accessor.getKeysToRetrieve() // If all keys found in the first pass, no need to collect again if (keysToRetrieve.isEmpty()) return result perSubCache.update(subId, keysToRetrieve) return accessor.block() } /** Gets the configuration boolean for the given [subId] and [key]. */ fun getBoolean(subId: Int, key: String): Boolean = transformConfig(subId) { getBoolean(key) } /** Gets the configuration int for the given [subId] and [key]. */ fun getInt(subId: Int, key: String): Int = transformConfig(subId) { getInt(key) } /** Gets the configuration string for the given [subId] and [key]. */ fun getString(subId: Int, key: String): String? = transformConfig(subId) { getString(key) } private fun ConfigCache.update(subId: Int, keysToRetrieve: Map<String, KeyType>) { val config = safeGetConfig(subId, keysToRetrieve.keys) ?: return for ((key, type) in keysToRetrieve) { when (type) { KeyType.BOOLEAN -> this[key] = BooleanConfigValue(config.getBoolean(key)) KeyType.INT -> this[key] = IntConfigValue(config.getInt(key)) KeyType.STRING -> this[key] = StringConfigValue(config.getString(key)) } } } /** Gets the configuration values of the specified config keys applied. */ private fun safeGetConfig(subId: Int, keys: Collection<String>): PersistableBundle? { if (carrierConfigManager == null || !SubscriptionManager.isValidSubscriptionId(subId)) { return null } tryRegisterListener(context) return try { carrierConfigManager.getConfigForSubId(subId, *keys.toTypedArray()) } catch (e: Exception) { Log.e(TAG, "safeGetConfig: exception", e) // The CarrierConfigLoader (the service implemented the CarrierConfigManager) hasn't // been initialized yet. This may occurs during very early phase of phone booting up // or when Phone process has been restarted. // Settings should not assume Carrier config loader (and any other system services // as well) are always available. If not available, use default value instead. null } } companion object { private const val TAG = "CarrierConfigRepository" private val DefaultConfig = CarrierConfigManager.getDefaultConfig() /** Cache of config values for each subscription. */ private val Cache = ConcurrentHashMap<Int, ConfigCache>() private fun getPerSubCache(subId: Int) = Cache.computeIfAbsent(subId) { ConcurrentHashMap() } /** To make sure the registerCarrierConfigChangeListener is only called once. */ private val ListenerRegistered = atomic(false) private fun tryRegisterListener(context: Context) { if (ListenerRegistered.compareAndSet(expect = false, update = true)) { val carrierConfigManager = context.applicationContext.getSystemService(CarrierConfigManager::class.java) if (carrierConfigManager != null) { carrierConfigManager.registerCarrierConfigChangeListener() } else { ListenerRegistered.getAndSet(false) } } } private fun CarrierConfigManager.registerCarrierConfigChangeListener() { val executor = Dispatchers.Default.asExecutor() registerCarrierConfigChangeListener(executor) { _, subId, _, _ -> Log.d(TAG, "[$subId] onCarrierConfigChanged") Cache.remove(subId) } } @VisibleForTesting fun resetForTest() { Cache.clear() ListenerRegistered.getAndSet(false) } @VisibleForTesting fun setBooleanForTest(subId: Int, key: String, value: Boolean) { check(key.endsWith("_bool")) { "Boolean key should ends with _bool" } getPerSubCache(subId)[key] = BooleanConfigValue(value) } @VisibleForTesting fun setIntForTest(subId: Int, key: String, value: Int) { check(key.endsWith("_int")) { "Int key should ends with _int" } getPerSubCache(subId)[key] = IntConfigValue(value) } @VisibleForTesting fun setStringForTest(subId: Int, key: String, value: String) { check(key.endsWith("_string")) { "String key should ends with _string" } getPerSubCache(subId)[key] = StringConfigValue(value) } } } private sealed interface ConfigValue private data class BooleanConfigValue(val value: Boolean) : ConfigValue private data class IntConfigValue(val value: Int) : ConfigValue private data class StringConfigValue(val value: String?) : ConfigValue private typealias ConfigCache = ConcurrentHashMap<String, ConfigValue>
src/com/android/settings/network/telephony/MobileDataRepository.kt +12 −0 Original line number Original line Diff line number Diff line Loading @@ -118,6 +118,18 @@ class MobileDataRepository( } } } } /** Creates an instance of a cold Flow for whether data roaming is enabled of given [subId]. */ fun isDataRoamingEnabledFlow(subId: Int): Flow<Boolean> { if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false) val telephonyManager = context.telephonyManager(subId) return mobileSettingsGlobalChangedFlow(Settings.Global.DATA_ROAMING, subId) .map { telephonyManager.isDataRoamingEnabled } .distinctUntilChanged() .conflate() .onEach { Log.d(TAG, "[$subId] isDataRoamingEnabledFlow: $it") } .flowOn(Dispatchers.Default) } private companion object { private companion object { private const val TAG = "MobileDataRepository" private const val TAG = "MobileDataRepository" } } Loading