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

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

Merge "Add the mechanism of enable DSDS" into main

parents 4406de67 2b5002ae
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -11685,6 +11685,13 @@
    <!-- Body text of automatic data switching at dual sim onboarding's primary sim page or SIMs page. [CHAR LIMIT=NONE] -->
    <string name="primary_sim_automatic_data_msg">Use data from either SIM depending on coverage and availability</string>
    <!-- Title of asking the user whether to restart device after enabling DSDS. [CHAR LIMIT=NONE] -->
    <string name="sim_action_restart_dialog_title">Restart to use 2 SIMs</string>
    <!-- Body text of asking the user whether to restart device after enabling DSDS. [CHAR LIMIT=NONE] -->
    <string name="sim_action_restart_dialog_msg">To use 2 SIMs at once, restart your device, then turn on both SIMs</string>
    <!-- Button text to cancel dialog and then enable the sim -->
    <string name="sim_action_restart_dialog_cancel">Use <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g> only</string>
    <!-- Text of phone number item when the sim is data only. [CHAR LIMIT=NONE] -->
    <string name="sim_onboarding_phoneNumber_data_only">Data only</string>
+90 −56
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.content.Intent
import android.os.Bundle
import android.telephony.SubscriptionManager
import android.util.Log
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
@@ -45,7 +44,6 @@ import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -67,7 +65,6 @@ import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spa.widget.dialog.AlertDialogButton
import com.android.settingslib.spa.widget.dialog.getDialogWidth
import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter
import com.android.settingslib.spa.widget.editor.SettingsOutlinedTextField
import com.android.settingslib.spa.widget.ui.SettingsTitle
import com.android.settingslib.spaprivileged.framework.common.userManager
import kotlinx.coroutines.CoroutineScope
@@ -83,6 +80,8 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
    lateinit var showBottomSheet: MutableState<Boolean>
    lateinit var showError: MutableState<ErrorType>
    lateinit var showProgressDialog: MutableState<Boolean>
    lateinit var showDsdsProgressDialog: MutableState<Boolean>
    lateinit var showRestartDialog: MutableState<Boolean>

    private var switchToEuiccSubscriptionSidecar: SwitchToEuiccSubscriptionSidecar? = null
    private var switchToRemovableSlotSidecar: SwitchToRemovableSlotSidecar? = null
