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

Commit e471604d authored by songferngwang's avatar songferngwang
Browse files

Add the mobile data into new SIMs page

Bug: 329584989
Test: verify UI.
atest TelephonyRepositoryTest

Change-Id: Ia00ac287ffd0d15ba0c9350b731c3afc1a04b7a0
parent fd27947e
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -45,15 +45,18 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.lifecycle.LifecycleRegistry
import com.android.settings.R
import com.android.settings.SidecarFragment
import com.android.settings.network.telephony.SubscriptionActionDialogActivity
import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity
import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
import com.android.settings.spa.network.SimOnboardingPageProvider.getRoute
import com.android.settings.wifi.WifiPickerTrackerHelper
import com.android.settingslib.spa.SpaBaseDialogActivity
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
@@ -73,6 +76,8 @@ import kotlinx.coroutines.launch

class SimOnboardingActivity : SpaBaseDialogActivity() {
    lateinit var scope: CoroutineScope
    lateinit var wifiPickerTrackerHelper: WifiPickerTrackerHelper
    lateinit var context: Context
    lateinit var showStartingDialog: MutableState<Boolean>
    lateinit var showError: MutableState<ErrorType>
    lateinit var showProgressDialog: MutableState<Boolean>
@@ -85,6 +90,7 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (!this.userManager.isAdminUser) {
            Log.e(TAG, "It is not the admin user. Unable to toggle subscription.")
            finish()
@@ -151,7 +157,10 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {

            CallbackType.CALLBACK_SETUP_PRIMARY_SIM -> {
                scope.launch {
                    onboardingService.startSetupPrimarySim(this@SimOnboardingActivity)
                    onboardingService.startSetupPrimarySim(
                        this@SimOnboardingActivity,
                        wifiPickerTrackerHelper
                    )
                }
            }

@@ -183,6 +192,12 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
        showDsdsProgressDialog = remember { mutableStateOf(false) }
        showRestartDialog = remember { mutableStateOf(false) }
        scope = rememberCoroutineScope()
        context = LocalContext.current
        val lifecycleOwner = LocalLifecycleOwner.current
        wifiPickerTrackerHelper = WifiPickerTrackerHelper(
            LifecycleRegistry(lifecycleOwner), context,
            null /* WifiPickerTrackerCallback */
        )

        registerSidecarReceiverFlow()

+6 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.settings.spa.network.setAutomaticData
import com.android.settings.spa.network.setDefaultData
import com.android.settings.spa.network.setDefaultSms
import com.android.settings.spa.network.setDefaultVoice
import com.android.settings.wifi.WifiPickerTrackerHelper
import com.android.settingslib.utils.ThreadUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
@@ -336,14 +337,17 @@ class SimOnboardingService {
        }
    }

    suspend fun startSetupPrimarySim(context: Context) {
    suspend fun startSetupPrimarySim(
        context: Context,
        wifiPickerTrackerHelper: WifiPickerTrackerHelper
    ) {
        withContext(Dispatchers.Default) {
                setDefaultVoice(subscriptionManager, targetPrimarySimCalls)
                setDefaultSms(subscriptionManager, targetPrimarySimTexts)
                setDefaultData(
                    context,
                    subscriptionManager,
                    null,
                    wifiPickerTrackerHelper,
                    targetPrimarySimMobileData
                )
                TelephonyRepository(context).setAutomaticData(
+38 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import android.util.Log
import com.android.settings.network.mobileDataEnabledFlow
import com.android.settings.wifi.WifiPickerTrackerHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.ProducerScope
@@ -62,6 +64,42 @@ class TelephonyRepository(
        telephonyManager.setMobileDataPolicyEnabled(policy, enabled)
    }

    fun isDataEnabled(
        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") }
            }
    }

    fun setMobileData(
        subId: Int,
        enabled: Boolean,
        wifiPickerTrackerHelper: WifiPickerTrackerHelper? = null
    ) {
        if (!SubscriptionManager.isValidSubscriptionId(subId)) return

        Log.d(TAG, "setMobileData: $enabled")
        MobileNetworkUtils.setMobileDataEnabled(
            context,
            subId,
            enabled /* enabled */,
            true /* disableOtherSubscriptions */
        )

        if (wifiPickerTrackerHelper != null
            && !wifiPickerTrackerHelper.isCarrierNetworkProvisionEnabled(subId)
        ) {
            wifiPickerTrackerHelper.setCarrierNetworkEnabled(enabled)
        }
    }
    private companion object {
        private const val TAG = "TelephonyRepository"
    }
+50 −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 MobileDataSwitchingPreference(
    isMobileDataEnabled: () -> Boolean?,
    setMobileDataEnabled: (newEnabled: Boolean) -> Unit,
) {
    val mobileDataSummary = stringResource(id = R.string.primary_sim_automatic_data_msg)
    val coroutineScope = rememberCoroutineScope()
    SwitchPreference(
        object : SwitchPreferenceModel {
            override val title = stringResource(id = R.string.mobile_data_settings_title)
            override val summary = { mobileDataSummary }
            override val checked = { isMobileDataEnabled() }
            override val onCheckedChange: (Boolean) -> Unit = { newEnabled ->
                coroutineScope.launch(Dispatchers.Default) {
                    setMobileDataEnabled(newEnabled)
                }
            }
            override val changeable:() -> Boolean = {true}
        }
    )
}
+94 −35
Original line number Diff line number Diff line
@@ -38,11 +38,12 @@ 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.collectAsStateWithLifecycle
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
@@ -167,7 +168,7 @@ fun PageImpl(
    defaultVoiceSubId: MutableIntState,
    defaultSmsSubId: MutableIntState,
    defaultDataSubId: MutableIntState,
    nonDds: MutableIntState
    nonDds: MutableIntState,
) {
    val selectableSubscriptionInfoList by selectableSubscriptionInfoListFlow
        .collectAsStateWithLifecycle(initialValue = emptyList())
@@ -175,22 +176,76 @@ fun PageImpl(
    val stringSims = stringResource(R.string.provider_network_settings_title)
    RegularScaffold(title = stringSims) {
        SimsSection(selectableSubscriptionInfoList)
        MobileDataSectionImpl(defaultDataSubId,
            nonDds,
        )

        PrimarySimSectionImpl(
            selectableSubscriptionInfoListFlow,
            defaultVoiceSubId,
            defaultSmsSubId,
            defaultDataSubId,
            nonDds
        )
    }
}

@Composable
fun MobileDataSectionImpl(
    mobileDataSelectedId: MutableIntState,
    nonDds: MutableIntState,
) {
    val context = LocalContext.current
    val localLifecycleOwner = LocalLifecycleOwner.current
    val wifiPickerTrackerHelper = getWifiPickerTrackerHelper(context, localLifecycleOwner)

    val subscriptionManager: SubscriptionManager? =
            context.getSystemService(SubscriptionManager::class.java)

    Category(title = stringResource(id = R.string.mobile_data_settings_title)) {
        val isAutoDataEnabled by remember(nonDds.intValue) {
            TelephonyRepository(context).isMobileDataPolicyEnabledFlow(
                subId = nonDds.intValue,
                policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
            )
        }.collectAsStateWithLifecycle(initialValue = null)

        val mobileDataStateChanged by remember(mobileDataSelectedId.intValue) {
            TelephonyRepository(context).isDataEnabled(mobileDataSelectedId.intValue)
        }.collectAsStateWithLifecycle(initialValue = false)
        val coroutineScope = rememberCoroutineScope()

        MobileDataSwitchingPreference(
            isMobileDataEnabled = { mobileDataStateChanged },
            setMobileDataEnabled = { newEnabled ->
                coroutineScope.launch {
                    setMobileData(
                        context,
                        subscriptionManager,
                        wifiPickerTrackerHelper,
                        mobileDataSelectedId.intValue,
                        newEnabled
                    )
                }
           },
        )
        if (nonDds.intValue != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
            AutomaticDataSwitchingPreference(
                isAutoDataEnabled = { isAutoDataEnabled },
                setAutoDataEnabled = { newEnabled ->
                    TelephonyRepository(context).setAutomaticData(nonDds.intValue, newEnabled)
                },
            )
        }
    }
}

@Composable
fun PrimarySimImpl(
    primarySimInfo: PrimarySimInfo,
    callsSelectedId: MutableIntState,
    textsSelectedId: MutableIntState,
    mobileDataSelectedId: MutableIntState,
    wifiPickerTrackerHelper: WifiPickerTrackerHelper? = null,
    subscriptionManager: SubscriptionManager? =
        LocalContext.current.getSystemService(SubscriptionManager::class.java),
    coroutineScope: CoroutineScope = rememberCoroutineScope(),
@@ -208,20 +263,15 @@ fun PrimarySimImpl(
        }
    },
    actionSetMobileData: (Int) -> Unit = {
        mobileDataSelectedId.intValue = it
        coroutineScope.launch {
            // TODO: to fix the WifiPickerTracker crash when create
            //       the wifiPickerTrackerHelper
            setDefaultData(
                context,
                subscriptionManager,
                null/*wifiPickerTrackerHelper*/,
                wifiPickerTrackerHelper,
                it
            )
        }
    },
    isAutoDataEnabled: () -> Boolean?,
    setAutoDataEnabled: (newEnabled: Boolean) -> Unit,
) {
    CreatePrimarySimListPreference(
        stringResource(id = R.string.primary_sim_calls_title),
@@ -244,8 +294,6 @@ fun PrimarySimImpl(
        Icons.Outlined.DataUsage,
        actionSetMobileData
    )

    AutomaticDataSwitchingPreference(isAutoDataEnabled, setAutoDataEnabled)
}

@Composable
@@ -254,9 +302,11 @@ fun PrimarySimSectionImpl(
    callsSelectedId: MutableIntState,
    textsSelectedId: MutableIntState,
    mobileDataSelectedId: MutableIntState,
    nonDds: MutableIntState,
) {
    val context = LocalContext.current
    val localLifecycleOwner = LocalLifecycleOwner.current
    val wifiPickerTrackerHelper = getWifiPickerTrackerHelper(context, localLifecycleOwner)

    val primarySimInfo = remember(subscriptionInfoListFlow) {
        subscriptionInfoListFlow
            .map { subscriptionInfoList ->
@@ -267,25 +317,25 @@ 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,
            isAutoDataEnabled = { isAutoDataEnabled },
            setAutoDataEnabled = { newEnabled ->
                TelephonyRepository(context).setAutomaticData(nonDds.intValue, newEnabled)
            },
            wifiPickerTrackerHelper
        )
    }
}

private fun getWifiPickerTrackerHelper(
    context: Context,
    lifecycleOwner: LifecycleOwner
): WifiPickerTrackerHelper {
    return WifiPickerTrackerHelper(
        LifecycleRegistry(lifecycleOwner), context,
        null /* WifiPickerTrackerCallback */
    )
}
private fun Context.defaultVoiceSubscriptionFlow(): Flow<Int> =
        merge(
                flowOf(null), // kick an initial value
@@ -335,18 +385,27 @@ suspend fun setDefaultData(
    wifiPickerTrackerHelper: WifiPickerTrackerHelper?,
    subId: Int
): Unit =
    withContext(Dispatchers.Default) {
        subscriptionManager?.setDefaultDataSubId(subId)
        Log.d(NetworkCellularGroupProvider.name, "setMobileDataEnabled: true")
        MobileNetworkUtils.setMobileDataEnabled(
    setMobileData(
        context,
        subscriptionManager,
        wifiPickerTrackerHelper,
        subId,
            true /* enabled */,
            true /* disableOtherSubscriptions */
        true
    )
        if (wifiPickerTrackerHelper != null
            && !wifiPickerTrackerHelper.isCarrierNetworkProvisionEnabled(subId)
        ) {
            wifiPickerTrackerHelper.setCarrierNetworkEnabled(true)

suspend fun setMobileData(
    context: Context,
    subscriptionManager: SubscriptionManager?,
    wifiPickerTrackerHelper: WifiPickerTrackerHelper?,
    subId: Int,
    enabled: Boolean,
): Unit =
    withContext(Dispatchers.Default) {
        Log.d(NetworkCellularGroupProvider.name, "setMobileData: $enabled")
        if (enabled) {
            Log.d(NetworkCellularGroupProvider.name, "setDefaultData: [$subId]")
            subscriptionManager?.setDefaultDataSubId(subId)
        }
        TelephonyRepository(context)
            .setMobileData(subId, enabled, wifiPickerTrackerHelper)
    }
 No newline at end of file
Loading