Loading res/values/strings.xml +7 −0 Original line number Diff line number Diff line Loading @@ -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> src/com/android/settings/network/SimOnboardingActivity.kt +90 −56 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -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) Loading Loading @@ -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 Loading @@ -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 = {}, Loading @@ -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) } } } Loading Loading @@ -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 } } } Loading @@ -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 -> { Loading @@ -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, Loading Loading @@ -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( Loading @@ -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 src/com/android/settings/network/SimOnboardingService.kt +101 −26 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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.") Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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" + Loading Loading @@ -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) Loading @@ -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( Loading @@ -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 Loading
res/values/strings.xml +7 −0 Original line number Diff line number Diff line Loading @@ -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>
src/com/android/settings/network/SimOnboardingActivity.kt +90 −56 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -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) Loading Loading @@ -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 Loading @@ -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 = {}, Loading @@ -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) } } } Loading Loading @@ -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 } } } Loading @@ -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 -> { Loading @@ -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, Loading Loading @@ -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( Loading @@ -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
src/com/android/settings/network/SimOnboardingService.kt +101 −26 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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.") Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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" + Loading Loading @@ -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) Loading @@ -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( Loading @@ -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