SIM Onboarding flow completed

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

Change-Id: Ie9680f0a67afe453c1449c0f2b59e98fd627e215
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 195c44e..720b3587 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -802,6 +802,11 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".network.SimOnboardingActivity"
+            android:exported="false"
+            android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
+            android:theme="@style/Theme.SpaLib.BottomSheetDialog"/>
+
         <activity android:name=".network.telephony.ToggleSubscriptionDialogActivity"
                   android:exported="false"
                   android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
diff --git a/src/com/android/settings/network/SimOnboardingActivity.kt b/src/com/android/settings/network/SimOnboardingActivity.kt
new file mode 100644
index 0000000..f5dc886
--- /dev/null
+++ b/src/com/android/settings/network/SimOnboardingActivity.kt
@@ -0,0 +1,430 @@
+/*
+ * 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.network
+
+import android.app.ProgressDialog
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.telephony.SubscriptionManager
+import android.util.Log
+import android.view.MotionEvent
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.SignalCellularAlt
+import androidx.compose.material3.Button
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.ModalBottomSheet
+import androidx.compose.material3.SheetState
+import androidx.compose.material3.Text
+import androidx.compose.material3.rememberModalBottomSheetState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
+import com.android.settings.R
+import com.android.settings.SidecarFragment
+import com.android.settings.network.telephony.SubscriptionActionDialogActivity
+import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
+import com.android.settings.spa.network.SimOnboardingPageProvider.getRoute
+import com.android.settingslib.spa.SpaBaseDialogActivity
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
+import com.android.settingslib.spa.widget.ui.SettingsTitle
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.launch
+
+class SimOnboardingActivity : SpaBaseDialogActivity() {
+    lateinit var scope: CoroutineScope
+    lateinit var showBottomSheet: MutableState<Boolean>
+    lateinit var showError: MutableState<Boolean>
+    lateinit var showDialog: MutableState<Boolean>
+
+    private var switchToEuiccSubscriptionSidecar: SwitchToEuiccSubscriptionSidecar? = null
+    private var switchToRemovableSlotSidecar: SwitchToRemovableSlotSidecar? = null
+    private var enableMultiSimSidecar: EnableMultiSimSidecar? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        if (!this.userManager.isAdminUser) {
+            Log.e(TAG, "It is not the admin user. Unable to toggle subscription.")
+            finish()
+            return
+        }
+
+        var targetSubId = intent.getIntExtra(SUB_ID,SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+        initServiceData(this, targetSubId, callbackListener)
+        if (!onboardingService.isUsableTargetSubscriptionId) {
+            Log.e(TAG, "The subscription id is not usable.")
+            finish()
+            return
+        }
+
+        switchToEuiccSubscriptionSidecar = SwitchToEuiccSubscriptionSidecar.get(fragmentManager)
+        switchToRemovableSlotSidecar = SwitchToRemovableSlotSidecar.get(fragmentManager)
+        enableMultiSimSidecar = EnableMultiSimSidecar.get(fragmentManager)
+
+        setContent {
+            Content()
+        }
+    }
+
+    override fun finish() {
+        setProgressDialog(false)
+        onboardingService.clear()
+        super.finish()
+    }
+
+    var callbackListener: (Int) -> Unit = {
+        Log.d(TAG, "Receive the CALLBACK: $it")
+        when (it) {
+            CALLBACK_ERROR -> {
+                setProgressDialog(false)
+                showError.value = true
+            }
+
+            CALLBACK_ONBOARDING_COMPLETE -> {
+                showBottomSheet.value = false
+                setProgressDialog(true)
+                scope.launch {
+                    // TODO: refactor the Sidecar
+                    // start to activate the sim
+                    startSimSwitching()
+                }
+            }
+
+            CALLBACK_SETUP_NAME -> {
+                scope.launch {
+                    onboardingService.startSetupName()
+                }
+            }
+
+            CALLBACK_SETUP_PRIMARY_SIM -> {
+                scope.launch {
+                    onboardingService.startSetupPrimarySim(this@SimOnboardingActivity)
+                }
+            }
+
+            CALLBACK_FINISH -> {
+                finish()
+            }
+        }
+    }
+
+    fun setProgressDialog(enable: Boolean) {
+        showDialog.value = enable
+        val progressState = if (enable) {
+            SubscriptionActionDialogActivity.PROGRESS_IS_SHOWING
+        } else {
+            SubscriptionActionDialogActivity.PROGRESS_IS_NOT_SHOWING
+        }
+        setProgressState(progressState)
+    }
+
+    @OptIn(ExperimentalMaterial3Api::class)
+    @Composable
+    override fun Content() {
+        showBottomSheet = remember { mutableStateOf(true) }
+        showError = remember { mutableStateOf(false) }
+        showDialog = remember { mutableStateOf(false) }
+        scope = rememberCoroutineScope()
+
+        registerSidecarReceiverFlow()
+
+        if(showError.value){
+            // show error
+            return
+        }
+
+        if (showBottomSheet.value) {
+            var sheetState = rememberModalBottomSheetState()
+            BottomSheetImpl(
+                sheetState = sheetState,
+                nextAction = {
+                    // TODO: if the phone is SS mode and the isDsdsConditionSatisfied is true, then
+                    //  enable the DSDS mode.
+                    //  case#1: the device need the reboot after enabling DSDS. Showing the confirm
+                    //          dialog to user whether reboot device or not.
+                    //  case#2: The device don't need the reboot. Enabling DSDS and then showing
+                    //          the SIM onboarding UI.
+
+                    // case#2
+                    val route = getRoute(onboardingService.targetSubId)
+                    startSpaActivity(route)
+                },
+                cancelAction = { finish() },
+            )
+        } else {
+            ProgressDialogImpl()
+        }
+    }
+
+    @Composable
+    fun ProgressDialogImpl() {
+        // TODO: 1. Create the SPA's ProgressDialog and using SPA's widget
+        val dialog: ProgressDialog = object : ProgressDialog(this) {
+            override fun onTouchEvent(event: MotionEvent): Boolean {
+                return true
+            }
+        }
+        dialog.setMessage(
+            stringResource(
+                R.string.sim_onboarding_progressbar_turning_sim_on,
+                onboardingService.targetSubInfo?.displayName ?: ""
+            )
+        )
+        dialog.setCancelable(false)
+
+        if(showDialog.value) {
+            dialog.show()
+        }
+    }
+    @Composable
+    fun registerSidecarReceiverFlow(){
+        switchToEuiccSubscriptionSidecar?.sidecarReceiverFlow()
+            ?.collectLatestWithLifecycle(LocalLifecycleOwner.current) {
+                onStateChange(it)
+            }
+        switchToRemovableSlotSidecar?.sidecarReceiverFlow()
+            ?.collectLatestWithLifecycle(LocalLifecycleOwner.current) {
+                onStateChange(it)
+            }
+        enableMultiSimSidecar?.sidecarReceiverFlow()
+            ?.collectLatestWithLifecycle(LocalLifecycleOwner.current) {
+                onStateChange(it)
+            }
+    }
+
+    fun SidecarFragment.sidecarReceiverFlow(): Flow<SidecarFragment> = callbackFlow {
+        val broadcastReceiver = SidecarFragment.Listener {
+            Log.d(TAG, "onReceive: $it")
+            trySend(it)
+        }
+        addListener(broadcastReceiver)
+
+        awaitClose { removeListener(broadcastReceiver) }
+    }.catch { e ->
+        Log.e(TAG, "Error while sidecarReceiverFlow", e)
+    }.conflate()
+
+    fun startSimSwitching(){
+        Log.d(TAG, "startSimSwitching:")
+
+        var targetSubInfo = onboardingService.targetSubInfo
+        targetSubInfo?.let {
+            var removedSubInfo = onboardingService.getRemovedSim()
+            if (targetSubInfo.isEmbedded) {
+                switchToEuiccSubscriptionSidecar!!.run(
+                    targetSubInfo.subscriptionId,
+                    UiccSlotUtil.INVALID_PORT_ID,
+                    removedSubInfo
+                )
+                return@let
+            }
+            switchToRemovableSlotSidecar!!.run(
+                UiccSlotUtil.INVALID_PHYSICAL_SLOT_ID,
+                removedSubInfo
+            )
+        } ?: run {
+            Log.e(TAG, "no target subInfo in onboardingService")
+            finish()
+        }
+    }
+
+    fun onStateChange(fragment: SidecarFragment?) {
+        if (fragment === switchToEuiccSubscriptionSidecar) {
+            handleSwitchToEuiccSubscriptionSidecarStateChange()
+        } else if (fragment === switchToRemovableSlotSidecar) {
+            handleSwitchToRemovableSlotSidecarStateChange()
+        } else if (fragment === enableMultiSimSidecar) {
+            handleEnableMultiSimSidecarStateChange()
+        }
+    }
+
+    fun handleSwitchToEuiccSubscriptionSidecarStateChange() {
+        when (switchToEuiccSubscriptionSidecar!!.state) {
+            SidecarFragment.State.SUCCESS -> {
+                Log.i(TAG, "Successfully enable the eSIM profile.")
+                switchToEuiccSubscriptionSidecar!!.reset()
+                callbackListener(CALLBACK_SETUP_NAME)
+            }
+
+            SidecarFragment.State.ERROR -> {
+                Log.i(TAG, "Failed to enable the eSIM profile.")
+                switchToEuiccSubscriptionSidecar!!.reset()
+                callbackListener(CALLBACK_ERROR)
+                // TODO: showErrorDialog and using privileged_action_disable_fail_title and
+                //       privileged_action_disable_fail_text
+            }
+        }
+    }
+
+    fun handleSwitchToRemovableSlotSidecarStateChange() {
+        when (switchToRemovableSlotSidecar!!.state) {
+            SidecarFragment.State.SUCCESS -> {
+                Log.i(TAG, "Successfully switched to removable slot.")
+                switchToRemovableSlotSidecar!!.reset()
+                onboardingService.handleTogglePsimAction()
+                callbackListener(CALLBACK_SETUP_NAME)
+            }
+
+            SidecarFragment.State.ERROR -> {
+                Log.e(TAG, "Failed switching to removable slot.")
+                switchToRemovableSlotSidecar!!.reset()
+                callbackListener(CALLBACK_ERROR)
+                // TODO: showErrorDialog and using sim_action_enable_sim_fail_title and
+                //       sim_action_enable_sim_fail_text
+            }
+        }
+    }
+
+    fun handleEnableMultiSimSidecarStateChange() {
+        when (enableMultiSimSidecar!!.state) {
+            SidecarFragment.State.SUCCESS -> {
+                enableMultiSimSidecar!!.reset()
+                Log.i(TAG, "Successfully switched to DSDS without reboot.")
+                handleEnableSubscriptionAfterEnablingDsds()
+            }
+
+            SidecarFragment.State.ERROR -> {
+                enableMultiSimSidecar!!.reset()
+                Log.i(TAG, "Failed to switch to DSDS without rebooting.")
+                callbackListener(CALLBACK_ERROR)
+                // TODO: showErrorDialog and using dsds_activation_failure_title and
+                //       dsds_activation_failure_body_msg2
+            }
+        }
+    }
+
+    fun handleEnableSubscriptionAfterEnablingDsds() {
+        var targetSubInfo = onboardingService.targetSubInfo
+        if (targetSubInfo?.isEmbedded == true) {
+            Log.i(TAG,
+                    "DSDS enabled, start to enable profile: " + targetSubInfo.getSubscriptionId()
+            )
+            // For eSIM operations, we simply switch to the selected eSIM profile.
+            switchToEuiccSubscriptionSidecar!!.run(
+                targetSubInfo.subscriptionId,
+                UiccSlotUtil.INVALID_PORT_ID,
+                null
+            )
+            return
+        }
+        Log.i(TAG, "DSDS enabled, start to enable pSIM profile.")
+        onboardingService.handleTogglePsimAction()
+        callbackListener(CALLBACK_FINISH)
+    }
+
+    @Composable
+    fun BottomSheetBody(nextAction: () -> Unit) {
+        Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(bottom = SettingsDimension.itemPaddingVertical)) {
+            Icon(
+                imageVector = Icons.Outlined.SignalCellularAlt,
+                contentDescription = null,
+                modifier = Modifier
+                    .size(SettingsDimension.iconLarge),
+                tint = MaterialTheme.colorScheme.primary,
+            )
+            SettingsTitle(stringResource(R.string.sim_onboarding_bottomsheets_title))
+            Column(Modifier.padding(SettingsDimension.itemPadding)) {
+                Text(
+                    text = stringResource(R.string.sim_onboarding_bottomsheets_msg),
+                    color = MaterialTheme.colorScheme.onSurfaceVariant,
+                    style = MaterialTheme.typography.bodyMedium,
+                    overflow = TextOverflow.Ellipsis,
+                    textAlign = TextAlign.Center
+                )
+            }
+            Button(onClick = nextAction) {
+                Text(stringResource(R.string.sim_onboarding_setup))
+            }
+        }
+    }
+
+    @OptIn(ExperimentalMaterial3Api::class)
+    @Composable
+    fun BottomSheetImpl(
+        sheetState: SheetState,
+        nextAction: () -> Unit,
+        cancelAction: () -> Unit,
+    ) {
+        ModalBottomSheet(
+            onDismissRequest = cancelAction,
+            sheetState = sheetState,
+        ) {
+            BottomSheetBody(nextAction = nextAction)
+        }
+        LaunchedEffect(Unit) {
+            sheetState.show()
+        }
+    }
+
+    fun setProgressState(state: Int) {
+        val prefs = getSharedPreferences(
+            SubscriptionActionDialogActivity.SIM_ACTION_DIALOG_PREFS,
+            MODE_PRIVATE
+        )
+        prefs.edit().putInt(SubscriptionActionDialogActivity.KEY_PROGRESS_STATE, state).apply()
+        Log.i(TAG, "setProgressState:$state")
+    }
+
+    fun initServiceData(context: Context,targetSubId: Int, callback:(Int)->Unit) {
+        onboardingService.initData(targetSubId, context,callback)
+    }
+
+    companion object {
+        @JvmStatic
+        fun startSimOnboardingActivity(
+            context: Context,
+            subId: Int,
+        ) {
+            val intent = Intent(context, SimOnboardingActivity::class.java).apply {
+                putExtra(SUB_ID, subId)
+            }
+            context.startActivity(intent)
+        }
+
+        var onboardingService:SimOnboardingService = SimOnboardingService()
+        const val TAG = "SimOnboardingActivity"
+        const val SUB_ID = "sub_id"
+        const val CALLBACK_ERROR = -1
+        const val CALLBACK_ONBOARDING_COMPLETE = 1
+        const val CALLBACK_SETUP_NAME = 2
+        const val CALLBACK_SETUP_PRIMARY_SIM = 3
+        const val CALLBACK_FINISH = 4
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/network/SimOnboardingService.kt b/src/com/android/settings/network/SimOnboardingService.kt
index 1b3994e..8679385 100644
--- a/src/com/android/settings/network/SimOnboardingService.kt
+++ b/src/com/android/settings/network/SimOnboardingService.kt
@@ -23,11 +23,17 @@
 import android.telephony.UiccCardInfo
 import android.telephony.UiccSlotInfo
 import android.util.Log
+import com.android.settings.spa.network.setAutomaticData
+import com.android.settings.spa.network.setDefaultData
+import com.android.settings.spa.network.setDefaultSms
+import com.android.settings.spa.network.setDefaultVoice
 import com.android.settingslib.utils.ThreadUtils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
 
 
 private const val TAG = "SimOnboardingService"
-private const val INVALID = -1
+private const val INVALID = SubscriptionManager.INVALID_SUBSCRIPTION_ID
 
 class SimOnboardingService {
     var subscriptionManager:SubscriptionManager? = null
@@ -40,19 +46,72 @@
     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 targetPrimarySimCalls: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
+    var targetPrimarySimTexts: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
+    var targetPrimarySimMobileData: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
+    var targetPrimarySimAutoDataSwitch: Boolean = false
+    var targetNonDds: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
+        get() {
+            if(targetPrimarySimMobileData == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+                Log.w(TAG, "No DDS")
+                return SubscriptionManager.INVALID_SUBSCRIPTION_ID
+            }
+            return selectedSubInfoList
+                .filter { info ->
+                    (info.simSlotIndex != -1) && (info.subscriptionId != targetPrimarySimMobileData)
+                }
+                .map { it.subscriptionId }
+                .firstOrNull() ?: SubscriptionManager.INVALID_SUBSCRIPTION_ID
+        }
+    var callback: (Int) -> Unit = {}
+
     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 }
+            return  uiccCardInfoList.any { it.isMultipleEnabledProfilesSupported }
         }
+    var isRemovableSimEnabled: Boolean = false
+        get() {
+            if(slotInfoList.isEmpty()) {
+                Log.w(TAG, "UICC Slot info list is empty.")
+                return false
+            }
+            return UiccSlotUtil.isRemovableSimEnabled(slotInfoList)
+        }
+
+    var doesTargetSimHaveEsimOperation = false
+        get() {
+            return targetSubInfo?.isEmbedded ?: false
+        }
+
+    var isUsableTargetSubscriptionId = false
+        get() {
+            return SubscriptionManager.isUsableSubscriptionId(targetSubId)
+        }
+    var getActiveModemCount = 0
+        get() {
+            return telephonyManager?.getActiveModemCount() ?: 0
+        }
+
     var renameMutableMap : MutableMap<Int, String> = mutableMapOf()
+    var userSelectedSubInfoList : MutableList<SubscriptionInfo> = mutableListOf()
+
+    var isSimSelectionFinished = false
+        get() {
+            return getActiveModemCount != 0 && userSelectedSubInfoList.size == getActiveModemCount
+        }
+
+    var isAllOfSlotAssigned = false
+        get() {
+            if(getActiveModemCount == 0){
+                Log.e(TAG, "isAllOfSlotAssigned: getActiveModemCount is 0")
+                return true
+            }
+            return getActiveModemCount != 0 && activeSubInfoList.size == getActiveModemCount
+        }
 
     fun isValid(): Boolean {
         return targetSubId != INVALID
@@ -73,18 +132,27 @@
         targetPrimarySimCalls = -1
         targetPrimarySimTexts = -1
         targetPrimarySimMobileData = -1
-        renameMutableMap.clear()
+        clearUserRecord()
     }
 
-    fun initData(inputTargetSubId:Int,context: Context) {
+    fun clearUserRecord(){
+        renameMutableMap.clear()
+        userSelectedSubInfoList.clear()
+    }
+
+    fun initData(inputTargetSubId:Int,context: Context, callback: (Int) -> Unit) {
+        this.callback = callback
         targetSubId = inputTargetSubId
         subscriptionManager = context.getSystemService(SubscriptionManager::class.java)
         telephonyManager = context.getSystemService(TelephonyManager::class.java)
-
+        Log.d(
+            TAG, "startInit: targetSubId:$targetSubId"
+        )
         ThreadUtils.postOnBackgroundThread {
             activeSubInfoList = SubscriptionUtil.getActiveSubscriptions(subscriptionManager)
             availableSubInfoList = SubscriptionUtil.getAvailableSubscriptions(context)
             targetSubInfo = availableSubInfoList.find { subInfo -> subInfo.subscriptionId == targetSubId }
+            targetSubInfo?.let { userSelectedSubInfoList.add(it) }
             Log.d(
                 TAG, "targetSubId: $targetSubId" + ", targetSubInfo: $targetSubInfo" +
                     ". activeSubInfoList: $activeSubInfoList"
@@ -94,11 +162,24 @@
             uiccCardInfoList = telephonyManager?.uiccCardsInfo!!
             Log.d(TAG, "uiccCardInfoList: $uiccCardInfoList")
 
-            Log.d(TAG, "isMultipleEnabledProfilesSupported: $isMultipleEnabledProfilesSupported")
+            targetPrimarySimCalls = SubscriptionManager.getDefaultVoiceSubscriptionId()
+            targetPrimarySimTexts = SubscriptionManager.getDefaultSmsSubscriptionId()
+            targetPrimarySimMobileData = SubscriptionManager.getDefaultDataSubscriptionId()
+            Log.d(
+                TAG,"doesTargetSimHaveEsimOperation: $doesTargetSimHaveEsimOperation" +
+                    ", isRemovableSimEnabled: $isRemovableSimEnabled" +
+                    ", isMultipleEnabledProfilesSupported: $isMultipleEnabledProfilesSupported" +
+                    ", targetPrimarySimCalls: $targetPrimarySimCalls" +
+                    ", targetPrimarySimTexts: $targetPrimarySimTexts" +
+                    ", targetPrimarySimMobileData: $targetPrimarySimMobileData")
         }
     }
 
-    fun getSelectableSubscriptionInfo(): List<SubscriptionInfo> {
+    /**
+     * Return the subscriptionInfo list which has
+     * the target subscriptionInfo + active subscriptionInfo.
+     */
+    fun getSelectableSubscriptionInfoList(): List<SubscriptionInfo> {
         var list: MutableList<SubscriptionInfo> = mutableListOf()
         list.addAll(activeSubInfoList)
         if (!list.contains(targetSubInfo)) {
@@ -109,18 +190,102 @@
         return list.toList()
     }
 
+    /**
+     * Return the user selected SubscriptionInfo list.
+     */
+    fun getSelectedSubscriptionInfoList(): List<SubscriptionInfo> {
+        if (userSelectedSubInfoList.isEmpty()){
+            Log.d(TAG, "userSelectedSubInfoList is empty")
+            return activeSubInfoList
+        }
+        return userSelectedSubInfoList.toList()
+    }
+
     fun addItemForRenaming(subInfo: SubscriptionInfo, newName: String) {
         if (subInfo.displayName == newName) {
             return
         }
         renameMutableMap[subInfo.subscriptionId] = newName
+        Log.d(TAG, "renameMutableMap add ${subInfo.subscriptionId} & $newName into: $renameMutableMap")
     }
 
     fun getSubscriptionInfoDisplayName(subInfo: SubscriptionInfo): String {
         return renameMutableMap[subInfo.subscriptionId] ?: subInfo.displayName.toString()
     }
 
-    fun startActivatingSim(callback:() -> Unit){
+    fun addCurrentItemForSelectedSim(){
+        userSelectedSubInfoList.addAll(activeSubInfoList)
+    }
+
+    fun addItemForSelectedSim(selectedSubInfo: SubscriptionInfo) {
+        userSelectedSubInfoList.add(selectedSubInfo)
+    }
+
+    fun removeItemForSelectedSim(selectedSubInfo: SubscriptionInfo) {
+        if (userSelectedSubInfoList.contains(selectedSubInfo)) {
+            userSelectedSubInfoList.remove(selectedSubInfo)
+        }
+    }
+
+    /**
+     * Return the subscriptionInfo which will be removed in the slot during the sim onboarding.
+     * If return Null, then no subscriptionInfo will be removed in the slot.
+     */
+    fun getRemovedSim():SubscriptionInfo?{
+        return activeSubInfoList.find { !userSelectedSubInfoList.contains(it) }
+    }
+
+    fun handleTogglePsimAction() {
+        val canDisablePhysicalSubscription =
+            subscriptionManager?.canDisablePhysicalSubscription() == true
+        if (targetSubInfo != null && canDisablePhysicalSubscription) {
+            // TODO: to support disable case.
+            subscriptionManager?.setUiccApplicationsEnabled(
+                    targetSubInfo!!.subscriptionId, /*enabled=*/true)
+        } else {
+            Log.i(TAG, "The device does not support toggling pSIM. It is enough to just "
+                    + "enable the removable slot."
+            )
+        }
+    }
+
+    fun startActivatingSim(){
         // TODO: start to activate sim
+        callback(SimOnboardingActivity.CALLBACK_FINISH)
+    }
+
+    suspend fun startSetupName() {
+        withContext(Dispatchers.Default) {
+            renameMutableMap.forEach {
+                subscriptionManager?.setDisplayName(
+                    it.value, it.key,
+                    SubscriptionManager.NAME_SOURCE_USER_INPUT
+                )
+            }
+            // next action is SETUP_PRIMARY_SIM
+            callback(SimOnboardingActivity.CALLBACK_SETUP_PRIMARY_SIM)
+        }
+    }
+
+    suspend fun startSetupPrimarySim(context: Context) {
+        withContext(Dispatchers.Default) {
+            setDefaultVoice(subscriptionManager,targetPrimarySimCalls)
+            setDefaultSms(subscriptionManager,targetPrimarySimTexts)
+            setDefaultData(
+                context,
+                subscriptionManager,
+                null,
+                targetPrimarySimMobileData
+            )
+
+
+            val telephonyManagerForNonDds: TelephonyManager? =
+                context.getSystemService(TelephonyManager::class.java)
+                    ?.createForSubscriptionId(targetNonDds)
+            setAutomaticData(telephonyManagerForNonDds, targetPrimarySimAutoDataSwitch)
+
+            // no next action, send finish
+            callback(SimOnboardingActivity.CALLBACK_FINISH)
+        }
     }
 }
\ 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 b6b433b..84e4e75 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -48,8 +48,6 @@
 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;
@@ -546,8 +544,7 @@
             return;
         }
         if (enable && Flags.isDualSimOnboardingEnabled()) {
-            String route = SimOnboardingPageProvider.INSTANCE.getRoute(subId);
-            SpaActivity.startSpaActivity(context, route);
+            SimOnboardingActivity.startSimOnboardingActivity(context, subId);
             return;
         }
         context.startActivity(ToggleSubscriptionDialogActivity.getIntent(context, subId, enable));
