Merge "Sort the selectable subscription by id" into main
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8b0cd67..f26939e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -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>
diff --git a/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java b/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java
index 869443c..58aa0cc 100644
--- a/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java
+++ b/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java
@@ -47,7 +47,7 @@
/**
- * A preference controller to turn on/off keyboard vibration state with a single toggle.
+ * A preference controller to turn on/off keyboard vibration state with a single toggle.
*/
public class KeyboardVibrationTogglePreferenceController extends TogglePreferenceController
implements DefaultLifecycleObserver {
@@ -110,7 +110,9 @@
@Override
public int getAvailabilityStatus() {
if (Flags.keyboardCategoryEnabled()
- && mContext.getResources().getBoolean(R.bool.config_keyboard_vibration_supported)) {
+ && mContext.getResources().getBoolean(R.bool.config_keyboard_vibration_supported)
+ && mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_keyboardHapticFeedbackFixedAmplitude) > 0) {
return AVAILABLE;
}
return UNSUPPORTED_ON_DEVICE;
diff --git a/src/com/android/settings/network/SimOnboardingActivity.kt b/src/com/android/settings/network/SimOnboardingActivity.kt
index 98bb5d7..350f5b8 100644
--- a/src/com/android/settings/network/SimOnboardingActivity.kt
+++ b/src/com/android/settings/network/SimOnboardingActivity.kt
@@ -21,7 +21,6 @@
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.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.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 @@
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 @@
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 @@
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 @@
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.
- // case#2: The device don't need the reboot. Enabling DSDS and then showing
- // the SIM onboarding UI.
-
- // case#2
- val route = getRoute(onboardingService.targetSubId)
- startSpaActivity(route)
+ 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
+ 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 = {},
@@ -232,19 +286,14 @@
) {
Row(
modifier = Modifier
- .fillMaxWidth()
- .padding(SettingsDimension.itemPaddingStart),
+ .fillMaxWidth()
+ .padding(SettingsDimension.itemPaddingStart),
verticalAlignment = Alignment.CenterVertically
) {
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 @@
Log.e(TAG, "Error while sidecarReceiverFlow", e)
}.conflate()
- fun startSimSwitching(){
+ fun startSimSwitching() {
Log.d(TAG, "startSimSwitching:")
var targetSubInfo = onboardingService.targetSubInfo
@@ -376,8 +425,6 @@
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 @@
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 @@
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 @@
onboardingService.initData(targetSubId, context,callback)
}
+ private fun startSimOnboardingProvider() {
+ val route = getRoute(onboardingService.targetSubId)
+ startSpaActivity(route)
+ }
+
companion object {
@JvmStatic
fun startSimOnboardingActivity(
@@ -523,9 +556,10 @@
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
diff --git a/src/com/android/settings/network/SimOnboardingService.kt b/src/com/android/settings/network/SimOnboardingService.kt
index 962741f..2ec1ad3 100644
--- a/src/com/android/settings/network/SimOnboardingService.kt
+++ b/src/com/android/settings/network/SimOnboardingService.kt
@@ -24,6 +24,7 @@
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 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 @@
}
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 @@
}
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 @@
}
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 @@
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 @@
}
}
+ 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,30 +336,50 @@
suspend fun startSetupPrimarySim(context: Context) {
withContext(Dispatchers.Default) {
- setDefaultVoice(subscriptionManager,targetPrimarySimCalls)
- setDefaultSms(subscriptionManager,targetPrimarySimTexts)
- setDefaultData(
- context,
- subscriptionManager,
- null,
- targetPrimarySimMobileData
- )
+ 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,
+ null,
+ targetPrimarySimMobileData
+ )
- var nonDds = targetNonDds
- Log.d(
- TAG,
- "setAutomaticData: targetNonDds: $nonDds," +
- " targetPrimarySimAutoDataSwitch: $targetPrimarySimAutoDataSwitch"
- )
- if (nonDds != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- val telephonyManagerForNonDds: TelephonyManager? =
- context.getSystemService(TelephonyManager::class.java)
- ?.createForSubscriptionId(nonDds)
- setAutomaticData(telephonyManagerForNonDds, targetPrimarySimAutoDataSwitch)
+ var nonDds = targetNonDds
+ Log.d(
+ TAG,
+ "setAutomaticData: targetNonDds: $nonDds," +
+ " targetPrimarySimAutoDataSwitch: $targetPrimarySimAutoDataSwitch"
+ )
+ if (nonDds != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ val telephonyManagerForNonDds: TelephonyManager? =
+ context.getSystemService(TelephonyManager::class.java)
+ ?.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
diff --git a/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java
index cf12e34..2d5905e 100644
--- a/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java
@@ -84,6 +84,9 @@
public void getAvailabilityStatus_featureSupported_available() {
mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
when(mResources.getBoolean(R.bool.config_keyboard_vibration_supported)).thenReturn(true);
+ when(mResources.getFloat(
+ com.android.internal.R.dimen.config_keyboardHapticFeedbackFixedAmplitude))
+ .thenReturn(0.8f);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}