• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.network
18 
19 import android.content.Context
20 import android.content.Intent
21 import android.os.Bundle
22 import android.os.UserHandle;
23 import android.provider.Settings
24 import android.telephony.SubscriptionManager
25 import android.util.Log
26 import androidx.compose.foundation.layout.Column
27 import androidx.compose.foundation.layout.Row
28 import androidx.compose.foundation.layout.fillMaxWidth
29 import androidx.compose.foundation.layout.padding
30 import androidx.compose.foundation.layout.size
31 import androidx.compose.foundation.layout.width
32 import androidx.compose.material.icons.Icons
33 import androidx.compose.material.icons.outlined.SignalCellularAlt
34 import androidx.compose.material3.AlertDialogDefaults
35 import androidx.compose.material3.BasicAlertDialog
36 import androidx.compose.material3.CircularProgressIndicator
37 import androidx.compose.material3.ExperimentalMaterial3Api
38 import androidx.compose.material3.Icon
39 import androidx.compose.material3.MaterialTheme
40 import androidx.compose.material3.Surface
41 import androidx.compose.material3.Text
42 import androidx.compose.runtime.Composable
43 import androidx.compose.runtime.LaunchedEffect
44 import androidx.compose.runtime.MutableState
45 import androidx.compose.runtime.mutableStateOf
46 import androidx.compose.runtime.rememberCoroutineScope
47 import androidx.compose.runtime.saveable.rememberSaveable
48 import androidx.compose.ui.Alignment
49 import androidx.compose.ui.Modifier
50 import androidx.compose.ui.platform.LocalContext
51 import androidx.compose.ui.platform.LocalLifecycleOwner
52 import androidx.compose.ui.res.stringResource
53 import androidx.compose.ui.text.style.TextAlign
54 import androidx.lifecycle.LifecycleRegistry
55 import com.android.settings.R
56 import com.android.settings.SidecarFragment
57 import com.android.settings.network.telephony.SimRepository
58 import com.android.settings.network.telephony.SubscriptionActionDialogActivity
59 import com.android.settings.network.telephony.SubscriptionRepository
60 import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity
61 import com.android.settings.network.telephony.requireSubscriptionManager
62 import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
63 import com.android.settings.spa.network.SimOnboardingPageProvider.getRoute
64 import com.android.settings.wifi.WifiPickerTrackerHelper
65 import com.android.settingslib.spa.SpaBaseDialogActivity
66 import com.android.settingslib.spa.framework.theme.SettingsDimension
67 import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
68 import com.android.settingslib.spa.widget.dialog.AlertDialogButton
69 import com.android.settingslib.spa.widget.dialog.SettingsAlertDialogWithIcon
70 import com.android.settingslib.spa.widget.dialog.getDialogWidth
71 import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter
72 import com.android.settingslib.spa.widget.ui.SettingsTitle
73 import com.android.settingslib.spaprivileged.framework.common.userManager
74 import java.util.concurrent.CountDownLatch
75 import java.util.concurrent.TimeUnit
76 import kotlinx.coroutines.CoroutineScope
77 import kotlinx.coroutines.Dispatchers
78 import kotlinx.coroutines.channels.awaitClose
79 import kotlinx.coroutines.flow.Flow
80 import kotlinx.coroutines.flow.callbackFlow
81 import kotlinx.coroutines.flow.catch
82 import kotlinx.coroutines.flow.conflate
83 import kotlinx.coroutines.flow.firstOrNull
84 import kotlinx.coroutines.launch
85 import kotlinx.coroutines.withContext
86 import kotlinx.coroutines.withTimeoutOrNull
87 
88 class SimOnboardingActivity : SpaBaseDialogActivity() {
89     lateinit var scope: CoroutineScope
90     lateinit var wifiPickerTrackerHelper: WifiPickerTrackerHelper
91     lateinit var context: Context
92     lateinit var showStartingDialog: MutableState<Boolean>
93     lateinit var showError: MutableState<ErrorType>
94     lateinit var showProgressDialog: MutableState<Boolean>
95     lateinit var showDsdsProgressDialog: MutableState<Boolean>
96     lateinit var showRestartDialog: MutableState<Boolean>
97 
98     private var switchToEuiccSubscriptionSidecar: SwitchToEuiccSubscriptionSidecar? = null
99     private var switchToRemovableSlotSidecar: SwitchToRemovableSlotSidecar? = null
100     private var enableMultiSimSidecar: EnableMultiSimSidecar? = null
101 
onCreatenull102     override fun onCreate(savedInstanceState: Bundle?) {
103         super.onCreate(savedInstanceState)
104 
105         if (!this.userManager.isAdminUser) {
106             Log.e(TAG, "It is not the admin user. Unable to toggle subscription.")
107             finish()
108             return
109         }
110 
111         var targetSubId = intent.getIntExtra(SUB_ID,SubscriptionManager.INVALID_SUBSCRIPTION_ID)
112         if (targetSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
113             targetSubId = intent.getIntExtra(
114               Settings.EXTRA_SUB_ID,
115               SubscriptionManager.INVALID_SUBSCRIPTION_ID
116             )
117         }
118         initServiceData(this, targetSubId, callbackListener)
119         if (!onboardingService.isUsableTargetSubscriptionId) {
120             Log.e(TAG, "The subscription id is not usable.")
121             finish()
122             return
123         }
124 
125         if (onboardingService.activeSubInfoList.isEmpty()
126             || (!onboardingService.isMultiSimEnabled && !onboardingService.isMultiSimSupported)) {
127             // TODO: refactor and replace the ToggleSubscriptionDialogActivity
128             Log.d(TAG, "onboardingService.activeSubInfoList is empty or restricted ss mode " +
129                     ", start ToggleSubscriptionDialogActivity")
130             this.startActivity(ToggleSubscriptionDialogActivity
131                     .getIntent(this.applicationContext, targetSubId, true))
132             finish()
133             return
134         }
135 
136         switchToEuiccSubscriptionSidecar = SwitchToEuiccSubscriptionSidecar.get(fragmentManager)
137         switchToRemovableSlotSidecar = SwitchToRemovableSlotSidecar.get(fragmentManager)
138         enableMultiSimSidecar = EnableMultiSimSidecar.get(fragmentManager)
139     }
140 
finishnull141     override fun finish() {
142         setProgressDialog(false)
143         onboardingService.clear()
144         super.finish()
145     }
146 
<lambda>null147     var callbackListener: (CallbackType) -> Unit = {
148         Log.d(TAG, "Receive the CALLBACK: $it")
149         when (it) {
150             CallbackType.CALLBACK_ERROR -> {
151                 setProgressDialog(false)
152             }
153 
154             CallbackType.CALLBACK_ENABLE_DSDS-> {
155                 scope.launch {
156                     onboardingService.startEnableDsds(this@SimOnboardingActivity)
157                 }
158             }
159 
160             CallbackType.CALLBACK_ONBOARDING_COMPLETE -> {
161                 showStartingDialog.value = false
162                 setProgressDialog(true)
163                 scope.launch {
164                     // TODO: refactor the Sidecar
165                     // start to activate the sim
166                     startSimSwitching()
167                 }
168             }
169 
170             CallbackType.CALLBACK_SETUP_NAME -> {
171                 scope.launch {
172                     onboardingService.startSetupName()
173                 }
174             }
175 
176             CallbackType.CALLBACK_SETUP_PRIMARY_SIM -> {
177                 scope.launch {
178                     onboardingService.startSetupPrimarySim(
179                         this@SimOnboardingActivity,
180                         wifiPickerTrackerHelper
181                     )
182                 }
183             }
184 
185             CallbackType.CALLBACK_FINISH -> {
186                 finish()
187             }
188         }
189     }
190 
setProgressDialognull191     fun setProgressDialog(enable: Boolean) {
192         if (!this::showProgressDialog.isInitialized) {
193             return
194         }
195         showProgressDialog.value = enable
196         val progressState = if (enable) {
197             SubscriptionActionDialogActivity.PROGRESS_IS_SHOWING
198         } else {
199             SubscriptionActionDialogActivity.PROGRESS_IS_NOT_SHOWING
200         }
201         setProgressState(progressState)
202     }
203 
204     @OptIn(ExperimentalMaterial3Api::class)
205     @Composable
Contentnull206     override fun Content() {
207         showStartingDialog = rememberSaveable { mutableStateOf(false) }
208         showError = rememberSaveable { mutableStateOf(ErrorType.ERROR_NONE) }
209         showProgressDialog = rememberSaveable { mutableStateOf(false) }
210         showDsdsProgressDialog = rememberSaveable { mutableStateOf(false) }
211         showRestartDialog = rememberSaveable { mutableStateOf(false) }
212         scope = rememberCoroutineScope()
213         context = LocalContext.current
214         val lifecycleOwner = LocalLifecycleOwner.current
215         wifiPickerTrackerHelper = WifiPickerTrackerHelper(
216             LifecycleRegistry(lifecycleOwner), context,
217             null /* WifiPickerTrackerCallback */
218         )
219 
220         registerSidecarReceiverFlow()
221 
222         ErrorDialogImpl()
223         RestartDialogImpl()
224         LaunchedEffect(Unit) {
225             if (showError.value != ErrorType.ERROR_NONE
226                 || showProgressDialog.value
227                 || showDsdsProgressDialog.value
228                 || showRestartDialog.value) {
229                 Log.d(TAG, "status: showError:${showError.value}, " +
230                         "showProgressDialog:${showProgressDialog.value}, " +
231                         "showDsdsProgressDialog:${showDsdsProgressDialog.value}, " +
232                         "showRestartDialog:${showRestartDialog.value}")
233                 showStartingDialog.value = false
234             } else if (onboardingService.activeSubInfoList.isNotEmpty()) {
235                 Log.d(TAG, "status: showStartingDialog.value:${showStartingDialog.value}")
236                 showStartingDialog.value = true
237             }
238         }
239 
240         if (showStartingDialog.value) {
241             StartingDialogImpl(
242                 nextAction = {
243                     if (onboardingService.isDsdsConditionSatisfied()) {
244                         // TODO: if the phone is SS mode and the isDsdsConditionSatisfied is true,
245                         //  then enable the DSDS mode.
246                         //  case#1: the device need the reboot after enabling DSDS. Showing the
247                         //          confirm dialog to user whether reboot device or not.
248                         //  case#2: The device don't need the reboot. Enabling DSDS and then showing
249                         //          the SIM onboarding UI.
250                         if (onboardingService.doesSwitchMultiSimConfigTriggerReboot) {
251                             // case#1
252                             Log.d(TAG, "Device does not support reboot free DSDS.")
253                             showRestartDialog.value = true
254                         } else {
255                             // case#2
256                             Log.d(TAG, "Enable DSDS mode")
257                             showDsdsProgressDialog.value = true
258                             enableMultiSimSidecar?.run(SimOnboardingService.NUM_OF_SIMS_FOR_DSDS)
259                         }
260                     } else {
261                         startSimOnboardingProvider()
262                     }
263                 },
264                 cancelAction = { finish() },
265             )
266         }
267 
268         if (showProgressDialog.value) {
269             ProgressDialogImpl(
270                 stringResource(
271                     R.string.sim_onboarding_progressbar_turning_sim_on,
272                     onboardingService.targetSubInfo?.displayName ?: ""
273                 )
274             )
275         }
276         if (showDsdsProgressDialog.value) {
277             ProgressDialogImpl(
278                 stringResource(R.string.sim_action_enabling_sim_without_carrier_name)
279             )
280         }
281     }
282     @Composable
RestartDialogImplnull283     private fun RestartDialogImpl() {
284         val restartDialogPresenter = rememberAlertDialogPresenter(
285             confirmButton = AlertDialogButton(
286                 stringResource(R.string.sim_action_reboot)
287             ) {
288                 callbackListener(CallbackType.CALLBACK_ENABLE_DSDS)
289             },
290             dismissButton = AlertDialogButton(
291                 stringResource(
292                     R.string.sim_action_restart_dialog_cancel,
293                     onboardingService.targetSubInfo?.displayName ?: "")
294             ) {
295                 callbackListener(CallbackType.CALLBACK_ONBOARDING_COMPLETE)
296             },
297             title = stringResource(R.string.sim_action_restart_dialog_title),
298             text = {
299                 Text(stringResource(R.string.sim_action_restart_dialog_msg))
300             },
301         )
302 
303         if(showRestartDialog.value){
304             LaunchedEffect(Unit) {
305                 restartDialogPresenter.open()
306             }
307         }
308     }
309 
310     @OptIn(ExperimentalMaterial3Api::class)
311     @Composable
ProgressDialogImplnull312     fun ProgressDialogImpl(title: String) {
313         // TODO: Create the SPA's ProgressDialog and using SPA's widget
314         BasicAlertDialog(
315             onDismissRequest = {},
316             modifier = Modifier.width(
317                 getDialogWidth()
318             ),
319         ) {
320             Surface(
321                 color = AlertDialogDefaults.containerColor,
322                 shape = AlertDialogDefaults.shape
323             ) {
324                 Row(
325                     modifier = Modifier
326                         .fillMaxWidth()
327                         .padding(SettingsDimension.itemPaddingStart),
328                     verticalAlignment = Alignment.CenterVertically
329                 ) {
330                     CircularProgressIndicator()
331                     Column(modifier = Modifier
332                             .padding(start = SettingsDimension.itemPaddingStart)) {
333                         SettingsTitle(title)
334                     }
335                 }
336             }
337         }
338     }
339 
340     @Composable
ErrorDialogImplnull341     fun ErrorDialogImpl(){
342         // EuiccSlotSidecar showErrorDialog
343         val errorDialogPresenterForSimSwitching = rememberAlertDialogPresenter(
344                 confirmButton = AlertDialogButton(
345                         stringResource(android.R.string.ok)
346                 ) {
347                     finish()
348                 },
349                 title = stringResource(R.string.sim_action_enable_sim_fail_title),
350                 text = {
351                     Text(stringResource(R.string.sim_action_enable_sim_fail_text))
352                 },
353         )
354 
355         // enableDSDS showErrorDialog
356         val errorDialogPresenterForMultiSimSidecar = rememberAlertDialogPresenter(
357                 confirmButton = AlertDialogButton(
358                         stringResource(android.R.string.ok)
359                 ) {
360                     finish()
361                 },
362                 title = stringResource(R.string.dsds_activation_failure_title),
363                 text = {
364                     Text(stringResource(R.string.dsds_activation_failure_body_msg2))
365                 },
366         )
367 
368         // show error
369         when (showError.value) {
370             ErrorType.ERROR_SIM_SWITCHING -> errorDialogPresenterForSimSwitching.open()
371             ErrorType.ERROR_ENABLE_DSDS -> errorDialogPresenterForMultiSimSidecar.open()
372             else -> {}
373         }
374     }
375 
376     @Composable
registerSidecarReceiverFlownull377     fun registerSidecarReceiverFlow(){
378         switchToEuiccSubscriptionSidecar?.sidecarReceiverFlow()
379             ?.collectLatestWithLifecycle(LocalLifecycleOwner.current) {
380                 onStateChange(it)
381             }
382         switchToRemovableSlotSidecar?.sidecarReceiverFlow()
383             ?.collectLatestWithLifecycle(LocalLifecycleOwner.current) {
384                 onStateChange(it)
385             }
386         enableMultiSimSidecar?.sidecarReceiverFlow()
387             ?.collectLatestWithLifecycle(LocalLifecycleOwner.current) {
388                 onStateChange(it)
389             }
390     }
391 
<lambda>null392     fun SidecarFragment.sidecarReceiverFlow(): Flow<SidecarFragment> = callbackFlow {
393         val broadcastReceiver = SidecarFragment.Listener {
394             Log.d(TAG, "onReceive: $it")
395             trySend(it)
396         }
397         addListener(broadcastReceiver)
398 
399         awaitClose { removeListener(broadcastReceiver) }
400     }.catch { e ->
401         Log.e(TAG, "Error while sidecarReceiverFlow", e)
402     }.conflate()
403 
startSimSwitchingnull404     fun startSimSwitching() {
405         Log.d(TAG, "startSimSwitching:")
406 
407         var targetSubInfo = onboardingService.targetSubInfo
408         if(onboardingService.doesTargetSimActive) {
409             Log.d(TAG, "target subInfo is already active")
410             callbackListener(CallbackType.CALLBACK_SETUP_NAME)
411             return
412         }
413         targetSubInfo?.let {
414             var removedSubInfo = onboardingService.getRemovedSim()
415             if (targetSubInfo.isEmbedded) {
416                 switchToEuiccSubscriptionSidecar!!.run(
417                     targetSubInfo.subscriptionId,
418                     UiccSlotUtil.INVALID_PORT_ID,
419                     removedSubInfo
420                 )
421                 return@let
422             }
423             switchToRemovableSlotSidecar!!.run(
424                 UiccSlotUtil.INVALID_PHYSICAL_SLOT_ID,
425                 removedSubInfo
426             )
427         } ?: run {
428             Log.e(TAG, "no target subInfo in onboardingService")
429             finish()
430         }
431     }
432 
onStateChangenull433     fun onStateChange(fragment: SidecarFragment?) {
434         if (fragment === switchToEuiccSubscriptionSidecar) {
435             handleSwitchToEuiccSubscriptionSidecarStateChange()
436         } else if (fragment === switchToRemovableSlotSidecar) {
437             handleSwitchToRemovableSlotSidecarStateChange()
438         } else if (fragment === enableMultiSimSidecar) {
439             handleEnableMultiSimSidecarStateChange()
440         }
441     }
442 
handleSwitchToEuiccSubscriptionSidecarStateChangenull443     fun handleSwitchToEuiccSubscriptionSidecarStateChange() {
444         when (switchToEuiccSubscriptionSidecar!!.state) {
445             SidecarFragment.State.SUCCESS -> {
446                 Log.i(TAG, "Successfully enable the eSIM profile.")
447                 switchToEuiccSubscriptionSidecar!!.reset()
448                 scope.launch {
449                     checkSimIsReadyAndGoNext()
450                 }
451             }
452 
453             SidecarFragment.State.ERROR -> {
454                 Log.i(TAG, "Failed to enable the eSIM profile.")
455                 switchToEuiccSubscriptionSidecar!!.reset()
456                 showError.value = ErrorType.ERROR_SIM_SWITCHING
457                 callbackListener(CallbackType.CALLBACK_ERROR)
458             }
459         }
460     }
461 
handleSwitchToRemovableSlotSidecarStateChangenull462     fun handleSwitchToRemovableSlotSidecarStateChange() {
463         when (switchToRemovableSlotSidecar!!.state) {
464             SidecarFragment.State.SUCCESS -> {
465                 Log.i(TAG, "Successfully switched to removable slot.")
466                 switchToRemovableSlotSidecar!!.reset()
467                 onboardingService.handleTogglePsimAction()
468                 scope.launch {
469                     checkSimIsReadyAndGoNext()
470                 }
471             }
472 
473             SidecarFragment.State.ERROR -> {
474                 Log.e(TAG, "Failed switching to removable slot.")
475                 switchToRemovableSlotSidecar!!.reset()
476                 showError.value = ErrorType.ERROR_SIM_SWITCHING
477                 callbackListener(CallbackType.CALLBACK_ERROR)
478             }
479         }
480     }
481 
handleEnableMultiSimSidecarStateChangenull482     fun handleEnableMultiSimSidecarStateChange() {
483         when (enableMultiSimSidecar!!.state) {
484             SidecarFragment.State.SUCCESS -> {
485                 enableMultiSimSidecar!!.reset()
486                 Log.i(TAG, "Successfully switched to DSDS without reboot.")
487                 showDsdsProgressDialog.value = false
488                 // refresh data
489                 initServiceData(this, onboardingService.targetSubId, callbackListener)
490                 startSimOnboardingProvider()
491             }
492 
493             SidecarFragment.State.ERROR -> {
494                 enableMultiSimSidecar!!.reset()
495                 showDsdsProgressDialog.value = false
496                 Log.i(TAG, "Failed to switch to DSDS without rebooting.")
497                 showError.value = ErrorType.ERROR_ENABLE_DSDS
498                 callbackListener(CallbackType.CALLBACK_ERROR)
499             }
500         }
501     }
502 
checkSimIsReadyAndGoNextnull503     private suspend fun checkSimIsReadyAndGoNext() {
504         withContext(Dispatchers.Default) {
505             val waitingTimeMillis =
506                 Settings.Global.getLong(
507                     context.contentResolver,
508                     Settings.Global.EUICC_SWITCH_SLOT_TIMEOUT_MILLIS,
509                     UiccSlotUtil.DEFAULT_WAIT_AFTER_SWITCH_TIMEOUT_MILLIS,
510                 )
511             Log.d(TAG, "Start waiting, waitingTime is $waitingTimeMillis")
512             val isTimeout =
513                 withTimeoutOrNull(waitingTimeMillis) {
514                     SubscriptionRepository(context)
515                         .isSubscriptionEnabledFlow(onboardingService.targetSubId)
516                         .firstOrNull { it }
517                 } == null
518             Log.d(
519                 TAG,
520                 if (isTimeout) "Sim is not ready after timeout" else "Sim is ready then go to next",
521             )
522             callbackListener(CallbackType.CALLBACK_SETUP_NAME)
523         }
524     }
525 
526     @Composable
StartingDialogImplnull527     fun StartingDialogImpl(
528         nextAction: () -> Unit,
529         cancelAction: () -> Unit,
530     ) {
531         SettingsAlertDialogWithIcon(
532             onDismissRequest = cancelAction,
533             confirmButton = AlertDialogButton(
534                 text = getString(R.string.sim_onboarding_setup),
535                 onClick = nextAction,
536             ),
537             dismissButton = AlertDialogButton(
538                 text = getString(R.string.sim_onboarding_close),
539                 onClick = cancelAction,
540             ),
541             title = stringResource(R.string.sim_onboarding_dialog_starting_title),
542             icon = {
543                 Icon(
544                     imageVector = Icons.Outlined.SignalCellularAlt,
545                     contentDescription = null,
546                     modifier = Modifier
547                         .size(SettingsDimension.iconLarge),
548                     tint = MaterialTheme.colorScheme.primary,
549                 )
550             },
551             text = {
552                 Text(
553                     stringResource(R.string.sim_onboarding_dialog_starting_msg),
554                     modifier = Modifier.fillMaxWidth(),
555                     textAlign = TextAlign.Center
556                 )
557             })
558 
559     }
560 
setProgressStatenull561     fun setProgressState(state: Int) {
562         val prefs = getSharedPreferences(
563             SubscriptionActionDialogActivity.SIM_ACTION_DIALOG_PREFS,
564             MODE_PRIVATE
565         )
566         prefs.edit().putInt(SubscriptionActionDialogActivity.KEY_PROGRESS_STATE, state).apply()
567         Log.i(TAG, "setProgressState:$state")
568     }
569 
initServiceDatanull570     fun initServiceData(context: Context,targetSubId: Int, callback:(CallbackType)->Unit) {
571         onboardingService.initData(targetSubId, context,callback)
572     }
573 
startSimOnboardingProvidernull574     private fun startSimOnboardingProvider() {
575         val route = getRoute(onboardingService.targetSubId)
576         startSpaActivity(route)
577     }
578 
579     companion object {
580         @JvmStatic
startSimOnboardingActivitynull581         fun startSimOnboardingActivity(
582             context: Context,
583             subId: Int,
584             isNewTask: Boolean = false,
585         ) {
586             if (!SimRepository(context).canEnterMobileNetworkPage()) {
587                 Log.i(TAG, "Unable to start SimOnboardingActivity due to missing permissions")
588                 return
589             }
590             val intent = Intent(context, SimOnboardingActivity::class.java).apply {
591                 putExtra(SUB_ID, subId)
592                 if(isNewTask) {
593                     setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
594                 }
595             }
596             context.startActivityAsUser(intent, UserHandle.CURRENT)
597         }
598 
599         var onboardingService:SimOnboardingService = SimOnboardingService()
600         const val TAG = "SimOnboardingActivity"
601         const val SUB_ID = "sub_id"
602 
603         enum class ErrorType(val value:Int){
604             ERROR_NONE(-1),
605             ERROR_SIM_SWITCHING(1),
606             ERROR_ENABLE_DSDS(2)
607         }
608 
609         enum class CallbackType(val value:Int){
610             CALLBACK_ERROR(-1),
611             CALLBACK_ONBOARDING_COMPLETE(1),
612             CALLBACK_ENABLE_DSDS(2),
613             CALLBACK_SETUP_NAME(3),
614             CALLBACK_SETUP_PRIMARY_SIM(4),
615             CALLBACK_FINISH(5)
616         }
617     }
618 }
619