Merge "Add the mechanism of enable DSDS" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
eb80786be3
@@ -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>
|
||||
|
||||
|
@@ -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()
|
||||
if (showProgressDialog.value) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,7 +378,7 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
|
||||
Log.e(TAG, "Error while sidecarReceiverFlow", e)
|
||||
}.conflate()
|
||||
|
||||
fun startSimSwitching(){
|
||||
fun startSimSwitching() {
|
||||
Log.d(TAG, "startSimSwitching:")
|
||||
|
||||
var targetSubInfo = onboardingService.targetSubInfo
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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,8 +336,13 @@ class SimOnboardingService {
|
||||
|
||||
suspend fun startSetupPrimarySim(context: Context) {
|
||||
withContext(Dispatchers.Default) {
|
||||
setDefaultVoice(subscriptionManager,targetPrimarySimCalls)
|
||||
setDefaultSms(subscriptionManager,targetPrimarySimTexts)
|
||||
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(
|
||||
context,
|
||||
subscriptionManager,
|
||||
@@ -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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user