Merge "Add the UI of dual sim onboarding" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
4601261f81
@@ -11538,7 +11538,7 @@
|
||||
<!-- Button on the dual sim onboarding to go to next page. [CHAR LIMIT=30] -->
|
||||
<string name="sim_onboarding_next">Next</string>
|
||||
<!-- Text on the progressbar of dual sim onboarding for turning sim on. [CHAR LIMIT=30] -->
|
||||
<string name="sim_onboarding_profressbar_turning_sim_on">Turning on <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>…</string>
|
||||
<string name="sim_onboarding_progressbar_turning_sim_on">Turning on <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>…</string>
|
||||
<!-- Title of service provider name(SPN) at mobile network settings page. [CHAR LIMIT=30] -->
|
||||
<string name="mobile_network_spn_title">Mobile network</string>
|
||||
<!-- Title of phone number at mobile network settings page. [CHAR LIMIT=30] -->
|
||||
|
126
src/com/android/settings/network/SimOnboardingService.kt
Normal file
126
src/com/android/settings/network/SimOnboardingService.kt
Normal file
@@ -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<SubscriptionInfo> = listOf()
|
||||
var activeSubInfoList: List<SubscriptionInfo> = listOf()
|
||||
var slotInfoList: List<UiccSlotInfo> = listOf()
|
||||
var uiccCardInfoList: List<UiccCardInfo> = listOf()
|
||||
var selectedSubInfoList: MutableList<SubscriptionInfo> = 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<Int, String> = 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<SubscriptionInfo> {
|
||||
var list: MutableList<SubscriptionInfo> = 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
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
@@ -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(
|
||||
|
113
src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
Normal file
113
src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
Normal file
@@ -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
|
||||
})
|
||||
}
|
||||
}
|
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
160
src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
Normal file
160
src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
Normal file
@@ -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<ListPreferenceOption>,
|
||||
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 }
|
||||
}
|
||||
})
|
@@ -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 }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -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<SimOnboardingService> {
|
||||
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()
|
||||
}
|
||||
}
|
@@ -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<SimOnboardingService> {
|
||||
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
|
||||
}
|
||||
}
|
@@ -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<SimOnboardingService> {
|
||||
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()
|
||||
}
|
||||
}
|
@@ -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<SimOnboardingService> {
|
||||
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()
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user