diff --git a/res/values/strings.xml b/res/values/strings.xml index e73cf31eea1..cbc1f957196 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11538,7 +11538,7 @@ Next - Turning on %1$s + Turning on %1$s Mobile network diff --git a/src/com/android/settings/network/SimOnboardingService.kt b/src/com/android/settings/network/SimOnboardingService.kt new file mode 100644 index 00000000000..1b3994e476e --- /dev/null +++ b/src/com/android/settings/network/SimOnboardingService.kt @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network + +import android.content.Context +import android.telephony.SubscriptionInfo +import android.telephony.SubscriptionManager +import android.telephony.TelephonyManager +import android.telephony.UiccCardInfo +import android.telephony.UiccSlotInfo +import android.util.Log +import com.android.settingslib.utils.ThreadUtils + + +private const val TAG = "SimOnboardingService" +private const val INVALID = -1 + +class SimOnboardingService { + var subscriptionManager:SubscriptionManager? = null + var telephonyManager:TelephonyManager? = null + + var targetSubId: Int = INVALID + var targetSubInfo: SubscriptionInfo? = null + var availableSubInfoList: List = listOf() + var activeSubInfoList: List = listOf() + var slotInfoList: List = listOf() + var uiccCardInfoList: List = listOf() + var selectedSubInfoList: MutableList = mutableListOf() + var targetPrimarySimCalls: Int = -1 + var targetPrimarySimTexts: Int = -1 + var targetPrimarySimMobileData: Int = -1 + var isMultipleEnabledProfilesSupported: Boolean = false + get() { + if (uiccCardInfoList.isEmpty()) { + Log.w(TAG, "UICC cards info list is empty.") + return false + } + return uiccCardInfoList.stream() + .anyMatch { cardInfo: UiccCardInfo -> cardInfo.isMultipleEnabledProfilesSupported } + } + var renameMutableMap : MutableMap = mutableMapOf() + + fun isValid(): Boolean { + return targetSubId != INVALID + && targetSubInfo != null + && activeSubInfoList.isNotEmpty() + && slotInfoList.isNotEmpty() + && selectedSubInfoList.isNotEmpty() + } + + fun clear() { + targetSubId = -1 + targetSubInfo = null + availableSubInfoList = listOf() + activeSubInfoList = listOf() + slotInfoList = listOf() + uiccCardInfoList = listOf() + selectedSubInfoList = mutableListOf() + targetPrimarySimCalls = -1 + targetPrimarySimTexts = -1 + targetPrimarySimMobileData = -1 + renameMutableMap.clear() + } + + fun initData(inputTargetSubId:Int,context: Context) { + targetSubId = inputTargetSubId + subscriptionManager = context.getSystemService(SubscriptionManager::class.java) + telephonyManager = context.getSystemService(TelephonyManager::class.java) + + ThreadUtils.postOnBackgroundThread { + activeSubInfoList = SubscriptionUtil.getActiveSubscriptions(subscriptionManager) + availableSubInfoList = SubscriptionUtil.getAvailableSubscriptions(context) + targetSubInfo = availableSubInfoList.find { subInfo -> subInfo.subscriptionId == targetSubId } + Log.d( + TAG, "targetSubId: $targetSubId" + ", targetSubInfo: $targetSubInfo" + + ". activeSubInfoList: $activeSubInfoList" + ) + slotInfoList = telephonyManager?.uiccSlotsInfo?.toList() ?: listOf() + Log.d(TAG, "slotInfoList: $slotInfoList.") + uiccCardInfoList = telephonyManager?.uiccCardsInfo!! + Log.d(TAG, "uiccCardInfoList: $uiccCardInfoList") + + Log.d(TAG, "isMultipleEnabledProfilesSupported: $isMultipleEnabledProfilesSupported") + } + } + + fun getSelectableSubscriptionInfo(): List { + var list: MutableList = mutableListOf() + list.addAll(activeSubInfoList) + if (!list.contains(targetSubInfo)) { + targetSubInfo?.let { list.add(it) } + } + + Log.d(TAG, "list: $list") + return list.toList() + } + + fun addItemForRenaming(subInfo: SubscriptionInfo, newName: String) { + if (subInfo.displayName == newName) { + return + } + renameMutableMap[subInfo.subscriptionId] = newName + } + + fun getSubscriptionInfoDisplayName(subInfo: SubscriptionInfo): String { + return renameMutableMap[subInfo.subscriptionId] ?: subInfo.displayName.toString() + } + + fun startActivatingSim(callback:() -> Unit){ + // TODO: start to activate sim + } +} \ No newline at end of file diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java index 1065e370d6c..b6b433b7955 100644 --- a/src/com/android/settings/network/SubscriptionUtil.java +++ b/src/com/android/settings/network/SubscriptionUtil.java @@ -42,12 +42,14 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.telephony.MccTable; -import com.android.internal.telephony.flags.Flags; import com.android.settings.R; +import com.android.settings.flags.Flags; import com.android.settings.network.helper.SelectableSubscriptions; import com.android.settings.network.helper.SubscriptionAnnotation; import com.android.settings.network.telephony.DeleteEuiccSubscriptionDialogActivity; import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity; +import com.android.settings.spa.SpaActivity; +import com.android.settings.spa.network.SimOnboardingPageProvider; import java.util.ArrayList; import java.util.Collections; @@ -543,6 +545,11 @@ public class SubscriptionUtil { Log.i(TAG, "Unable to toggle subscription due to invalid subscription ID."); return; } + if (enable && Flags.isDualSimOnboardingEnabled()) { + String route = SimOnboardingPageProvider.INSTANCE.getRoute(subId); + SpaActivity.startSpaActivity(context, route); + return; + } context.startActivity(ToggleSubscriptionDialogActivity.getIntent(context, subId, enable)); } @@ -822,7 +829,7 @@ public class SubscriptionUtil { private static boolean isEmbeddedSubscriptionVisible(@NonNull SubscriptionInfo subInfo) { if (subInfo.isEmbedded() && (subInfo.getProfileClass() == PROFILE_CLASS_PROVISIONING - || (Flags.oemEnabledSatelliteFlag() + || (com.android.internal.telephony.flags.Flags.oemEnabledSatelliteFlag() && subInfo.isOnlyNonTerrestrialNetwork()))) { return false; } diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt index a6cf5cca7e0..d94e8618082 100644 --- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt +++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt @@ -47,6 +47,7 @@ import com.android.settings.spa.development.UsageStatsPageProvider import com.android.settings.spa.development.compat.PlatformCompatAppListPageProvider import com.android.settings.spa.home.HomePageProvider import com.android.settings.spa.network.NetworkAndInternetPageProvider +import com.android.settings.spa.network.SimOnboardingPageProvider import com.android.settings.spa.notification.AppListNotificationsPageProvider import com.android.settings.spa.notification.NotificationMainPageProvider import com.android.settings.spa.system.AppLanguagesPageProvider @@ -114,6 +115,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { StorageAppListPageProvider.Apps, StorageAppListPageProvider.Games, ApnEditPageProvider, + SimOnboardingPageProvider, ) override val logger = if (FeatureFlagUtils.isEnabled( diff --git a/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt b/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt new file mode 100644 index 00000000000..4cb04b69eac --- /dev/null +++ b/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.spa.network + +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.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +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 +import com.android.settingslib.spa.widget.editor.SettingsOutlinedTextField + +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.scaffold.BottomAppBarButton +import com.android.settingslib.spa.widget.scaffold.SuwScaffold +import com.android.settingslib.spa.widget.ui.SettingsBody + +/** + * the sim onboarding label compose + */ +@Composable +fun SimOnboardingLabelSimImpl( + nextAction: () -> Unit, + cancelAction: () -> Unit, + onboardingService: SimOnboardingService +) { + SuwScaffold( + imageVector = Icons.Outlined.SignalCellularAlt, + title = stringResource(R.string.sim_onboarding_label_sim_title), + actionButton = BottomAppBarButton( + stringResource(R.string.sim_onboarding_next), + nextAction + ), + dismissButton = BottomAppBarButton( + stringResource(R.string.cancel), + cancelAction + ), + ) { + labelSimBody(onboardingService) + } +} + +@Composable +private fun labelSimBody(onboardingService: SimOnboardingService) { + Column(Modifier.padding(SettingsDimension.itemPadding)) { + SettingsBody(stringResource(R.string.sim_onboarding_label_sim_msg)) + } + + for (subInfo in onboardingService.getSelectableSubscriptionInfo()) { + var titleSimName by remember { + mutableStateOf( + onboardingService.getSubscriptionInfoDisplayName(subInfo) + ) + } + var summaryNumber = subInfo.number + // TODO using the SubscriptionUtil.getFormattedPhoneNumber + val alertDialogPresenter = rememberAlertDialogPresenter( + confirmButton = AlertDialogButton( + stringResource(R.string.mobile_network_sim_name_rename) + ) { + onboardingService.addItemForRenaming(subInfo, titleSimName) + }, + dismissButton = AlertDialogButton(stringResource(R.string.cancel)) { + titleSimName = onboardingService.getSubscriptionInfoDisplayName(subInfo) + }, + title = stringResource(R.string.sim_onboarding_label_sim_dialog_title), + text = { + Text(summaryNumber) + SettingsOutlinedTextField( + value = titleSimName, + label = stringResource(R.string.sim_onboarding_label_sim_dialog_label), + enabled = true + ) { + titleSimName = it + } + }, + ) + Preference(object : PreferenceModel { + override val title = titleSimName + override val summary: () -> String + get() = { summaryNumber } + override val onClick = alertDialogPresenter::open + }) + } +} \ No newline at end of file diff --git a/src/com/android/settings/spa/network/SimOnboardingPageProvider.kt b/src/com/android/settings/spa/network/SimOnboardingPageProvider.kt new file mode 100644 index 00000000000..e46dc2e6cc6 --- /dev/null +++ b/src/com/android/settings/spa/network/SimOnboardingPageProvider.kt @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.spa.network + + +import android.app.Activity +import android.content.Context +import android.content.ContextWrapper +import android.os.Bundle +import androidx.annotation.VisibleForTesting +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.navigation.NavHostController +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument +import com.android.settings.R +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 + +const val SUB_ID = "subId" + +enum class SimOnboardingScreen(val stringResId: Int) { + LabelSim(R.string.sim_onboarding_label_sim_title), + SelectSim(R.string.sim_onboarding_select_sim_title), + PrimarySim(R.string.sim_onboarding_primary_sim_title) +} + +/** + * Showing the sim onboarding which is the process flow of sim switching on. + */ +object SimOnboardingPageProvider : SettingsPageProvider { + override val name = "SimOnboardingPageProvider" + override val parameter = listOf( + navArgument(SUB_ID) { type = NavType.IntType }, + ) + + private val owner = createSettingsPage() + @VisibleForTesting + var onboardingService: SimOnboardingService = SimOnboardingService() + + fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = owner) + .setUiLayoutFn { + // never using + Preference(object : PreferenceModel { + override val title = name + override val onClick = navigator(getRoute(-1)) + }) + } + + @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) { + is Activity -> this + is ContextWrapper -> baseContext.getActivity() + else -> null +} + +@Composable +fun PageImpl(onboardingService:SimOnboardingService,navHostController: NavHostController) { + val context = LocalContext.current + var previousPageOfOnboarding: () -> Unit = { context.getActivity()?.finish() } + + NavHost( + navController = navHostController, + startDestination = SimOnboardingScreen.LabelSim.name + ) { + composable(route = SimOnboardingScreen.LabelSim.name) { + val nextPage = + // Adding more conditions + if (onboardingService.isMultipleEnabledProfilesSupported) { + SimOnboardingScreen.SelectSim.name + } else { + SimOnboardingScreen.PrimarySim.name + } + SimOnboardingLabelSimImpl( + nextAction = { navHostController.navigate(nextPage) }, + cancelAction = previousPageOfOnboarding, + onboardingService = onboardingService + ) + } + composable(route = SimOnboardingScreen.PrimarySim.name) { + SimOnboardingPrimarySimImpl( + nextAction = { + //go back and activate sim + }, + cancelAction = previousPageOfOnboarding, + onboardingService = onboardingService + ) + } + composable(route = SimOnboardingScreen.SelectSim.name) { + SimOnboardingSelectSimImpl( + nextAction = { navHostController.navigate(SimOnboardingScreen.PrimarySim.name) }, + cancelAction = previousPageOfOnboarding, + onboardingService = onboardingService + ) + } + } +} \ No newline at end of file diff --git a/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt b/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt new file mode 100644 index 00000000000..7704f84ec40 --- /dev/null +++ b/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.spa.network + +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 +import com.android.settingslib.spa.widget.ui.SettingsIcon + +/** + * the sim onboarding primary sim compose + */ +@Composable +fun SimOnboardingPrimarySimImpl( + nextAction: () -> Unit, + cancelAction: () -> Unit, + onboardingService: SimOnboardingService +) { + SuwScaffold( + imageVector = Icons.Outlined.SignalCellularAlt, + title = stringResource(id = R.string.sim_onboarding_primary_sim_title), + actionButton = BottomAppBarButton( + stringResource(id = R.string.done), + nextAction + ), + dismissButton = BottomAppBarButton( + stringResource(id = R.string.cancel), + 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), + true + ) + createPrimarySimListPreference( + stringResource(id = R.string.primary_sim_texts_title), + list, + textsSelectedId, + Icons.AutoMirrored.Outlined.Message, + true + ) + createPrimarySimListPreference( + stringResource(id = R.string.mobile_data_settings_title), + list, + mobileDataSelectedId, + Icons.Outlined.DataUsage, + true + ) + + 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 } + } + }) +} + +@Composable +fun createPrimarySimListPreference( + title: String, + list: List, + selectedId: MutableIntState, + icon: ImageVector, + enable: Boolean +) = ListPreference(remember { + object : ListPreferenceModel { + override val title = title + override val options = list + override val selectedId = selectedId + override val onIdSelected: (id: Int) -> Unit = { selectedId.intValue = it } + override val icon = @Composable { + SettingsIcon(icon) + } + override val enabled: () -> Boolean + get() = { enable } + } +}) \ No newline at end of file diff --git a/src/com/android/settings/spa/network/SimOnboardingSelectSim.kt b/src/com/android/settings/spa/network/SimOnboardingSelectSim.kt new file mode 100644 index 00000000000..1955d1335e4 --- /dev/null +++ b/src/com/android/settings/spa/network/SimOnboardingSelectSim.kt @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.spa.network + +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.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 + +/** + * the sim onboarding select sim compose + */ +@Composable +fun SimOnboardingSelectSimImpl( + nextAction: () -> Unit, + cancelAction: () -> Unit, + onboardingService: SimOnboardingService +) { + SuwScaffold( + imageVector = Icons.Outlined.SignalCellularAlt, + title = stringResource(id = R.string.sim_onboarding_select_sim_title), + actionButton = BottomAppBarButton( + stringResource(id = R.string.sim_onboarding_next), + nextAction + ), + dismissButton = BottomAppBarButton( + stringResource(id = R.string.cancel), + cancelAction + ), + ) { + selectSimBody(onboardingService) + } +} + +@Composable +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 title = onboardingService.getSubscriptionInfoDisplayName(subInfo) + var summaryNumber = + subInfo.number // TODO using the SubscriptionUtil.getFormattedPhoneNumber + var changeable = subInfo.isActive + var checked by rememberSaveable { mutableStateOf(!subInfo.isActive) } + + 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 } + } + }) + } +} \ No newline at end of file diff --git a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingLabelSimTest.kt b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingLabelSimTest.kt new file mode 100644 index 00000000000..dace5e9acb2 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingLabelSimTest.kt @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.spa.network + +import android.content.Context +import android.telephony.SubscriptionInfo +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settings.network.SimOnboardingService +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub +import org.mockito.kotlin.verify + +@RunWith(AndroidJUnit4::class) +class SimOnboardingLabelSimTest { + @get:Rule + val composeTestRule = createComposeRule() + + private val context: Context = ApplicationProvider.getApplicationContext() + private var mockSimOnboardingService = mock { + on { targetSubId }.doReturn(-1) + on { targetSubInfo }.doReturn(null) + on { availableSubInfoList }.doReturn(listOf()) + on { activeSubInfoList }.doReturn(listOf()) + on { slotInfoList }.doReturn(listOf()) + on { uiccCardInfoList }.doReturn(listOf()) + on { selectedSubInfoList }.doReturn(mutableListOf()) + + on { targetPrimarySimCalls }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + on { targetPrimarySimTexts }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + on { targetPrimarySimMobileData }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + } + + private val nextAction: () -> Unit = mock() + private val cancelAction: () -> Unit = mock() + + @Test + fun simOnboardingLabelSimImpl_showTitle() { + composeTestRule.setContent { + SimOnboardingLabelSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_label_sim_title)) + .assertIsDisplayed() + } + + @Test + fun simOnboardingLabelSimImpl_showSubTitle() { + composeTestRule.setContent { + SimOnboardingLabelSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_label_sim_msg)) + .assertIsDisplayed() + } + + @Test + fun simOnboardingLabelSimImpl_clickNextAction_verifyNextAction() { + composeTestRule.setContent { + SimOnboardingLabelSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_next)) + .performClick() + + verify(nextAction) + } + + @Test + fun simOnboardingLabelSimImpl_clickCancelAction_verifyCancelAction() { + composeTestRule.setContent { + SimOnboardingLabelSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.cancel)) + .performClick() + + verify(cancelAction) + } + + @Test + fun simOnboardingLabelSimImpl_showItem_show3Items() { + mockSimOnboardingService.stub { + on { targetSubId }.doReturn(SUB_ID_1) + on { targetSubInfo }.doReturn(SUB_INFO_1) + on { availableSubInfoList }.doReturn(listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_3)) + on { activeSubInfoList }.doReturn(listOf(SUB_INFO_2, SUB_INFO_3)) + on { getSelectableSubscriptionInfo() }.doReturn( + listOf( + SUB_INFO_1, + SUB_INFO_2, + SUB_INFO_3 + ) + ) + on { getSubscriptionInfoDisplayName(SUB_INFO_1) }.doReturn(DISPLAY_NAME_1) + on { getSubscriptionInfoDisplayName(SUB_INFO_2) }.doReturn(DISPLAY_NAME_2) + on { getSubscriptionInfoDisplayName(SUB_INFO_3) }.doReturn(DISPLAY_NAME_3) + } + + composeTestRule.setContent { + SimOnboardingLabelSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(DISPLAY_NAME_1).assertIsDisplayed() + composeTestRule.onNodeWithText(NUMBER_1).assertIsDisplayed() + composeTestRule.onNodeWithText(DISPLAY_NAME_2).assertIsDisplayed() + composeTestRule.onNodeWithText(NUMBER_2).assertIsDisplayed() + composeTestRule.onNodeWithText(DISPLAY_NAME_3).assertIsDisplayed() + composeTestRule.onNodeWithText(NUMBER_3).assertIsDisplayed() + } + + @Test + fun simOnboardingLabelSimImpl_showDialog_checkTitle() { + mockSimOnboardingService.stub { + on { targetSubId }.doReturn(SUB_ID_1) + on { targetSubInfo }.doReturn(SUB_INFO_1) + on { availableSubInfoList }.doReturn(listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_3)) + on { activeSubInfoList }.doReturn(listOf(SUB_INFO_2, SUB_INFO_3)) + on { getSelectableSubscriptionInfo() }.doReturn( + listOf( + SUB_INFO_1, + SUB_INFO_2, + SUB_INFO_3 + ) + ) + on { getSubscriptionInfoDisplayName(SUB_INFO_1) }.doReturn(DISPLAY_NAME_1) + on { getSubscriptionInfoDisplayName(SUB_INFO_2) }.doReturn(DISPLAY_NAME_2) + on { getSubscriptionInfoDisplayName(SUB_INFO_3) }.doReturn(DISPLAY_NAME_3) + } + + composeTestRule.setContent { + SimOnboardingLabelSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + + composeTestRule.onNodeWithText(DISPLAY_NAME_1).performClick() + + composeTestRule.onNodeWithText( + context.getString(R.string.sim_onboarding_label_sim_dialog_title) + ) + .assertIsDisplayed() + } + + private companion object { + const val SUB_ID_1 = 1 + const val SUB_ID_2 = 2 + const val SUB_ID_3 = 3 + const val DISPLAY_NAME_1 = "Sub 1" + const val DISPLAY_NAME_2 = "Sub 2" + const val DISPLAY_NAME_3 = "Sub 3" + const val NUMBER_1 = "000000001" + const val NUMBER_2 = "000000002" + const val NUMBER_3 = "000000003" + const val PRIMARY_SIM_ASK_EVERY_TIME = -1 + + val SUB_INFO_1: SubscriptionInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID_1) + setDisplayName(DISPLAY_NAME_1) + setNumber(NUMBER_1) + }.build() + + val SUB_INFO_2: SubscriptionInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID_2) + setDisplayName(DISPLAY_NAME_2) + setNumber(NUMBER_2) + }.build() + + val SUB_INFO_3: SubscriptionInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID_3) + setDisplayName(DISPLAY_NAME_3) + setNumber(NUMBER_3) + }.build() + } +} diff --git a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingPageProviderTest.kt new file mode 100644 index 00000000000..35f19682393 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingPageProviderTest.kt @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.spa.network + +import android.content.Context +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.navigation.compose.rememberNavController +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settings.network.SimOnboardingService +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub + +@RunWith(AndroidJUnit4::class) +class SimOnboardingPageProviderTest { + @get:Rule + val composeTestRule = createComposeRule() + + private val context: Context = ApplicationProvider.getApplicationContext() + private var mockSimOnboardingService = mock { + on { targetSubId }.doReturn(SUB_ID) + on { targetSubInfo }.doReturn(null) + on { availableSubInfoList }.doReturn(listOf()) + on { activeSubInfoList }.doReturn(listOf()) + on { slotInfoList }.doReturn(listOf()) + on { uiccCardInfoList }.doReturn(listOf()) + on { selectedSubInfoList }.doReturn(mutableListOf()) + + on { targetPrimarySimCalls }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + on { targetPrimarySimTexts }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + on { targetPrimarySimMobileData }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + } + + @Test + fun simOnboardingPageProvider_name() { + assertThat(SimOnboardingPageProvider.name).isEqualTo("SimOnboardingPageProvider") + } + + @Test + fun simOnboardingPage_labelSim() { + composeTestRule.setContent { + val navHostController = rememberNavController() + PageImpl(mockSimOnboardingService, navHostController) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_label_sim_title)) + .assertIsDisplayed() + } + + @Test + fun simOnboardingPage_nextAction_fromLabelSimToPrimarySim() { + mockSimOnboardingService.stub { + on { isMultipleEnabledProfilesSupported }.thenReturn(false) + } + composeTestRule.setContent { + val navHostController = rememberNavController() + PageImpl(mockSimOnboardingService, navHostController) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_next)) + .performClick() + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_primary_sim_title)) + .assertIsDisplayed() + } + + @Test + fun simOnboardingPage_nextAction_fromLabelSimToSelectSim() { + mockSimOnboardingService.stub { + on { isMultipleEnabledProfilesSupported }.thenReturn(true) + } + + composeTestRule.setContent { + val navHostController = rememberNavController() + PageImpl(mockSimOnboardingService, navHostController) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_next)) + .performClick() + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_select_sim_title)) + .assertIsDisplayed() + } + + @Test + fun simOnboardingPage_nextAction_fromSelectSimToPrimarySim() { + composeTestRule.setContent { + val navHostController = rememberNavController() + PageImpl(mockSimOnboardingService, navHostController) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_next)) + .performClick() + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_primary_sim_title)) + .assertIsDisplayed() + } + + private companion object { + const val SUB_ID = 1 + const val PRIMARY_SIM_ASK_EVERY_TIME = -1 + } +} diff --git a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingPrimarySimTest.kt b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingPrimarySimTest.kt new file mode 100644 index 00000000000..9cb8909a542 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingPrimarySimTest.kt @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.spa.network + +import android.content.Context +import android.telephony.SubscriptionInfo +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settings.network.SimOnboardingService +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub +import org.mockito.kotlin.verify + + +@RunWith(AndroidJUnit4::class) +class SimOnboardingPrimarySimTest { + @get:Rule + val composeTestRule = createComposeRule() + + private val context: Context = ApplicationProvider.getApplicationContext() + private var mockSimOnboardingService = mock { + on { targetSubId }.doReturn(-1) + on { targetSubInfo }.doReturn(null) + on { availableSubInfoList }.doReturn(listOf()) + on { activeSubInfoList }.doReturn(listOf()) + on { slotInfoList }.doReturn(listOf()) + on { uiccCardInfoList }.doReturn(listOf()) + on { selectedSubInfoList }.doReturn(mutableListOf()) + + on { targetPrimarySimCalls }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + on { targetPrimarySimTexts }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + on { targetPrimarySimMobileData }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + } + + private val nextAction: () -> Unit = mock() + private val cancelAction: () -> Unit = mock() + + @Test + fun simOnboardingPrimarySimImpl_showTitle() { + composeTestRule.setContent { + SimOnboardingPrimarySimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_primary_sim_title)) + .assertIsDisplayed() + } + + @Test + fun simOnboardingPrimarySimImpl_showSubTitle() { + composeTestRule.setContent { + SimOnboardingPrimarySimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_primary_sim_msg)) + .assertIsDisplayed() + } + + @Test + fun simOnboardingPrimarySimImpl_clickCancelAction_verifyCancelAction() { + composeTestRule.setContent { + SimOnboardingPrimarySimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.cancel)) + .performClick() + + verify(cancelAction) + } + + private companion object { + const val SUB_ID_1 = 1 + const val SUB_ID_2 = 2 + const val SUB_ID_3 = 3 + const val DISPLAY_NAME_1 = "Sub 1" + const val DISPLAY_NAME_2 = "Sub 2" + const val DISPLAY_NAME_3 = "Sub 3" + const val NUMBER_1 = "000000001" + const val NUMBER_2 = "000000002" + const val NUMBER_3 = "000000003" + const val PRIMARY_SIM_ASK_EVERY_TIME = -1 + + val SUB_INFO_1: SubscriptionInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID_1) + setDisplayName(DISPLAY_NAME_1) + setNumber(NUMBER_1) + }.build() + + val SUB_INFO_2: SubscriptionInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID_2) + setDisplayName(DISPLAY_NAME_2) + setNumber(NUMBER_2) + }.build() + + val SUB_INFO_3: SubscriptionInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID_3) + setDisplayName(DISPLAY_NAME_3) + setNumber(NUMBER_3) + }.build() + } +} diff --git a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt new file mode 100644 index 00000000000..5d7465f4d50 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.spa.network + +import android.content.Context +import android.telephony.SubscriptionInfo +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settings.network.SimOnboardingService +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub +import org.mockito.kotlin.verify + +@RunWith(AndroidJUnit4::class) +class SimOnboardingSelectSimTest { + @get:Rule + val composeTestRule = createComposeRule() + + private val context: Context = ApplicationProvider.getApplicationContext() + private var mockSimOnboardingService = mock { + on { targetSubId }.doReturn(-1) + on { targetSubInfo }.doReturn(null) + on { availableSubInfoList }.doReturn(listOf()) + on { activeSubInfoList }.doReturn(listOf()) + on { slotInfoList }.doReturn(listOf()) + on { uiccCardInfoList }.doReturn(listOf()) + on { selectedSubInfoList }.doReturn(mutableListOf()) + + on { targetPrimarySimCalls }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + on { targetPrimarySimTexts }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + on { targetPrimarySimMobileData }.doReturn(PRIMARY_SIM_ASK_EVERY_TIME) + } + + private val nextAction: () -> Unit = mock() + private val cancelAction: () -> Unit = mock() + + @Test + fun simOnboardingSelectSimImpl_showTitle() { + composeTestRule.setContent { + SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_select_sim_title)) + .assertIsDisplayed() + } + + @Test + fun simOnboardingSelectSimImpl_showSubTitle() { + composeTestRule.setContent { + SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_select_sim_msg)) + .assertIsDisplayed() + } + + @Test + fun simOnboardingSelectSimImpl_clickNextAction_verifyNextAction() { + composeTestRule.setContent { + SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_next)) + .performClick() + + verify(nextAction) + } + + @Test + fun simOnboardingSelectSimImpl_clickCancelAction_verifyCancelAction() { + composeTestRule.setContent { + SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(context.getString(R.string.cancel)) + .performClick() + + verify(cancelAction) + } + + @Test + fun simOnboardingSelectSimImpl_showItem_show3Items() { + mockSimOnboardingService.stub { + on { targetSubId }.doReturn(SUB_ID_1) + on { targetSubInfo }.doReturn(SUB_INFO_1) + on { availableSubInfoList }.doReturn(listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_3)) + on { activeSubInfoList }.doReturn(listOf(SUB_INFO_2, SUB_INFO_3)) + on { getSelectableSubscriptionInfo() }.doReturn( + listOf( + SUB_INFO_1, + SUB_INFO_2, + SUB_INFO_3 + ) + ) + on { getSubscriptionInfoDisplayName(SUB_INFO_1) }.doReturn(DISPLAY_NAME_1) + on { getSubscriptionInfoDisplayName(SUB_INFO_2) }.doReturn(DISPLAY_NAME_2) + on { getSubscriptionInfoDisplayName(SUB_INFO_3) }.doReturn(DISPLAY_NAME_3) + } + + composeTestRule.setContent { + SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService) + } + + composeTestRule.onNodeWithText(DISPLAY_NAME_1).assertIsDisplayed() + composeTestRule.onNodeWithText(NUMBER_1).assertIsDisplayed() + composeTestRule.onNodeWithText(DISPLAY_NAME_2).assertIsDisplayed() + composeTestRule.onNodeWithText(NUMBER_2).assertIsDisplayed() + composeTestRule.onNodeWithText(DISPLAY_NAME_3).assertIsDisplayed() + composeTestRule.onNodeWithText(NUMBER_3).assertIsDisplayed() + } + + private companion object { + const val SUB_ID_1 = 1 + const val SUB_ID_2 = 2 + const val SUB_ID_3 = 3 + const val DISPLAY_NAME_1 = "Sub 1" + const val DISPLAY_NAME_2 = "Sub 2" + const val DISPLAY_NAME_3 = "Sub 3" + const val NUMBER_1 = "000000001" + const val NUMBER_2 = "000000002" + const val NUMBER_3 = "000000003" + const val PRIMARY_SIM_ASK_EVERY_TIME = -1 + + val SUB_INFO_1: SubscriptionInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID_1) + setDisplayName(DISPLAY_NAME_1) + setNumber(NUMBER_1) + }.build() + + val SUB_INFO_2: SubscriptionInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID_2) + setDisplayName(DISPLAY_NAME_2) + setNumber(NUMBER_2) + }.build() + + val SUB_INFO_3: SubscriptionInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID_3) + setDisplayName(DISPLAY_NAME_3) + setNumber(NUMBER_3) + }.build() + } +}