@@ -132,6 +131,12 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
                setProgressDialog(false)
            }

            CallbackType.CALLBACK_ENABLE_DSDS-> {
                scope.launch {
                    onboardingService.startEnableDsds(this@SimOnboardingActivity)
                }
            }

            CallbackType.CALLBACK_ONBOARDING_COMPLETE -> {
                showBottomSheet.value = false
                setProgressDialog(true)
@@ -179,12 +184,14 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
        showBottomSheet = remember { mutableStateOf(false) }
        showError = remember { mutableStateOf(ErrorType.ERROR_NONE) }
        showProgressDialog = remember { mutableStateOf(false) }
        showDsdsProgressDialog = remember { mutableStateOf(false) }
        showRestartDialog = remember { mutableStateOf(false) }
        scope = rememberCoroutineScope()

        registerSidecarReceiverFlow()

        ErrorDialogImpl()

        RestartDialogImpl()
        LaunchedEffect(Unit) {
            if (onboardingService.activeSubInfoList.isNotEmpty()) {
                showBottomSheet.value = true
@@ -196,29 +203,76 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
            BottomSheetImpl(
                sheetState = sheetState,
                nextAction = {
                    // TODO: if the phone is SS mode and the isDsdsConditionSatisfied is true, then
                    //  enable the DSDS mode.
                    //  case#1: the device need the reboot after enabling DSDS. Showing the confirm
                    //          dialog to user whether reboot device or not.
                    if (onboardingService.isDsdsConditionSatisfied()) {
                        // TODO: if the phone is SS mode and the isDsdsConditionSatisfied is true,
                        //  then enable the DSDS mode.
                        //  case#1: the device need the reboot after enabling DSDS. Showing the
                        //          confirm dialog to user whether reboot device or not.
                        //  case#2: The device don't need the reboot. Enabling DSDS and then showing
                        //          the SIM onboarding UI.

                        if (onboardingService.doesSwitchMultiSimConfigTriggerReboot) {
                            // case#1
                            Log.d(TAG, "Device does not support reboot free DSDS.")
                            showRestartDialog.value = true
                        } else {
                            // case#2
                    val route = getRoute(onboardingService.targetSubId)
                    startSpaActivity(route)
                            Log.d(TAG, "Enable DSDS mode")
                            showDsdsProgressDialog.value = true
                            enableMultiSimSidecar?.run(SimOnboardingService.NUM_OF_SIMS_FOR_DSDS)
                        }
                    } else {
                        startSimOnboardingProvider()
                    }
                },
                cancelAction = { finish() },
            )
        }

        if (showProgressDialog.value) {
            ProgressDialogImpl()
            ProgressDialogImpl(
                stringResource(
                    R.string.sim_onboarding_progressbar_turning_sim_on,
                    onboardingService.targetSubInfo?.displayName ?: ""
                )
            )
        }
        if (showDsdsProgressDialog.value) {
            ProgressDialogImpl(
                stringResource(R.string.sim_action_enabling_sim_without_carrier_name)
            )
        }
    }
    @Composable
    private fun RestartDialogImpl() {
        val restartDialogPresenter = rememberAlertDialogPresenter(
            confirmButton = AlertDialogButton(
                stringResource(R.string.sim_action_reboot)
            ) {
                callbackListener(CallbackType.CALLBACK_ENABLE_DSDS)
            },
            dismissButton = AlertDialogButton(
                stringResource(
                    R.string.sim_action_restart_dialog_cancel,
                    onboardingService.targetSubInfo?.displayName ?: "")
            ) {
                callbackListener(CallbackType.CALLBACK_ONBOARDING_COMPLETE)
            },
            title = stringResource(R.string.sim_action_restart_dialog_title),
            text = {
                Text(stringResource(R.string.sim_action_restart_dialog_msg))
            },
        )

        if(showRestartDialog.value){
            LaunchedEffect(Unit) {
                restartDialogPresenter.open()
            }
        }
    }

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun ProgressDialogImpl() {
    fun ProgressDialogImpl(title: String) {
        // TODO: Create the SPA's ProgressDialog and using SPA's widget
        BasicAlertDialog(
            onDismissRequest = {},
@@ -239,12 +293,7 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
                    CircularProgressIndicator()
                    Column(modifier = Modifier
                            .padding(start = SettingsDimension.itemPaddingStart)) {
                        SettingsTitle(
                            stringResource(
                                R.string.sim_onboarding_progressbar_turning_sim_on,
                                onboardingService.targetSubInfo?.displayName ?: ""
                            )
                        )
                        SettingsTitle(title)
                    }
                }
            }
@@ -376,8 +425,6 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
                switchToEuiccSubscriptionSidecar!!.reset()
                showError.value = ErrorType.ERROR_EUICC_SLOT
                callbackListener(CallbackType.CALLBACK_ERROR)
                // TODO: showErrorDialog and using privileged_action_disable_fail_title and
                //       privileged_action_disable_fail_text
            }
        }
    }
