Loading res/values/strings.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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] --> src/com/android/settings/network/SimOnboardingService.kt 0 → 100644 +126 −0 Original line number Diff line number Diff line /* * 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 } } No newline at end of file src/com/android/settings/network/SubscriptionUtil.java +9 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); } Loading Loading @@ -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; } Loading src/com/android/settings/spa/SettingsSpaEnvironment.kt +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -114,6 +115,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { StorageAppListPageProvider.Apps, StorageAppListPageProvider.Games, ApnEditPageProvider, SimOnboardingPageProvider, ) override val logger = if (FeatureFlagUtils.isEnabled( Loading src/com/android/settings/spa/network/SimOnboardingLabelSim.kt 0 → 100644 +113 −0 Original line number Diff line number Diff line /* * 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 Loading
res/values/strings.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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] -->
src/com/android/settings/network/SimOnboardingService.kt 0 → 100644 +126 −0 Original line number Diff line number Diff line /* * 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 } } No newline at end of file
src/com/android/settings/network/SubscriptionUtil.java +9 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); } Loading Loading @@ -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; } Loading
src/com/android/settings/spa/SettingsSpaEnvironment.kt +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -114,6 +115,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { StorageAppListPageProvider.Apps, StorageAppListPageProvider.Games, ApnEditPageProvider, SimOnboardingPageProvider, ) override val logger = if (FeatureFlagUtils.isEnabled( Loading
src/com/android/settings/spa/network/SimOnboardingLabelSim.kt 0 → 100644 +113 −0 Original line number Diff line number Diff line /* * 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