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

Commit bfd8a517 authored by Chaohui Wang's avatar Chaohui Wang
Browse files

Refactor AutomaticDataSwitchingPreference

Split into AutomaticDataSwitchingPreference.kt, and use
isMobileDataPolicyEnabledFlow.

Bug: 329061940
Test: manual - Set Automatic data switching
Test: unit test
Change-Id: I878ed70328307c0a5dba6dfb461ff5a85efbcf88
parent 3a12c7b1
Loading
Loading
Loading
Loading
+6 −13
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.telephony.UiccCardInfo
import android.telephony.UiccSlotInfo
import android.util.Log
import com.android.settings.network.SimOnboardingActivity.Companion.CallbackType
import com.android.settings.network.telephony.TelephonyRepository
import com.android.settings.sim.SimActivationNotifier
import com.android.settings.spa.network.setAutomaticData
import com.android.settings.spa.network.setDefaultData
@@ -31,6 +32,7 @@ import com.android.settings.spa.network.setDefaultSms
import com.android.settings.spa.network.setDefaultVoice
import com.android.settingslib.utils.ThreadUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withContext

class SimOnboardingService {
@@ -46,7 +48,7 @@ class SimOnboardingService {
    var targetPrimarySimCalls: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
    var targetPrimarySimTexts: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
    var targetPrimarySimMobileData: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
    var targetPrimarySimAutoDataSwitch: Boolean = false
    val targetPrimarySimAutoDataSwitch = MutableStateFlow(false)
    var targetNonDds: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
        get() {
            if(targetPrimarySimMobileData == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
@@ -349,19 +351,10 @@ class SimOnboardingService {
                    null,
                    targetPrimarySimMobileData
                )

                var nonDds = targetNonDds
                Log.d(
                    TAG,
                    "setAutomaticData: targetNonDds: $nonDds," +
                            " targetPrimarySimAutoDataSwitch: $targetPrimarySimAutoDataSwitch"
                TelephonyRepository(context).setAutomaticData(
                    targetNonDds,
                    targetPrimarySimAutoDataSwitch.value
                )
                if (nonDds != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                    val telephonyManagerForNonDds: TelephonyManager? =
                        context.getSystemService(TelephonyManager::class.java)
                            ?.createForSubscriptionId(nonDds)
                    setAutomaticData(telephonyManagerForNonDds, targetPrimarySimAutoDataSwitch)
                }
            }
            // no next action, send finish
            callback(CallbackType.CALLBACK_FINISH)
+44 −2
Original line number Diff line number Diff line
@@ -17,8 +17,10 @@
package com.android.settings.network.telephony

import android.content.Context
import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.ProducerScope
@@ -26,15 +28,51 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map

class TelephonyRepository(
    private val context: Context,
    private val subscriptionsChangedFlow: Flow<Unit> = context.subscriptionsChangedFlow(),
) {
    fun isMobileDataPolicyEnabledFlow(
        subId: Int,
        @TelephonyManager.MobileDataPolicy policy: Int,
    ): Flow<Boolean> {
        if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)

        val telephonyManager = context.telephonyManager(subId)

        return subscriptionsChangedFlow.map {
            telephonyManager.isMobileDataPolicyEnabled(policy)
                .also { Log.d(TAG, "[$subId] isMobileDataPolicyEnabled($policy): $it") }
        }.conflate().flowOn(Dispatchers.Default)
    }

    fun setMobileDataPolicyEnabled(
        subId: Int,
        @TelephonyManager.MobileDataPolicy policy: Int,
        enabled: Boolean,
    ) {
        if (!SubscriptionManager.isValidSubscriptionId(subId)) return

        val telephonyManager = context.telephonyManager(subId)
        Log.d(TAG, "[$subId] setMobileDataPolicyEnabled($policy): $enabled")
        telephonyManager.setMobileDataPolicyEnabled(policy, enabled)
    }

    private companion object {
        private const val TAG = "TelephonyRepository"
    }
}

/** Creates an instance of a cold Flow for Telephony callback of given [subId]. */
fun <T> Context.telephonyCallbackFlow(
    subId: Int,
    block: ProducerScope<T>.() -> TelephonyCallback,
): Flow<T> = callbackFlow {
    val telephonyManager = getSystemService(TelephonyManager::class.java)!!
        .createForSubscriptionId(subId)
    val telephonyManager = telephonyManager(subId)

    val callback = block()

@@ -42,3 +80,7 @@ fun <T> Context.telephonyCallbackFlow(

    awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
}.conflate().flowOn(Dispatchers.Default)

fun Context.telephonyManager(subId: Int): TelephonyManager =
    getSystemService(TelephonyManager::class.java)!!
        .createForSubscriptionId(subId)
+58 −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.settings.spa.network

import android.telephony.TelephonyManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.res.stringResource
import com.android.settings.R
import com.android.settings.network.telephony.TelephonyRepository
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

@Composable
fun AutomaticDataSwitchingPreference(
    isAutoDataEnabled: () -> Boolean?,
    setAutoDataEnabled: (newEnabled: Boolean) -> Unit,
) {
    val autoDataSummary = stringResource(id = R.string.primary_sim_automatic_data_msg)
    val coroutineScope = rememberCoroutineScope()
    SwitchPreference(
        object : SwitchPreferenceModel {
            override val title = stringResource(id = R.string.primary_sim_automatic_data_title)
            override val summary = { autoDataSummary }
            override val checked = { isAutoDataEnabled() }
            override val onCheckedChange: (Boolean) -> Unit = { newEnabled ->
                coroutineScope.launch(Dispatchers.Default) {
                    setAutoDataEnabled(newEnabled)
                }
            }
        }
    )
}

fun TelephonyRepository.setAutomaticData(subId: Int, newEnabled: Boolean) {
    setMobileDataPolicyEnabled(
        subId = subId,
        policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
        enabled = newEnabled,
    )
    //TODO: setup backup calling
}
+14 −66
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
@@ -44,6 +43,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.settings.R
import com.android.settings.network.SubscriptionInfoListViewModel
import com.android.settings.network.telephony.MobileNetworkUtils
import com.android.settings.network.telephony.TelephonyRepository
import com.android.settings.spa.network.PrimarySimRepository.PrimarySimInfo
import com.android.settings.wifi.WifiPickerTrackerHelper
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
@@ -53,8 +53,6 @@ import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.Category
import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverFlow
@@ -193,7 +191,6 @@ fun PrimarySimImpl(
    callsSelectedId: MutableIntState,
    textsSelectedId: MutableIntState,
    mobileDataSelectedId: MutableIntState,
    nonDds: MutableIntState,
    subscriptionManager: SubscriptionManager? =
        LocalContext.current.getSystemService(SubscriptionManager::class.java),
    coroutineScope: CoroutineScope = rememberCoroutineScope(),
@@ -223,23 +220,9 @@ fun PrimarySimImpl(
            )
        }
    },
    actionSetAutoDataSwitch: (Boolean) -> Unit = { newState ->
        coroutineScope.launch {
            val telephonyManagerForNonDds: TelephonyManager? =
                context.getSystemService(TelephonyManager::class.java)
                    ?.createForSubscriptionId(nonDds.intValue)
            Log.d(NetworkCellularGroupProvider.name, "NonDds:${nonDds.intValue} setAutomaticData")
            setAutomaticData(telephonyManagerForNonDds, newState)
        }
    },
    isAutoDataEnabled: () -> Boolean?,
    setAutoDataEnabled: (newEnabled: Boolean) -> Unit,
) {
    val telephonyManagerForNonDds: TelephonyManager? =
            context.getSystemService(TelephonyManager::class.java)
                    ?.createForSubscriptionId(nonDds.intValue)
    val automaticDataChecked = rememberSaveable() {
        mutableStateOf(false)
    }

    CreatePrimarySimListPreference(
        stringResource(id = R.string.primary_sim_calls_title),
        primarySimInfo.callsAndSmsList,
@@ -262,31 +245,7 @@ fun PrimarySimImpl(
        actionSetMobileData
    )

    val autoDataTitle = stringResource(id = R.string.primary_sim_automatic_data_title)
    val autoDataSummary = stringResource(id = R.string.primary_sim_automatic_data_msg)
    SwitchPreference(
        object : SwitchPreferenceModel {
            override val title = autoDataTitle
            override val summary = { autoDataSummary }
            override val checked = {
                if (nonDds.intValue != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                    coroutineScope.launch {
                        automaticDataChecked.value = getAutomaticData(telephonyManagerForNonDds)
                        Log.d(
                            NetworkCellularGroupProvider.name,
                            "NonDds:${nonDds.intValue}" +
                                "getAutomaticData:${automaticDataChecked.value}"
                        )
                    }
                }
                automaticDataChecked.value
            }
            override val onCheckedChange: ((Boolean) -> Unit)? = {
                automaticDataChecked.value = it
                actionSetAutoDataSwitch(it)
            }
        }
    )
    AutomaticDataSwitchingPreference(isAutoDataEnabled, setAutoDataEnabled)
}

@Composable
@@ -308,12 +267,21 @@ fun PrimarySimSectionImpl(
    }.collectAsStateWithLifecycle(initialValue = null).value ?: return

    Category(title = stringResource(id = R.string.primary_sim_title)) {
        val isAutoDataEnabled by remember(nonDds.intValue) {
            TelephonyRepository(context).isMobileDataPolicyEnabledFlow(
                subId = nonDds.intValue,
                policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
            )
        }.collectAsStateWithLifecycle(initialValue = null)
        PrimarySimImpl(
            primarySimInfo,
            callsSelectedId,
            textsSelectedId,
            mobileDataSelectedId,
            nonDds
            isAutoDataEnabled = { isAutoDataEnabled },
            setAutoDataEnabled = { newEnabled ->
                TelephonyRepository(context).setAutomaticData(nonDds.intValue, newEnabled)
            },
        )
    }
}
@@ -381,23 +349,3 @@ suspend fun setDefaultData(
            wifiPickerTrackerHelper.setCarrierNetworkEnabled(true)
        }
    }

suspend fun getAutomaticData(telephonyManagerForNonDds: TelephonyManager?): Boolean =
    withContext(Dispatchers.Default) {
        telephonyManagerForNonDds != null
            && telephonyManagerForNonDds.isMobileDataPolicyEnabled(
            TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
    }

suspend fun setAutomaticData(telephonyManager: TelephonyManager?, newState: Boolean): Unit =
    withContext(Dispatchers.Default) {
        Log.d(
            NetworkCellularGroupProvider.name,
            "setAutomaticData: MOBILE_DATA_POLICY_AUTO_DATA_SWITCH as $newState"
        )
        telephonyManager?.setMobileDataPolicyEnabled(
            TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
            newState
        )
        //TODO: setup backup calling
    }
 No newline at end of file
+8 −6
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.SignalCellularAlt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
@@ -75,9 +76,6 @@ fun SimOnboardingPrimarySimImpl(
        val mobileDataSelectedId = rememberSaveable {
            mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
        }
        val nonDdsRemember = rememberSaveable {
            mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
        }

        Column(Modifier.padding(SettingsDimension.itemPadding)) {
            SettingsBody(stringResource(id = R.string.sim_onboarding_primary_sim_msg))
@@ -94,12 +92,14 @@ fun SimOnboardingPrimarySimImpl(
        callsSelectedId.intValue = onboardingService.targetPrimarySimCalls
        textsSelectedId.intValue = onboardingService.targetPrimarySimTexts
        mobileDataSelectedId.intValue = onboardingService.targetPrimarySimMobileData
        val isAutoDataEnabled by
            onboardingService.targetPrimarySimAutoDataSwitch
                .collectAsStateWithLifecycle(initialValue = null)
        PrimarySimImpl(
            primarySimInfo = primarySimInfo,
            callsSelectedId = callsSelectedId,
            textsSelectedId = textsSelectedId,
            mobileDataSelectedId = mobileDataSelectedId,
            nonDds = nonDdsRemember,
            actionSetCalls = {
                callsSelectedId.intValue = it
                onboardingService.targetPrimarySimCalls = it},
@@ -109,8 +109,10 @@ fun SimOnboardingPrimarySimImpl(
            actionSetMobileData = {
                mobileDataSelectedId.intValue = it
                onboardingService.targetPrimarySimMobileData = it},
            actionSetAutoDataSwitch = {
                onboardingService.targetPrimarySimAutoDataSwitch = it},
            isAutoDataEnabled = { isAutoDataEnabled },
            setAutoDataEnabled = { newEnabled ->
                onboardingService.targetPrimarySimAutoDataSwitch.value = newEnabled
            },
        )
    }
}
Loading