@@ -396,18 +443,19 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
                switchToRemovableSlotSidecar!!.reset()
                showError.value = ErrorType.ERROR_REMOVABLE_SLOT
                callbackListener(CallbackType.CALLBACK_ERROR)
                // TODO: showErrorDialog and using sim_action_enable_sim_fail_title and
                //       sim_action_enable_sim_fail_text
            }
        }
    }

    fun handleEnableMultiSimSidecarStateChange() {
        showDsdsProgressDialog.value = false
        when (enableMultiSimSidecar!!.state) {
            SidecarFragment.State.SUCCESS -> {
                enableMultiSimSidecar!!.reset()
                Log.i(TAG, "Successfully switched to DSDS without reboot.")
                handleEnableSubscriptionAfterEnablingDsds()
                // refresh data
                initServiceData(this, onboardingService.targetSubId, callbackListener)
                startSimOnboardingProvider()
            }

            SidecarFragment.State.ERROR -> {
@@ -415,34 +463,14 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
                Log.i(TAG, "Failed to switch to DSDS without rebooting.")
                showError.value = ErrorType.ERROR_ENABLE_DSDS
                callbackListener(CallbackType.CALLBACK_ERROR)
                // TODO: showErrorDialog and using dsds_activation_failure_title and
                //       dsds_activation_failure_body_msg2
            }
        }
    }

    fun handleEnableSubscriptionAfterEnablingDsds() {
        var targetSubInfo = onboardingService.targetSubInfo
        if (targetSubInfo?.isEmbedded == true) {
            Log.i(TAG,
                    "DSDS enabled, start to enable profile: " + targetSubInfo.getSubscriptionId()
            )
            // For eSIM operations, we simply switch to the selected eSIM profile.
            switchToEuiccSubscriptionSidecar!!.run(
                targetSubInfo.subscriptionId,
                UiccSlotUtil.INVALID_PORT_ID,
                null
            )
            return
        }
        Log.i(TAG, "DSDS enabled, start to enable pSIM profile.")
        onboardingService.handleTogglePsimAction()
        callbackListener(CallbackType.CALLBACK_FINISH)
    }

    @Composable
    fun BottomSheetBody(nextAction: () -> Unit) {
        Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(bottom = SettingsDimension.itemPaddingVertical)) {
        Column(horizontalAlignment = Alignment.CenterHorizontally,
            modifier = Modifier.padding(bottom = SettingsDimension.itemPaddingVertical)) {
            Icon(
                imageVector = Icons.Outlined.SignalCellularAlt,
                contentDescription = null,
@@ -497,6 +525,11 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
        onboardingService.initData(targetSubId, context,callback)
    }

    private fun startSimOnboardingProvider() {
        val route = getRoute(onboardingService.targetSubId)
        startSpaActivity(route)
    }

    companion object {
        @JvmStatic
        fun startSimOnboardingActivity(
@@ -523,9 +556,10 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
        enum class CallbackType(val value:Int){
            CALLBACK_ERROR(-1),
            CALLBACK_ONBOARDING_COMPLETE(1),
            CALLBACK_SETUP_NAME(2),
            CALLBACK_SETUP_PRIMARY_SIM(3),
            CALLBACK_FINISH(4)
            CALLBACK_ENABLE_DSDS(2),
            CALLBACK_SETUP_NAME(3),
            CALLBACK_SETUP_PRIMARY_SIM(4),
            CALLBACK_FINISH(5)
        }
    }
}
 No newline at end of file
+101 −26
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.sim.SimActivationNotifier
import com.android.settings.spa.network.setAutomaticData
import com.android.settings.spa.network.setDefaultData
import com.android.settings.spa.network.setDefaultSms
@@ -32,9 +33,6 @@ import com.android.settingslib.utils.ThreadUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

private const val TAG = "SimOnboardingService"
private const val INVALID = SubscriptionManager.INVALID_SUBSCRIPTION_ID

class SimOnboardingService {
    var subscriptionManager:SubscriptionManager? = null
    var telephonyManager:TelephonyManager? = null
@@ -70,7 +68,7 @@ class SimOnboardingService {
            }
            return  uiccCardInfoList.any { it.isMultipleEnabledProfilesSupported }
        }
    var isRemovableSimEnabled: Boolean = false
    var isRemovablePsimProfileEnabled: Boolean = false
        get() {
            if(slotInfoList.isEmpty()) {
                Log.w(TAG, "UICC Slot info list is empty.")
@@ -78,7 +76,11 @@ class SimOnboardingService {
            }
            return UiccSlotUtil.isRemovableSimEnabled(slotInfoList)
        }

    var isEsimProfileEnabled: Boolean = false
        get() {
            activeSubInfoList.stream().anyMatch { it.isEmbedded }
            return false
        }
    var doesTargetSimHaveEsimOperation = false
        get() {
            return targetSubInfo?.isEmbedded ?: false
@@ -109,6 +111,19 @@ class SimOnboardingService {
            }
            return getActiveModemCount != 0 && activeSubInfoList.size == getActiveModemCount
        }
    var isMultiSimEnabled = false
        get() {
            return getActiveModemCount > 1
        }
    var isMultiSimSupported = false
        get() {
            return telephonyManager?.isMultiSimSupported == TelephonyManager.MULTISIM_ALLOWED
        }

    var doesSwitchMultiSimConfigTriggerReboot = false
        get() {
            return telephonyManager?.doesSwitchMultiSimConfigTriggerReboot() ?: false
        }

    fun isValid(): Boolean {
        return targetSubId != INVALID
@@ -161,9 +176,10 @@ class SimOnboardingService {
            targetPrimarySimCalls = SubscriptionManager.getDefaultVoiceSubscriptionId()
            targetPrimarySimTexts = SubscriptionManager.getDefaultSmsSubscriptionId()
            targetPrimarySimMobileData = SubscriptionManager.getDefaultDataSubscriptionId()

            Log.d(
                TAG,"doesTargetSimHaveEsimOperation: $doesTargetSimHaveEsimOperation" +
                    ", isRemovableSimEnabled: $isRemovableSimEnabled" +
                    ", isRemovableSimEnabled: $isRemovablePsimProfileEnabled" +
                    ", isMultipleEnabledProfilesSupported: $isMultipleEnabledProfilesSupported" +
                    ", targetPrimarySimCalls: $targetPrimarySimCalls" +
                    ", targetPrimarySimTexts: $targetPrimarySimTexts" +
@@ -261,6 +277,45 @@ class SimOnboardingService {
        }
    }

    fun isDsdsConditionSatisfied(): Boolean {
        if (isMultiSimEnabled) {
            Log.d(
                TAG,
                "DSDS is already enabled. Condition not satisfied."
            )
            return false
        }
        if (!isMultiSimSupported) {
            Log.d(TAG, "Hardware does not support DSDS.")
            return false
        }
        val isActiveSim = activeSubInfoList.isNotEmpty()
        if (isMultipleEnabledProfilesSupported && isActiveSim) {
            Log.d(TAG,
                "Device supports MEP and eSIM operation and eSIM profile is enabled."
                        + " DSDS condition satisfied."
            )
            return true
        }

        if (doesTargetSimHaveEsimOperation && isRemovablePsimProfileEnabled) {
            Log.d(TAG,
                "eSIM operation and removable PSIM is enabled. DSDS condition satisfied."
            )
            return true
        }

        if (!doesTargetSimHaveEsimOperation && isEsimProfileEnabled) {
            Log.d(TAG,
                "Removable SIM operation and eSIM profile is enabled. DSDS condition"
                        + " satisfied."
            )
            return true
        }
        Log.d(TAG, "DSDS condition not satisfied.")
        return false
    }

    fun startActivatingSim(){
        // TODO: start to activate sim
        callback(CallbackType.CALLBACK_FINISH)
@@ -281,6 +336,11 @@ class SimOnboardingService {

    suspend fun startSetupPrimarySim(context: Context) {
        withContext(Dispatchers.Default) {
            if (SubscriptionUtil.getActiveSubscriptions(subscriptionManager).size <= 1) {
                Log.d(TAG,
                    "startSetupPrimarySim: number of active subscriptionInfo is less than 2"
                )
            } else {
                setDefaultVoice(subscriptionManager, targetPrimarySimCalls)
                setDefaultSms(subscriptionManager, targetPrimarySimTexts)
                setDefaultData(
@@ -302,9 +362,24 @@ class SimOnboardingService {
                            ?.createForSubscriptionId(nonDds)
                    setAutomaticData(telephonyManagerForNonDds, targetPrimarySimAutoDataSwitch)
                }

            }
            // no next action, send finish
            callback(CallbackType.CALLBACK_FINISH)
        }
    }

    suspend fun startEnableDsds(context: Context) {
        withContext(Dispatchers.Default) {
            Log.d(TAG, "User confirmed reboot to enable DSDS.")
            SimActivationNotifier.setShowSimSettingsNotification(context, true)
            telephonyManager?.switchMultiSimConfig(NUM_OF_SIMS_FOR_DSDS)
            callback(CallbackType.CALLBACK_FINISH)
        }
    }

    companion object{
        private const val TAG = "SimOnboardingService"
        private const val INVALID = SubscriptionManager.INVALID_SUBSCRIPTION_ID
        const val NUM_OF_SIMS_FOR_DSDS = 2
    }
}
 No newline at end of file