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

Commit 7eaa2b16 authored by SongFerng Wang's avatar SongFerng Wang Committed by Android (Google) Code Review
Browse files

Merge "Add the mobile data into new SIMs page" into main

parents 08529156 e471604d
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -46,15 +46,18 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
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
@@ -74,6 +77,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>
@@ -86,6 +91,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()
@@ -152,7 +158,10 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {

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

@@ -184,6 +193,12 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
        showDsdsProgressDialog = rememberSaveable { mutableStateOf(false) }
        showRestartDialog = rememberSaveable { 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