diff --git a/src/com/android/settings/network/UiccSlotUtil.java b/src/com/android/settings/network/UiccSlotUtil.java
index 5175c23..df23f12 100644
--- a/src/com/android/settings/network/UiccSlotUtil.java
+++ b/src/com/android/settings/network/UiccSlotUtil.java
@@ -463,17 +463,27 @@
         if (telMgr == null) {
             return false;
         }
-        ImmutableList<UiccSlotInfo> slotInfos = UiccSlotUtil.getSlotInfos(telMgr);
+        List<UiccSlotInfo> slotInfos = UiccSlotUtil.getSlotInfos(telMgr);
+        return isRemovableSimEnabled(slotInfos);
+    }
+
+    /**
+     * Return whether the removable psim is enabled.
+     *
+     * @param slotInfos is a List of UiccSlotInfo.
+     * @return whether the removable psim is enabled.
+     */
+    public static boolean isRemovableSimEnabled(List<UiccSlotInfo> slotInfos) {
         boolean isRemovableSimEnabled =
                 slotInfos.stream()
                         .anyMatch(
                                 slot -> slot != null
                                         && slot.isRemovable()
                                         && !slot.getIsEuicc()
-                                        && slot.getPorts().stream().anyMatch(
-                                                port -> port.isActive())
+                                        && slot.getPorts().stream()
+                                                .anyMatch(port -> port.isActive())
                                         && slot.getCardStateInfo()
-                                                == UiccSlotInfo.CARD_STATE_INFO_PRESENT);
+                                        == UiccSlotInfo.CARD_STATE_INFO_PRESENT);
         Log.i(TAG, "isRemovableSimEnabled: " + isRemovableSimEnabled);
         return isRemovableSimEnabled;
     }
