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

Commit 8c507e87 authored by Chaohui Wang's avatar Chaohui Wang
Browse files

Catch exception in telephonyRepository.isDataEnabledFlow

And migrate BillingCycleRepository to use it.

Fix: 339197552
Test: manual - on data usage
Test: unit test
Change-Id: Ieac295f37fdbf75d184d66ea11f170652af3ec5f
parent 5a85f6a7
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -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
@@ -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 {
+7 −9
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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.
+11 −8
Original line number Diff line number Diff line
@@ -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(
@@ -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
@@ -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"
    }
+11 −6
Original line number Diff line number Diff line
@@ -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,
@@ -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(
@@ -100,6 +104,7 @@ class TelephonyRepository(
            wifiPickerTrackerHelper.setCarrierNetworkEnabled(enabled)
        }
    }

    private companion object {
        private const val TAG = "TelephonyRepository"
    }
+2 −3
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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