Loading src/com/android/settings/datausage/BillingCyclePreference.kt +2 −4 Original line number Diff line number Diff line Loading @@ -26,11 +26,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.settings.R import com.android.settings.core.SubSettingLauncher import com.android.settings.datausage.lib.BillingCycleRepository import com.android.settings.network.mobileDataEnabledFlow import com.android.settings.spa.preference.ComposePreference import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel import kotlinx.coroutines.flow.map /** * Preference which displays billing cycle of subscription Loading @@ -46,8 +44,8 @@ class BillingCyclePreference @JvmOverloads constructor( override fun setTemplate(template: NetworkTemplate, subId: Int) { setContent { val isModifiable by remember { context.mobileDataEnabledFlow(subId).map { repository.isModifiable(subId) } val isModifiable by remember(subId) { repository.isModifiableFlow(subId) }.collectAsStateWithLifecycle(initialValue = false) Preference(object : PreferenceModel { Loading src/com/android/settings/datausage/DataUsageList.kt +7 −9 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ import com.android.settings.datausage.lib.BillingCycleRepository import com.android.settings.datausage.lib.NetworkUsageData import com.android.settings.network.MobileNetworkRepository import com.android.settings.network.SubscriptionUtil import com.android.settings.network.mobileDataEnabledFlow import com.android.settings.network.telephony.requireSubscriptionManager import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spaprivileged.framework.common.userManager Loading Loading @@ -113,8 +113,8 @@ open class DataUsageList : DashboardFragment() { override fun onViewCreated(v: View, savedInstanceState: Bundle?) { super.onViewCreated(v, savedInstanceState) requireContext().mobileDataEnabledFlow(subId) .collectLatestWithLifecycle(viewLifecycleOwner) { updatePolicy() } billingCycleRepository.isModifiableFlow(subId) .collectLatestWithLifecycle(viewLifecycleOwner, action = ::updatePolicy) val template = template ?: return viewModel.templateFlow.value = template Loading Loading @@ -163,16 +163,14 @@ open class DataUsageList : DashboardFragment() { } /** Update chart sweeps and cycle list to reflect [NetworkPolicy] for current [template]. */ private fun updatePolicy() { val isBillingCycleModifiable = isBillingCycleModifiable() private fun updatePolicy(isModifiable: Boolean) { val isBillingCycleModifiable = isModifiable && isActiveSubscription() dataUsageListHeaderController?.setConfigButtonVisible(isBillingCycleModifiable) chartDataUsagePreferenceController?.setBillingCycleModifiable(isBillingCycleModifiable) } private fun isBillingCycleModifiable(): Boolean = billingCycleRepository.isModifiable(subId) && requireContext().getSystemService(SubscriptionManager::class.java)!! .getActiveSubscriptionInfo(subId) != null private fun isActiveSubscription(): Boolean = requireContext().requireSubscriptionManager().getActiveSubscriptionInfo(subId) != null /** * Updates the chart and detail data when initial loaded or selected cycle changed. Loading src/com/android/settings/datausage/lib/BillingCycleRepository.kt +11 −8 Original line number Diff line number Diff line Loading @@ -19,10 +19,15 @@ package com.android.settings.datausage.lib import android.content.Context import android.os.INetworkManagementService import android.os.ServiceManager import android.telephony.TelephonyManager import android.util.Log import androidx.annotation.OpenForTesting import com.android.settings.network.telephony.TelephonyRepository import com.android.settingslib.spaprivileged.framework.common.userManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map @OpenForTesting open class BillingCycleRepository @JvmOverloads constructor( Loading @@ -31,12 +36,14 @@ open class BillingCycleRepository @JvmOverloads constructor( INetworkManagementService.Stub.asInterface( ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE) ), private val telephonyRepository: TelephonyRepository = TelephonyRepository(context), ) { private val userManager = context.userManager private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!! fun isModifiable(subId: Int): Boolean = isBandwidthControlEnabled() && userManager.isAdminUser && isDataEnabled(subId) fun isModifiableFlow(subId: Int): Flow<Boolean> = telephonyRepository.isDataEnabledFlow(subId).map { isDataEnabled -> isDataEnabled && isBandwidthControlEnabled() && userManager.isAdminUser }.conflate().flowOn(Dispatchers.Default) open fun isBandwidthControlEnabled(): Boolean = try { networkService.isBandwidthControlEnabled Loading @@ -45,10 +52,6 @@ open class BillingCycleRepository @JvmOverloads constructor( false } private fun isDataEnabled(subId: Int): Boolean = telephonyManager.createForSubscriptionId(subId) .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER) companion object { private const val TAG = "BillingCycleRepository" } Loading src/com/android/settings/network/telephony/TelephonyRepository.kt +11 −6 Original line number Diff line number Diff line Loading @@ -29,10 +29,12 @@ import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach class TelephonyRepository( private val context: Context, Loading Loading @@ -64,19 +66,21 @@ class TelephonyRepository( telephonyManager.setMobileDataPolicyEnabled(policy, enabled) } fun isDataEnabled( subId: Int, ): Flow<Boolean> { fun isDataEnabledFlow(subId: Int): Flow<Boolean> { if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false) Log.d(TAG, "register mobileDataEnabledFlow: [$subId]") return context.mobileDataEnabledFlow(subId) .map { Log.d(TAG, "mobileDataEnabledFlow: receive mobile data [$subId] start") val telephonyManager = context.telephonyManager(subId) telephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER) .also { Log.d(TAG, "mobileDataEnabledFlow: [$subId] isDataEnabled(): $it") } } .catch { Log.w(TAG, "[$subId] isDataEnabledFlow: exception", it) emit(false) } .onEach { Log.d(TAG, "[$subId] isDataEnabledFlow: isDataEnabled() = $it") } .conflate() .flowOn(Dispatchers.Default) } fun setMobileData( Loading @@ -100,6 +104,7 @@ class TelephonyRepository( wifiPickerTrackerHelper.setCarrierNetworkEnabled(enabled) } } private companion object { private const val TAG = "TelephonyRepository" } Loading src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt +2 −3 Original line number Diff line number Diff line Loading @@ -36,11 +36,11 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.android.settings.R Loading @@ -62,7 +62,6 @@ import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBool import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.flowOf Loading Loading @@ -207,7 +206,7 @@ fun MobileDataSectionImpl( }.collectAsStateWithLifecycle(initialValue = null) val mobileDataStateChanged by remember(mobileDataSelectedId.intValue) { TelephonyRepository(context).isDataEnabled(mobileDataSelectedId.intValue) TelephonyRepository(context).isDataEnabledFlow(mobileDataSelectedId.intValue) }.collectAsStateWithLifecycle(initialValue = false) val coroutineScope = rememberCoroutineScope() Loading Loading
src/com/android/settings/datausage/BillingCyclePreference.kt +2 −4 Original line number Diff line number Diff line Loading @@ -26,11 +26,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.settings.R import com.android.settings.core.SubSettingLauncher import com.android.settings.datausage.lib.BillingCycleRepository import com.android.settings.network.mobileDataEnabledFlow import com.android.settings.spa.preference.ComposePreference import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel import kotlinx.coroutines.flow.map /** * Preference which displays billing cycle of subscription Loading @@ -46,8 +44,8 @@ class BillingCyclePreference @JvmOverloads constructor( override fun setTemplate(template: NetworkTemplate, subId: Int) { setContent { val isModifiable by remember { context.mobileDataEnabledFlow(subId).map { repository.isModifiable(subId) } val isModifiable by remember(subId) { repository.isModifiableFlow(subId) }.collectAsStateWithLifecycle(initialValue = false) Preference(object : PreferenceModel { Loading
src/com/android/settings/datausage/DataUsageList.kt +7 −9 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ import com.android.settings.datausage.lib.BillingCycleRepository import com.android.settings.datausage.lib.NetworkUsageData import com.android.settings.network.MobileNetworkRepository import com.android.settings.network.SubscriptionUtil import com.android.settings.network.mobileDataEnabledFlow import com.android.settings.network.telephony.requireSubscriptionManager import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spaprivileged.framework.common.userManager Loading Loading @@ -113,8 +113,8 @@ open class DataUsageList : DashboardFragment() { override fun onViewCreated(v: View, savedInstanceState: Bundle?) { super.onViewCreated(v, savedInstanceState) requireContext().mobileDataEnabledFlow(subId) .collectLatestWithLifecycle(viewLifecycleOwner) { updatePolicy() } billingCycleRepository.isModifiableFlow(subId) .collectLatestWithLifecycle(viewLifecycleOwner, action = ::updatePolicy) val template = template ?: return viewModel.templateFlow.value = template Loading Loading @@ -163,16 +163,14 @@ open class DataUsageList : DashboardFragment() { } /** Update chart sweeps and cycle list to reflect [NetworkPolicy] for current [template]. */ private fun updatePolicy() { val isBillingCycleModifiable = isBillingCycleModifiable() private fun updatePolicy(isModifiable: Boolean) { val isBillingCycleModifiable = isModifiable && isActiveSubscription() dataUsageListHeaderController?.setConfigButtonVisible(isBillingCycleModifiable) chartDataUsagePreferenceController?.setBillingCycleModifiable(isBillingCycleModifiable) } private fun isBillingCycleModifiable(): Boolean = billingCycleRepository.isModifiable(subId) && requireContext().getSystemService(SubscriptionManager::class.java)!! .getActiveSubscriptionInfo(subId) != null private fun isActiveSubscription(): Boolean = requireContext().requireSubscriptionManager().getActiveSubscriptionInfo(subId) != null /** * Updates the chart and detail data when initial loaded or selected cycle changed. Loading
src/com/android/settings/datausage/lib/BillingCycleRepository.kt +11 −8 Original line number Diff line number Diff line Loading @@ -19,10 +19,15 @@ package com.android.settings.datausage.lib import android.content.Context import android.os.INetworkManagementService import android.os.ServiceManager import android.telephony.TelephonyManager import android.util.Log import androidx.annotation.OpenForTesting import com.android.settings.network.telephony.TelephonyRepository import com.android.settingslib.spaprivileged.framework.common.userManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map @OpenForTesting open class BillingCycleRepository @JvmOverloads constructor( Loading @@ -31,12 +36,14 @@ open class BillingCycleRepository @JvmOverloads constructor( INetworkManagementService.Stub.asInterface( ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE) ), private val telephonyRepository: TelephonyRepository = TelephonyRepository(context), ) { private val userManager = context.userManager private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!! fun isModifiable(subId: Int): Boolean = isBandwidthControlEnabled() && userManager.isAdminUser && isDataEnabled(subId) fun isModifiableFlow(subId: Int): Flow<Boolean> = telephonyRepository.isDataEnabledFlow(subId).map { isDataEnabled -> isDataEnabled && isBandwidthControlEnabled() && userManager.isAdminUser }.conflate().flowOn(Dispatchers.Default) open fun isBandwidthControlEnabled(): Boolean = try { networkService.isBandwidthControlEnabled Loading @@ -45,10 +52,6 @@ open class BillingCycleRepository @JvmOverloads constructor( false } private fun isDataEnabled(subId: Int): Boolean = telephonyManager.createForSubscriptionId(subId) .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER) companion object { private const val TAG = "BillingCycleRepository" } Loading
src/com/android/settings/network/telephony/TelephonyRepository.kt +11 −6 Original line number Diff line number Diff line Loading @@ -29,10 +29,12 @@ import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach class TelephonyRepository( private val context: Context, Loading Loading @@ -64,19 +66,21 @@ class TelephonyRepository( telephonyManager.setMobileDataPolicyEnabled(policy, enabled) } fun isDataEnabled( subId: Int, ): Flow<Boolean> { fun isDataEnabledFlow(subId: Int): Flow<Boolean> { if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false) Log.d(TAG, "register mobileDataEnabledFlow: [$subId]") return context.mobileDataEnabledFlow(subId) .map { Log.d(TAG, "mobileDataEnabledFlow: receive mobile data [$subId] start") val telephonyManager = context.telephonyManager(subId) telephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER) .also { Log.d(TAG, "mobileDataEnabledFlow: [$subId] isDataEnabled(): $it") } } .catch { Log.w(TAG, "[$subId] isDataEnabledFlow: exception", it) emit(false) } .onEach { Log.d(TAG, "[$subId] isDataEnabledFlow: isDataEnabled() = $it") } .conflate() .flowOn(Dispatchers.Default) } fun setMobileData( Loading @@ -100,6 +104,7 @@ class TelephonyRepository( wifiPickerTrackerHelper.setCarrierNetworkEnabled(enabled) } } private companion object { private const val TAG = "TelephonyRepository" } Loading
src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt +2 −3 Original line number Diff line number Diff line Loading @@ -36,11 +36,11 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.android.settings.R Loading @@ -62,7 +62,6 @@ import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBool import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.flowOf Loading Loading @@ -207,7 +206,7 @@ fun MobileDataSectionImpl( }.collectAsStateWithLifecycle(initialValue = null) val mobileDataStateChanged by remember(mobileDataSelectedId.intValue) { TelephonyRepository(context).isDataEnabled(mobileDataSelectedId.intValue) TelephonyRepository(context).isDataEnabledFlow(mobileDataSelectedId.intValue) }.collectAsStateWithLifecycle(initialValue = false) val coroutineScope = rememberCoroutineScope() Loading