diff --git a/src/com/android/settings/sim/SimDialogActivity.java b/src/com/android/settings/sim/SimDialogActivity.java
index d65b2d1..4544e73 100644
--- a/src/com/android/settings/sim/SimDialogActivity.java
+++ b/src/com/android/settings/sim/SimDialogActivity.java
@@ -41,6 +41,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
+import com.android.settings.flags.Flags;
 import com.android.settings.network.CarrierConfigCache;
 import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.network.ims.WifiCallingQueryImsState;
@@ -134,6 +135,17 @@
             return;
         }
 
+        if (Flags.isDualSimOnboardingEnabled()
+                && getProgressState() == SubscriptionActionDialogActivity.PROGRESS_IS_SHOWING
+                && (dialogType == PREFERRED_PICK
+                || dialogType == DATA_PICK
+                || dialogType == CALLS_PICK
+                || dialogType == SMS_PICK)) {
+            Log.d(TAG, "Finish the sim dialog since the sim onboarding is shown");
+            finish();
+            return;
+        }
+
         final String tag = Integer.toString(dialogType);
         final FragmentManager fragmentManager = getSupportFragmentManager();
         SimDialogFragment fragment = (SimDialogFragment) fragmentManager.findFragmentByTag(tag);
diff --git a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
index e746d4a..b6d83f2 100644
--- a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
+++ b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
@@ -67,6 +67,7 @@
 
 import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
 import com.android.settingslib.spaprivileged.template.preference.RestrictedPreference
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
@@ -171,6 +172,8 @@
                     .map { it.subscriptionId }
                     .firstOrNull() ?: SubscriptionManager.INVALID_SUBSCRIPTION_ID
         }
