SIM Onboarding flow completed

- Add the setup flow for switching sim and rename and setup primary sim
  items
- Add the bottom sheet and progress dialog.
Bug: 318310357
Bug: 298898436
Bug: 298891941
Test: build pass. Will upload another cl for testing

Change-Id: Ie9680f0a67afe453c1449c0f2b59e98fd627e215
This commit is contained in:
songferngwang
2024-02-05 23:46:13 +00:00
parent 5fa73d14ab
commit f1ea484425
14 changed files with 810 additions and 193 deletions

View File

@@ -67,6 +67,7 @@ import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverF
import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
import com.android.settingslib.spaprivileged.template.preference.RestrictedPreference
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -171,6 +172,8 @@ object NetworkCellularGroupProvider : SettingsPageProvider {
.map { it.subscriptionId }
.firstOrNull() ?: SubscriptionManager.INVALID_SUBSCRIPTION_ID
}
Log.d(name, "defaultDataSubId: $defaultDataSubId, nonDds: $nonDds")
}
}
@@ -195,7 +198,6 @@ fun PageImpl(selectableSubscriptionInfoList: List<SubscriptionInfo>,
selectableSubscriptionInfoList
)
PrimarySimSectionImpl(
subscriptionManager,
activeSubscriptionInfoList,
defaultVoiceSubId,
defaultSmsSubId,
@@ -257,12 +259,49 @@ fun SimsSectionImpl(
@Composable
fun PrimarySimSectionImpl(
subscriptionManager: SubscriptionManager?,
activeSubscriptionInfoList: List<SubscriptionInfo>,
callsSelectedId: MutableIntState,
textsSelectedId: MutableIntState,
mobileDataSelectedId: MutableIntState,
nonDds: MutableIntState
subscriptionInfoList: List<SubscriptionInfo>,
callsSelectedId: MutableIntState,
textsSelectedId: MutableIntState,
mobileDataSelectedId: MutableIntState,
nonDds: MutableIntState,
subscriptionManager: SubscriptionManager? =
LocalContext.current.getSystemService(SubscriptionManager::class.java),
coroutineScope: CoroutineScope = rememberCoroutineScope(),
context: Context = LocalContext.current,
actionSetCalls: (Int) -> Unit = {
callsSelectedId.intValue = it
coroutineScope.launch {
setDefaultVoice(subscriptionManager, it)
}
},
actionSetTexts: (Int) -> Unit = {
textsSelectedId.intValue = it
coroutineScope.launch {
setDefaultSms(subscriptionManager, it)
}
},
actionSetMobileData: (Int) -> Unit = {
mobileDataSelectedId.intValue = it
coroutineScope.launch {
// TODO: to fix the WifiPickerTracker crash when create
// the wifiPickerTrackerHelper
setDefaultData(
context,
subscriptionManager,
null/*wifiPickerTrackerHelper*/,
it
)
}
},
actionSetAutoDataSwitch: (Boolean) -> Unit = { newState ->
coroutineScope.launch {
val telephonyManagerForNonDds: TelephonyManager? =
context.getSystemService(TelephonyManager::class.java)
?.createForSubscriptionId(nonDds.intValue)
Log.d(NetworkCellularGroupProvider.name, "NonDds:${nonDds.intValue} setAutomaticData")
setAutomaticData(telephonyManagerForNonDds, newState)
}
},
) {
var state = rememberSaveable { mutableStateOf(false) }
var callsAndSmsList = remember {
@@ -272,11 +311,11 @@ fun PrimarySimSectionImpl(
mutableListOf(ListPreferenceOption(id = -1, text = "Loading"))
}
if (activeSubscriptionInfoList.size >= 2) {
if (subscriptionInfoList.size >= 2) {
state.value = true
callsAndSmsList.clear()
dataList.clear()
for (info in activeSubscriptionInfoList) {
for (info in subscriptionInfoList) {
var item = ListPreferenceOption(
id = info.subscriptionId,
text = "${info.displayName}"
@@ -291,12 +330,10 @@ fun PrimarySimSectionImpl(
} else {
// hide the primary sim
state.value = false
Log.d("NetworkCellularGroupProvider", "Hide primary sim")
Log.d(NetworkCellularGroupProvider.name, "Hide primary sim")
}
if (state.value) {
val coroutineScope = rememberCoroutineScope()
var context = LocalContext.current
val telephonyManagerForNonDds: TelephonyManager? =
context.getSystemService(TelephonyManager::class.java)
?.createForSubscriptionId(nonDds.intValue)
@@ -305,44 +342,27 @@ fun PrimarySimSectionImpl(
}
Category(title = stringResource(id = R.string.primary_sim_title)) {
createPrimarySimListPreference(
CreatePrimarySimListPreference(
stringResource(id = R.string.primary_sim_calls_title),
callsAndSmsList,
callsSelectedId,
ImageVector.vectorResource(R.drawable.ic_phone),
) {
callsSelectedId.intValue = it
coroutineScope.launch {
setDefaultVoice(subscriptionManager, it)
}
}
createPrimarySimListPreference(
actionSetCalls
)
CreatePrimarySimListPreference(
stringResource(id = R.string.primary_sim_texts_title),
callsAndSmsList,
textsSelectedId,
Icons.AutoMirrored.Outlined.Message,
) {
textsSelectedId.intValue = it
coroutineScope.launch {
setDefaultSms(subscriptionManager, it)
}
}
createPrimarySimListPreference(
actionSetTexts
)
CreatePrimarySimListPreference(
stringResource(id = R.string.mobile_data_settings_title),
dataList,
mobileDataSelectedId,
Icons.Outlined.DataUsage,
) {
mobileDataSelectedId.intValue = it
coroutineScope.launch {
// TODO: to fix the WifiPickerTracker crash when create
// the wifiPickerTrackerHelper
setDefaultData(context,
subscriptionManager,
null/*wifiPickerTrackerHelper*/,
it)
}
}
actionSetMobileData
)
}
val autoDataTitle = stringResource(id = R.string.primary_sim_automatic_data_title)
@@ -351,25 +371,18 @@ fun PrimarySimSectionImpl(
object : SwitchPreferenceModel {
override val title = autoDataTitle
override val summary = { autoDataSummary }
override val changeable: () -> Boolean = {
nonDds.intValue != SubscriptionManager.INVALID_SUBSCRIPTION_ID
}
override val checked = {
coroutineScope.launch {
withContext(Dispatchers.Default) {
automaticDataChecked.value = telephonyManagerForNonDds != null
&& telephonyManagerForNonDds.isMobileDataPolicyEnabled(
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
if (nonDds.intValue != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
coroutineScope.launch {
automaticDataChecked.value = getAutomaticData(telephonyManagerForNonDds)
}
}
automaticDataChecked.value
}
override val onCheckedChange: ((Boolean) -> Unit)? =
{ newChecked: Boolean ->
coroutineScope.launch {
setAutomaticData(telephonyManagerForNonDds, newChecked)
}
}
override val onCheckedChange: ((Boolean) -> Unit)? = {
automaticDataChecked.value = it
actionSetAutoDataSwitch(it)
}
}
})
}
@@ -428,19 +441,19 @@ private fun showEuiccSettings(context: Context): Boolean {
return MobileNetworkUtils.showEuiccSettings(context)
}
private suspend fun setDefaultVoice(
suspend fun setDefaultVoice(
subscriptionManager: SubscriptionManager?,
subId: Int): Unit = withContext(Dispatchers.Default) {
subscriptionManager?.setDefaultVoiceSubscriptionId(subId)
}
private suspend fun setDefaultSms(
suspend fun setDefaultSms(
subscriptionManager: SubscriptionManager?,
subId: Int): Unit = withContext(Dispatchers.Default) {
subscriptionManager?.setDefaultSmsSubId(subId)
}
private suspend fun setDefaultData(context: Context,
suspend fun setDefaultData(context: Context,
subscriptionManager: SubscriptionManager?,
wifiPickerTrackerHelper: WifiPickerTrackerHelper?,
subId: Int): Unit = withContext(Dispatchers.Default) {
@@ -455,11 +468,22 @@ private suspend fun setDefaultData(context: Context,
wifiPickerTrackerHelper.setCarrierNetworkEnabled(true)
}
}
suspend fun getAutomaticData(telephonyManagerForNonDds: TelephonyManager?): Boolean =
withContext(Dispatchers.Default) {
telephonyManagerForNonDds != null
&& telephonyManagerForNonDds.isMobileDataPolicyEnabled(
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
}
private suspend fun setAutomaticData(telephonyManager: TelephonyManager?, newState: Boolean): Unit =
withContext(Dispatchers.Default) {
telephonyManager?.setMobileDataPolicyEnabled(
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
newState)
//TODO: setup backup calling
}
suspend fun setAutomaticData(telephonyManager: TelephonyManager?, newState: Boolean): Unit =
withContext(Dispatchers.Default) {
Log.d(
"NetworkCellularGroupProvider",
"setAutomaticData: MOBILE_DATA_POLICY_AUTO_DATA_SWITCH as $newState"
)
telephonyManager?.setMobileDataPolicyEnabled(
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
newState
)
//TODO: setup backup calling
}

View File

@@ -27,11 +27,9 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.android.settings.R
import com.android.settings.network.SimOnboardingService
import com.android.settings.network.SubscriptionUtil
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.widget.dialog.AlertDialogButton
import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter
@@ -74,7 +72,7 @@ private fun labelSimBody(onboardingService: SimOnboardingService) {
SettingsBody(stringResource(R.string.sim_onboarding_label_sim_msg))
}
for (subInfo in onboardingService.getSelectableSubscriptionInfo()) {
for (subInfo in onboardingService.getSelectableSubscriptionInfoList()) {
var titleSimName by remember {
mutableStateOf(
onboardingService.getSubscriptionInfoDisplayName(subInfo)

View File

@@ -21,6 +21,7 @@ import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.os.Bundle
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
@@ -31,12 +32,12 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.android.settings.R
import com.android.settings.network.SimOnboardingActivity
import com.android.settings.network.SimOnboardingService
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -59,7 +60,7 @@ object SimOnboardingPageProvider : SettingsPageProvider {
private val owner = createSettingsPage()
@VisibleForTesting
var onboardingService: SimOnboardingService = SimOnboardingService()
var onboardingService: SimOnboardingService = SimOnboardingActivity.onboardingService
fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = owner)
.setUiLayoutFn {
@@ -72,18 +73,12 @@ object SimOnboardingPageProvider : SettingsPageProvider {
@Composable
override fun Page(arguments: Bundle?) {
initServiceData(arguments!!.getInt(SUB_ID))
PageImpl(onboardingService,rememberNavController())
}
fun getRoute(
subId: Int
): String = "${name}/$subId"
@Composable
fun initServiceData(targetSubId: Int) {
onboardingService.initData(targetSubId, LocalContext.current)
}
}
private fun Context.getActivity(): Activity? = when (this) {
@@ -95,7 +90,10 @@ private fun Context.getActivity(): Activity? = when (this) {
@Composable
fun PageImpl(onboardingService:SimOnboardingService,navHostController: NavHostController) {
val context = LocalContext.current
var previousPageOfOnboarding: () -> Unit = { context.getActivity()?.finish() }
var finishOnboarding: () -> Unit = {
context.getActivity()?.finish()
onboardingService.callback(SimOnboardingActivity.CALLBACK_FINISH)
}
NavHost(
navController = navHostController,
@@ -103,31 +101,32 @@ fun PageImpl(onboardingService:SimOnboardingService,navHostController: NavHostCo
) {
composable(route = SimOnboardingScreen.LabelSim.name) {
val nextPage =
// Adding more conditions
if (onboardingService.isMultipleEnabledProfilesSupported) {
if (onboardingService.isMultipleEnabledProfilesSupported && onboardingService.isAllOfSlotAssigned) {
SimOnboardingScreen.SelectSim.name
} else {
onboardingService.addCurrentItemForSelectedSim()
SimOnboardingScreen.PrimarySim.name
}
SimOnboardingLabelSimImpl(
nextAction = { navHostController.navigate(nextPage) },
cancelAction = previousPageOfOnboarding,
cancelAction = finishOnboarding,
onboardingService = onboardingService
)
}
composable(route = SimOnboardingScreen.PrimarySim.name) {
SimOnboardingPrimarySimImpl(
nextAction = {
//go back and activate sim
onboardingService.callback(SimOnboardingActivity.CALLBACK_ONBOARDING_COMPLETE)
context.getActivity()?.finish()
},
cancelAction = previousPageOfOnboarding,
cancelAction = finishOnboarding,
onboardingService = onboardingService
)
}
composable(route = SimOnboardingScreen.SelectSim.name) {
SimOnboardingSelectSimImpl(
nextAction = { navHostController.navigate(SimOnboardingScreen.PrimarySim.name) },
cancelAction = previousPageOfOnboarding,
cancelAction = finishOnboarding,
onboardingService = onboardingService
)
}

View File

@@ -16,32 +16,25 @@
package com.android.settings.spa.network
import android.telephony.SubscriptionManager
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.Message
import androidx.compose.material.icons.outlined.DataUsage
import androidx.compose.material.icons.outlined.SignalCellularAlt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import com.android.settings.R
import com.android.settings.network.SimOnboardingService
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.widget.preference.ListPreference
import com.android.settingslib.spa.widget.preference.ListPreferenceModel
import com.android.settingslib.spa.widget.preference.ListPreferenceOption
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spa.widget.scaffold.BottomAppBarButton
import com.android.settingslib.spa.widget.scaffold.SuwScaffold
import com.android.settingslib.spa.widget.ui.SettingsBody
@@ -68,84 +61,54 @@ fun SimOnboardingPrimarySimImpl(
cancelAction
),
) {
primarySimBody(onboardingService)
}
}
@Composable
private fun primarySimBody(onboardingService: SimOnboardingService) {
//TODO: Load the status from the frameworks
var callsSelectedId = rememberSaveable { mutableIntStateOf(1) }
var textsSelectedId = rememberSaveable { mutableIntStateOf(1) }
var mobileDataSelectedId = rememberSaveable { mutableIntStateOf(1) }
var automaticDataChecked by rememberSaveable { mutableStateOf(true) }
Column(Modifier.padding(SettingsDimension.itemPadding)) {
SettingsBody(stringResource(id = R.string.sim_onboarding_primary_sim_msg))
}
var selectableSubscriptionInfo = onboardingService.getSelectableSubscriptionInfo()
var list = listOf(ListPreferenceOption(id = -1, text = "Loading"))
if (selectableSubscriptionInfo.size >= 2) {
list = listOf(
ListPreferenceOption(
id = selectableSubscriptionInfo[0].subscriptionId,
text = "${selectableSubscriptionInfo[0].displayName}"
),
ListPreferenceOption(
id = selectableSubscriptionInfo[1].subscriptionId,
text = "${selectableSubscriptionInfo[1].displayName}"
),
ListPreferenceOption(
id = -1,
text = stringResource(id = R.string.sim_calls_ask_first_prefs_title)
),
)
} else {
// set all of primary sim items' enable as false and showing that sim.
}
createPrimarySimListPreference(
stringResource(id = R.string.primary_sim_calls_title),
list,
callsSelectedId,
ImageVector.vectorResource(R.drawable.ic_phone),
onIdSelected = { callsSelectedId.intValue = it }
)
createPrimarySimListPreference(
stringResource(id = R.string.primary_sim_texts_title),
list,
textsSelectedId,
Icons.AutoMirrored.Outlined.Message,
onIdSelected = { textsSelectedId.intValue = it }
)
createPrimarySimListPreference(
stringResource(id = R.string.mobile_data_settings_title),
list,
mobileDataSelectedId,
Icons.Outlined.DataUsage,
onIdSelected = { mobileDataSelectedId.intValue = it }
)
val autoDataTitle = stringResource(id = R.string.primary_sim_automatic_data_title)
val autoDataSummary = stringResource(id = R.string.primary_sim_automatic_data_msg)
SwitchPreference(remember {
object : SwitchPreferenceModel {
override val title = autoDataTitle
override val summary = { autoDataSummary }
override val checked = { automaticDataChecked }
override val onCheckedChange =
{ newChecked: Boolean -> automaticDataChecked = newChecked }
val callsSelectedId = rememberSaveable {
mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
}
})
val textsSelectedId = rememberSaveable {
mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
}
val mobileDataSelectedId = rememberSaveable {
mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
}
val nonDdsRemember = rememberSaveable {
mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
}
Column(Modifier.padding(SettingsDimension.itemPadding)) {
SettingsBody(stringResource(id = R.string.sim_onboarding_primary_sim_msg))
}
var selectedSubscriptionInfoList = onboardingService.getSelectedSubscriptionInfoList()
callsSelectedId.intValue = onboardingService.targetPrimarySimCalls
textsSelectedId.intValue = onboardingService.targetPrimarySimTexts
mobileDataSelectedId.intValue = onboardingService.targetPrimarySimMobileData
PrimarySimSectionImpl(
subscriptionInfoList = selectedSubscriptionInfoList,
callsSelectedId = callsSelectedId,
textsSelectedId = textsSelectedId,
mobileDataSelectedId = mobileDataSelectedId,
nonDds = nonDdsRemember,
actionSetCalls = {
callsSelectedId.intValue = it
onboardingService.targetPrimarySimCalls = it},
actionSetTexts = {
textsSelectedId.intValue = it
onboardingService.targetPrimarySimTexts = it},
actionSetMobileData = {
mobileDataSelectedId.intValue = it
onboardingService.targetPrimarySimMobileData = it},
actionSetAutoDataSwitch = {
onboardingService.targetPrimarySimAutoDataSwitch = it},
)
}
}
@Composable
fun createPrimarySimListPreference(
fun CreatePrimarySimListPreference(
title: String,
list: List<ListPreferenceOption>,
selectedId: MutableIntState,
icon: ImageVector,
enable: Boolean = true,
onIdSelected: (id: Int) -> Unit
) = ListPreference(remember {
object : ListPreferenceModel {
@@ -156,7 +119,5 @@ fun createPrimarySimListPreference(
override val icon = @Composable {
SettingsIcon(icon)
}
override val enabled: () -> Boolean
get() = { enable }
}
})

View File

@@ -16,24 +16,23 @@
package com.android.settings.spa.network
import android.util.Log
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.SignalCellularAlt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.android.settings.R
import com.android.settings.network.SimOnboardingService
import com.android.settings.sim.SimDialogActivity
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.widget.preference.CheckboxPreference
import com.android.settingslib.spa.widget.preference.CheckboxPreferenceModel
import com.android.settingslib.spa.widget.scaffold.BottomAppBarButton
import com.android.settingslib.spa.widget.scaffold.SuwScaffold
import com.android.settingslib.spa.widget.ui.SettingsBody
@@ -68,22 +67,38 @@ private fun selectSimBody(onboardingService: SimOnboardingService) {
Column(Modifier.padding(SettingsDimension.itemPadding)) {
SettingsBody(stringResource(id = R.string.sim_onboarding_select_sim_msg))
}
for (subInfo in onboardingService.getSelectableSubscriptionInfo()) {
var isFinished = rememberSaveable { mutableStateOf(false) }
isFinished.value = onboardingService.isSimSelectionFinished
for (subInfo in onboardingService.getSelectableSubscriptionInfoList()) {
var title = onboardingService.getSubscriptionInfoDisplayName(subInfo)
var summaryNumber =
subInfo.number // TODO using the SubscriptionUtil.getFormattedPhoneNumber
var changeable = subInfo.isActive
var checked by rememberSaveable { mutableStateOf(!subInfo.isActive) }
var checked = rememberSaveable {
mutableStateOf(
onboardingService.getSelectedSubscriptionInfoList().contains(subInfo)
)
}
CheckboxPreference(remember {
object : CheckboxPreferenceModel {
override val title = title
override val summary: () -> String
get() = { summaryNumber }
override val checked = { checked }
override val changeable = { changeable }
override val onCheckedChange = { newChecked: Boolean -> checked = newChecked }
override val checked = { checked.value }
override val onCheckedChange = { newChecked: Boolean ->
checked.value = newChecked
if (newChecked) {
onboardingService.addItemForSelectedSim(subInfo)
} else {
onboardingService.removeItemForSelectedSim(subInfo)
}
isFinished.value = onboardingService.isSimSelectionFinished
}
override val changeable = {
subInfo.isActive
&& (!isFinished.value || (isFinished.value && checked.value))
}
}
})
}
}
}