+
+        Log.d(name, "defaultDataSubId: $defaultDataSubId, nonDds: $nonDds")
     }
 }
 
@@ -195,7 +198,6 @@
                 selectableSubscriptionInfoList
         )
         PrimarySimSectionImpl(
-                subscriptionManager,
                 activeSubscriptionInfoList,
                 defaultVoiceSubId,
                 defaultSmsSubId,
@@ -257,12 +259,49 @@
 
 @Composable
 fun PrimarySimSectionImpl(
-        subscriptionManager: SubscriptionManager?,
-        activeSubscriptionInfoList: List<SubscriptionInfo>,
-        callsSelectedId: MutableIntState,
-        textsSelectedId: MutableIntState,
-        mobileDataSelectedId: MutableIntState,
-        nonDds: MutableIntState
+    subscriptionInfoList: List<SubscriptionInfo>,
+    callsSelectedId: MutableIntState,
+    textsSelectedId: MutableIntState,
+    mobileDataSelectedId: MutableIntState,
+    nonDds: MutableIntState,
+    subscriptionManager: SubscriptionManager? =
+        LocalContext.current.getSystemService(SubscriptionManager::class.java),
+    coroutineScope: CoroutineScope = rememberCoroutineScope(),
+    context: Context = LocalContext.current,
+    actionSetCalls: (Int) -> Unit = {
+        callsSelectedId.intValue = it
+        coroutineScope.launch {
+            setDefaultVoice(subscriptionManager, it)
+        }
+    },
+    actionSetTexts: (Int) -> Unit = {
+        textsSelectedId.intValue = it
+        coroutineScope.launch {
+            setDefaultSms(subscriptionManager, it)
+        }
+    },
+    actionSetMobileData: (Int) -> Unit = {
+        mobileDataSelectedId.intValue = it
+        coroutineScope.launch {
+            // TODO: to fix the WifiPickerTracker crash when create
+            //       the wifiPickerTrackerHelper
+            setDefaultData(
+                context,
+                subscriptionManager,
+                null/*wifiPickerTrackerHelper*/,
+                it
+            )
+        }
+    },
+    actionSetAutoDataSwitch: (Boolean) -> Unit = { newState ->
+        coroutineScope.launch {
+            val telephonyManagerForNonDds: TelephonyManager? =
+                context.getSystemService(TelephonyManager::class.java)
+                    ?.createForSubscriptionId(nonDds.intValue)
+            Log.d(NetworkCellularGroupProvider.name, "NonDds:${nonDds.intValue} setAutomaticData")
+            setAutomaticData(telephonyManagerForNonDds, newState)
+        }
+    },
 ) {
     var state = rememberSaveable { mutableStateOf(false) }
     var callsAndSmsList = remember {
@@ -272,11 +311,11 @@
         mutableListOf(ListPreferenceOption(id = -1, text = "Loading"))
     }
 
-    if (activeSubscriptionInfoList.size >= 2) {
+    if (subscriptionInfoList.size >= 2) {
         state.value = true
         callsAndSmsList.clear()
         dataList.clear()
-        for (info in activeSubscriptionInfoList) {
+        for (info in subscriptionInfoList) {
             var item = ListPreferenceOption(
                     id = info.subscriptionId,
                     text = "${info.displayName}"
@@ -291,12 +330,10 @@
     } else {
         // hide the primary sim
         state.value = false
-        Log.d("NetworkCellularGroupProvider", "Hide primary sim")
+        Log.d(NetworkCellularGroupProvider.name, "Hide primary sim")
     }
 
     if (state.value) {
-        val coroutineScope = rememberCoroutineScope()
-        var context = LocalContext.current
         val telephonyManagerForNonDds: TelephonyManager? =
                 context.getSystemService(TelephonyManager::class.java)
                         ?.createForSubscriptionId(nonDds.intValue)
@@ -305,44 +342,27 @@
         }
 
         Category(title = stringResource(id = R.string.primary_sim_title)) {
-            createPrimarySimListPreference(
+            CreatePrimarySimListPreference(
                     stringResource(id = R.string.primary_sim_calls_title),
                     callsAndSmsList,
                     callsSelectedId,
                     ImageVector.vectorResource(R.drawable.ic_phone),
-            ) {
-                callsSelectedId.intValue = it
-                coroutineScope.launch {
-                    setDefaultVoice(subscriptionManager, it)
-                }
-            }
-            createPrimarySimListPreference(
+                    actionSetCalls
+            )
+            CreatePrimarySimListPreference(
                     stringResource(id = R.string.primary_sim_texts_title),
                     callsAndSmsList,
                     textsSelectedId,
                     Icons.AutoMirrored.Outlined.Message,
-            ) {
-                textsSelectedId.intValue = it
-                coroutineScope.launch {
-                    setDefaultSms(subscriptionManager, it)
-                }
-            }
-            createPrimarySimListPreference(
+                    actionSetTexts
+            )
+            CreatePrimarySimListPreference(
                     stringResource(id = R.string.mobile_data_settings_title),
                     dataList,
                     mobileDataSelectedId,
                     Icons.Outlined.DataUsage,
-            ) {
-                mobileDataSelectedId.intValue = it
-                coroutineScope.launch {
-                    // TODO: to fix the WifiPickerTracker crash when create
-                    //       the wifiPickerTrackerHelper
-                    setDefaultData(context,
-                            subscriptionManager,
-                            null/*wifiPickerTrackerHelper*/,
-                            it)
-                }
-            }
+                    actionSetMobileData
+            )
         }
 
         val autoDataTitle = stringResource(id = R.string.primary_sim_automatic_data_title)
@@ -351,25 +371,18 @@
             object : SwitchPreferenceModel {
                 override val title = autoDataTitle
                 override val summary = { autoDataSummary }
-                override val changeable: () -> Boolean = {
-                    nonDds.intValue != SubscriptionManager.INVALID_SUBSCRIPTION_ID
-                }
                 override val checked = {
-                    coroutineScope.launch {
-                        withContext(Dispatchers.Default) {
-                            automaticDataChecked.value = telephonyManagerForNonDds != null
-                                    && telephonyManagerForNonDds.isMobileDataPolicyEnabled(
-                                    TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
+                    if (nonDds.intValue != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+                        coroutineScope.launch {
+                            automaticDataChecked.value = getAutomaticData(telephonyManagerForNonDds)
                         }
                     }
                     automaticDataChecked.value
                 }
-                override val onCheckedChange: ((Boolean) -> Unit)? =
-                        { newChecked: Boolean ->
-                            coroutineScope.launch {
-                                setAutomaticData(telephonyManagerForNonDds, newChecked)
-                            }
-                        }
+                override val onCheckedChange: ((Boolean) -> Unit)? = {
+                    automaticDataChecked.value = it
+                    actionSetAutoDataSwitch(it)
+                }
             }
         })
     }
@@ -428,19 +441,19 @@
     return MobileNetworkUtils.showEuiccSettings(context)
 }
 
-private suspend fun setDefaultVoice(
+suspend fun setDefaultVoice(
         subscriptionManager: SubscriptionManager?,
         subId: Int): Unit = withContext(Dispatchers.Default) {
     subscriptionManager?.setDefaultVoiceSubscriptionId(subId)
 }
 
-private suspend fun setDefaultSms(
+suspend fun setDefaultSms(
         subscriptionManager: SubscriptionManager?,
         subId: Int): Unit = withContext(Dispatchers.Default) {
     subscriptionManager?.setDefaultSmsSubId(subId)
 }
 
-private suspend fun setDefaultData(context: Context,
+suspend fun setDefaultData(context: Context,
                                    subscriptionManager: SubscriptionManager?,
                                    wifiPickerTrackerHelper: WifiPickerTrackerHelper?,
                                    subId: Int): Unit = withContext(Dispatchers.Default) {
@@ -455,11 +468,22 @@
         wifiPickerTrackerHelper.setCarrierNetworkEnabled(true)
     }
 }
+suspend fun getAutomaticData(telephonyManagerForNonDds: TelephonyManager?): Boolean =
+    withContext(Dispatchers.Default) {
+        telephonyManagerForNonDds != null
+            && telephonyManagerForNonDds.isMobileDataPolicyEnabled(
+            TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
+    }
 
-private suspend fun setAutomaticData(telephonyManager: TelephonyManager?, newState: Boolean): Unit =
-        withContext(Dispatchers.Default) {
-            telephonyManager?.setMobileDataPolicyEnabled(
-                    TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
-                    newState)
-            //TODO: setup backup calling
-        }
\ No newline at end of file
+suspend fun setAutomaticData(telephonyManager: TelephonyManager?, newState: Boolean): Unit =
+    withContext(Dispatchers.Default) {
+        Log.d(
+            "NetworkCellularGroupProvider",
+            "setAutomaticData: MOBILE_DATA_POLICY_AUTO_DATA_SWITCH as $newState"
+        )
+        telephonyManager?.setMobileDataPolicyEnabled(
+            TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
+            newState
+        )
+        //TODO: setup backup calling
+    }
\ No newline at end of file
diff --git a/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt b/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
index 4cb04b6..e88c5c7 100644
--- a/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
+++ b/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
@@ -27,11 +27,9 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
 import com.android.settings.R
 import com.android.settings.network.SimOnboardingService
-import com.android.settings.network.SubscriptionUtil
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.widget.dialog.AlertDialogButton
 import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter
@@ -74,7 +72,7 @@
         SettingsBody(stringResource(R.string.sim_onboarding_label_sim_msg))
     }
 
-    for (subInfo in onboardingService.getSelectableSubscriptionInfo()) {
+    for (subInfo in onboardingService.getSelectableSubscriptionInfoList()) {
         var titleSimName by remember {
             mutableStateOf(
                 onboardingService.getSubscriptionInfoDisplayName(subInfo)
diff --git a/src/com/android/settings/spa/network/SimOnboardingPageProvider.kt b/src/com/android/settings/spa/network/SimOnboardingPageProvider.kt
index e46dc2e..c60ac88 100644
--- a/src/com/android/settings/spa/network/SimOnboardingPageProvider.kt
+++ b/src/com/android/settings/spa/network/SimOnboardingPageProvider.kt
@@ -21,6 +21,7 @@
 import android.content.Context
 import android.content.ContextWrapper
 import android.os.Bundle
+import android.util.Log
 import androidx.annotation.VisibleForTesting
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.platform.LocalContext
@@ -31,12 +32,12 @@
 import androidx.navigation.compose.rememberNavController
 import androidx.navigation.navArgument
 import com.android.settings.R
+import com.android.settings.network.SimOnboardingActivity
 import com.android.settings.network.SimOnboardingService
 import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.navigator
-
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 
@@ -59,7 +60,7 @@
 
     private val owner = createSettingsPage()
     @VisibleForTesting
-    var onboardingService: SimOnboardingService = SimOnboardingService()
+    var onboardingService: SimOnboardingService = SimOnboardingActivity.onboardingService
 
     fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = owner)
         .setUiLayoutFn {
@@ -72,18 +73,12 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        initServiceData(arguments!!.getInt(SUB_ID))
         PageImpl(onboardingService,rememberNavController())
     }
 
     fun getRoute(
         subId: Int
     ): String = "${name}/$subId"
-
-    @Composable
-    fun initServiceData(targetSubId: Int) {
-        onboardingService.initData(targetSubId, LocalContext.current)
-    }
 }
 
 private fun Context.getActivity(): Activity? = when (this) {
@@ -95,7 +90,10 @@
 @Composable
 fun PageImpl(onboardingService:SimOnboardingService,navHostController: NavHostController) {
     val context = LocalContext.current
-    var previousPageOfOnboarding: () -> Unit = { context.getActivity()?.finish() }
+    var finishOnboarding: () -> Unit = {
+        context.getActivity()?.finish()
+        onboardingService.callback(SimOnboardingActivity.CALLBACK_FINISH)
+    }
 
     NavHost(
         navController = navHostController,
@@ -103,31 +101,32 @@
     ) {
         composable(route = SimOnboardingScreen.LabelSim.name) {
             val nextPage =
-                // Adding more conditions
-                if (onboardingService.isMultipleEnabledProfilesSupported) {
+                if (onboardingService.isMultipleEnabledProfilesSupported && onboardingService.isAllOfSlotAssigned) {
                     SimOnboardingScreen.SelectSim.name
                 } else {
+                    onboardingService.addCurrentItemForSelectedSim()
                     SimOnboardingScreen.PrimarySim.name
                 }
             SimOnboardingLabelSimImpl(
                 nextAction = { navHostController.navigate(nextPage) },
-                cancelAction = previousPageOfOnboarding,
+                cancelAction = finishOnboarding,
                 onboardingService = onboardingService
             )
         }
         composable(route = SimOnboardingScreen.PrimarySim.name) {
             SimOnboardingPrimarySimImpl(
                 nextAction = {
-                    //go back and activate sim
+                    onboardingService.callback(SimOnboardingActivity.CALLBACK_ONBOARDING_COMPLETE)
+                    context.getActivity()?.finish()
                 },
-                cancelAction = previousPageOfOnboarding,
+                cancelAction = finishOnboarding,
                 onboardingService = onboardingService
             )
         }
         composable(route = SimOnboardingScreen.SelectSim.name) {
             SimOnboardingSelectSimImpl(
                 nextAction = { navHostController.navigate(SimOnboardingScreen.PrimarySim.name) },
-                cancelAction = previousPageOfOnboarding,
+                cancelAction = finishOnboarding,
                 onboardingService = onboardingService
             )
         }
diff --git a/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt b/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
index 5752a4f..999abb4 100644
--- a/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
+++ b/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
@@ -16,32 +16,25 @@
 
 package com.android.settings.spa.network
 
+import android.telephony.SubscriptionManager
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.padding
 import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.outlined.Message
-import androidx.compose.material.icons.outlined.DataUsage
 import androidx.compose.material.icons.outlined.SignalCellularAlt
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.MutableIntState
-import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.res.vectorResource
 import com.android.settings.R
 import com.android.settings.network.SimOnboardingService
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.widget.preference.ListPreference
 import com.android.settingslib.spa.widget.preference.ListPreferenceModel
 import com.android.settingslib.spa.widget.preference.ListPreferenceOption
-import com.android.settingslib.spa.widget.preference.SwitchPreference
-import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
 import com.android.settingslib.spa.widget.scaffold.BottomAppBarButton
 import com.android.settingslib.spa.widget.scaffold.SuwScaffold
 import com.android.settingslib.spa.widget.ui.SettingsBody
@@ -68,84 +61,54 @@
             cancelAction
         ),
     ) {
-        primarySimBody(onboardingService)
-    }
-}
-
-@Composable
-private fun primarySimBody(onboardingService: SimOnboardingService) {
-    //TODO: Load the status from the frameworks
-    var callsSelectedId = rememberSaveable { mutableIntStateOf(1) }
-    var textsSelectedId = rememberSaveable { mutableIntStateOf(1) }
-    var mobileDataSelectedId = rememberSaveable { mutableIntStateOf(1) }
-    var automaticDataChecked by rememberSaveable { mutableStateOf(true) }
-
-    Column(Modifier.padding(SettingsDimension.itemPadding)) {
-        SettingsBody(stringResource(id = R.string.sim_onboarding_primary_sim_msg))
-    }
-    var selectableSubscriptionInfo = onboardingService.getSelectableSubscriptionInfo()
-    var list = listOf(ListPreferenceOption(id = -1, text = "Loading"))
-    if (selectableSubscriptionInfo.size >= 2) {
-        list = listOf(
-            ListPreferenceOption(
-                id = selectableSubscriptionInfo[0].subscriptionId,
-                text = "${selectableSubscriptionInfo[0].displayName}"
-            ),
-            ListPreferenceOption(
-                id = selectableSubscriptionInfo[1].subscriptionId,
-                text = "${selectableSubscriptionInfo[1].displayName}"
-            ),
-            ListPreferenceOption(
-                id = -1,
-                text = stringResource(id = R.string.sim_calls_ask_first_prefs_title)
-            ),
-        )
-    } else {
-        // set all of primary sim items' enable as false and showing that sim.
-    }
-    createPrimarySimListPreference(
-        stringResource(id = R.string.primary_sim_calls_title),
-        list,
-        callsSelectedId,
-        ImageVector.vectorResource(R.drawable.ic_phone),
-        onIdSelected = { callsSelectedId.intValue = it }
-    )
-    createPrimarySimListPreference(
-        stringResource(id = R.string.primary_sim_texts_title),
-        list,
-        textsSelectedId,
-        Icons.AutoMirrored.Outlined.Message,
-        onIdSelected = { textsSelectedId.intValue = it }
-    )
-
-    createPrimarySimListPreference(
-            stringResource(id = R.string.mobile_data_settings_title),
-            list,
-            mobileDataSelectedId,
-        Icons.Outlined.DataUsage,
-            onIdSelected = { mobileDataSelectedId.intValue = it }
-    )
-
-    val autoDataTitle = stringResource(id = R.string.primary_sim_automatic_data_title)
-    val autoDataSummary = stringResource(id = R.string.primary_sim_automatic_data_msg)
-    SwitchPreference(remember {
-        object : SwitchPreferenceModel {
-            override val title = autoDataTitle
-            override val summary = { autoDataSummary }
-            override val checked = { automaticDataChecked }
-            override val onCheckedChange =
-                { newChecked: Boolean -> automaticDataChecked = newChecked }
+        val callsSelectedId = rememberSaveable {
+            mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
         }
-    })
+        val textsSelectedId = rememberSaveable {
+            mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+        }
+        val mobileDataSelectedId = rememberSaveable {
+            mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+        }
+        val nonDdsRemember = rememberSaveable {
+            mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+        }
+
+        Column(Modifier.padding(SettingsDimension.itemPadding)) {
+            SettingsBody(stringResource(id = R.string.sim_onboarding_primary_sim_msg))
+        }
+
+        var selectedSubscriptionInfoList = onboardingService.getSelectedSubscriptionInfoList()
+        callsSelectedId.intValue = onboardingService.targetPrimarySimCalls
+        textsSelectedId.intValue = onboardingService.targetPrimarySimTexts
+        mobileDataSelectedId.intValue = onboardingService.targetPrimarySimMobileData
+        PrimarySimSectionImpl(
+            subscriptionInfoList = selectedSubscriptionInfoList,
+            callsSelectedId = callsSelectedId,
+            textsSelectedId = textsSelectedId,
+            mobileDataSelectedId = mobileDataSelectedId,
+            nonDds = nonDdsRemember,
+            actionSetCalls = {
+                callsSelectedId.intValue = it
+                onboardingService.targetPrimarySimCalls = it},
+            actionSetTexts = {
+                textsSelectedId.intValue = it
+                onboardingService.targetPrimarySimTexts = it},
+            actionSetMobileData = {
+                mobileDataSelectedId.intValue = it
+                onboardingService.targetPrimarySimMobileData = it},
+            actionSetAutoDataSwitch = {
+                onboardingService.targetPrimarySimAutoDataSwitch = it},
+        )
+    }
 }
 
 @Composable
-fun createPrimarySimListPreference(
+fun CreatePrimarySimListPreference(
         title: String,
         list: List<ListPreferenceOption>,
         selectedId: MutableIntState,
         icon: ImageVector,
-        enable: Boolean = true,
         onIdSelected: (id: Int) -> Unit
 ) = ListPreference(remember {
     object : ListPreferenceModel {
@@ -156,7 +119,5 @@
         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
index 1955d13..5e71b12 100644
--- a/src/com/android/settings/spa/network/SimOnboardingSelectSim.kt
+++ b/src/com/android/settings/spa/network/SimOnboardingSelectSim.kt
@@ -16,24 +16,23 @@
 
 package com.android.settings.spa.network
 
+import android.util.Log
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.padding
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.SignalCellularAlt
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import com.android.settings.R
 import com.android.settings.network.SimOnboardingService
+import com.android.settings.sim.SimDialogActivity
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.widget.preference.CheckboxPreference
 import com.android.settingslib.spa.widget.preference.CheckboxPreferenceModel
-
 import com.android.settingslib.spa.widget.scaffold.BottomAppBarButton
 import com.android.settingslib.spa.widget.scaffold.SuwScaffold
 import com.android.settingslib.spa.widget.ui.SettingsBody
@@ -68,22 +67,38 @@
     Column(Modifier.padding(SettingsDimension.itemPadding)) {
         SettingsBody(stringResource(id = R.string.sim_onboarding_select_sim_msg))
     }
-    for (subInfo in onboardingService.getSelectableSubscriptionInfo()) {
+    var isFinished = rememberSaveable { mutableStateOf(false) }
+    isFinished.value = onboardingService.isSimSelectionFinished
+    for (subInfo in onboardingService.getSelectableSubscriptionInfoList()) {
         var title = onboardingService.getSubscriptionInfoDisplayName(subInfo)
         var summaryNumber =
             subInfo.number // TODO using the SubscriptionUtil.getFormattedPhoneNumber
-        var changeable = subInfo.isActive
-        var checked by rememberSaveable { mutableStateOf(!subInfo.isActive) }
+        var checked = rememberSaveable {
+            mutableStateOf(
+                onboardingService.getSelectedSubscriptionInfoList().contains(subInfo)
+            )
+        }
 
         CheckboxPreference(remember {
             object : CheckboxPreferenceModel {
                 override val title = title
                 override val summary: () -> String
                     get() = { summaryNumber }
-                override val checked = { checked }
-                override val changeable = { changeable }
-                override val onCheckedChange = { newChecked: Boolean -> checked = newChecked }
+                override val checked = { checked.value }
+                override val onCheckedChange = { newChecked: Boolean ->
+                    checked.value = newChecked
+                    if (newChecked) {
+                        onboardingService.addItemForSelectedSim(subInfo)
+                    } else {
+                        onboardingService.removeItemForSelectedSim(subInfo)
+                    }
+                    isFinished.value = onboardingService.isSimSelectionFinished
+                }
+                override val changeable = {
+                    subInfo.isActive
+                        && (!isFinished.value || (isFinished.value && checked.value))
+                }
             }
         })
     }
-}
\ 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
index dace5e9..8e12b20 100644
--- a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingLabelSimTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingLabelSimTest.kt
@@ -108,7 +108,7 @@
             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(
+            on { getSelectableSubscriptionInfoList() }.doReturn(
                 listOf(
                     SUB_INFO_1,
                     SUB_INFO_2,
@@ -139,7 +139,7 @@
             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(
+            on { getSelectableSubscriptionInfoList() }.doReturn(
                 listOf(
                     SUB_INFO_1,
                     SUB_INFO_2,
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
index 35f1968..82dba76 100644
--- a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingPageProviderTest.kt
@@ -91,6 +91,7 @@
     fun simOnboardingPage_nextAction_fromLabelSimToSelectSim() {
         mockSimOnboardingService.stub {
             on { isMultipleEnabledProfilesSupported }.thenReturn(true)
+            on { isAllOfSlotAssigned }.thenReturn(true)
         }
 
         composeTestRule.setContent {
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
index 5d7465f..45667ef 100644
--- a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt
@@ -108,7 +108,7 @@
             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(
+            on { getSelectableSubscriptionInfoList() }.doReturn(
                 listOf(
                     SUB_INFO_1,
                     SUB_INFO_2,