Check if ECBMode when deactivate SIM card

If in ECBMode, start ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS to show a
dialog instead.

This align with the current airplane mode switch.

Fix: 191943857
Test: adb shell cmd phone emergency-callback-mode
Test: unit test
Change-Id: Icf646cd76990d621121b4367ec0fd02a3880b85c
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt
index 6c5127f..63364f9 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt
+++ b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt
@@ -21,14 +21,15 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settings.R
-import com.android.settings.network.SubscriptionUtil
 import com.android.settings.spa.preference.ComposePreferenceController
 import com.android.settingslib.spa.widget.preference.MainSwitchPreference
 import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import kotlinx.coroutines.launch
 
 class MobileNetworkSwitchController @JvmOverloads constructor(
     context: Context,
@@ -56,12 +57,15 @@
         val changeable by remember {
             subscriptionActivationRepository.isActivationChangeableFlow()
         }.collectAsStateWithLifecycle(initialValue = true)
+        val coroutineScope = rememberCoroutineScope()
         MainSwitchPreference(model = object : SwitchPreferenceModel {
             override val title = stringResource(R.string.mobile_network_use_sim_on)
             override val changeable = { changeable }
             override val checked = { checked }
-            override val onCheckedChange = { newChecked: Boolean ->
-                SubscriptionUtil.startToggleSubscriptionDialogActivity(mContext, subId, newChecked)
+            override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
+                coroutineScope.launch {
+                    subscriptionActivationRepository.setActive(subId, newChecked)
+                }
             }
         })
     }
diff --git a/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt b/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt
index 416dda1..185af0c 100644
--- a/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt
+++ b/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt
@@ -17,9 +17,18 @@
 package com.android.settings.network.telephony
 
 import android.content.Context
+import android.content.Intent
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS
+import android.util.Log
+import com.android.settings.Utils
+import com.android.settings.flags.Flags
 import com.android.settings.network.SatelliteRepository
+import com.android.settings.network.SimOnboardingActivity.Companion.startSimOnboardingActivity
+import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.withContext
 
 class SubscriptionActivationRepository(
     private val context: Context,
@@ -32,4 +41,36 @@
     ) { isInCall, isSatelliteModemEnabled ->
         !isInCall && !isSatelliteModemEnabled
     }
+
+    /**
+     * Starts a dialog activity to handle SIM enabling / disabling.
+     * @param subId The id of subscription need to be enabled or disabled.
+     * @param active Whether the subscription with [subId] should be enabled or disabled.
+     */
+    suspend fun setActive(subId: Int, active: Boolean) {
+        if (!SubscriptionManager.isUsableSubscriptionId(subId)) {
+            Log.i(TAG, "Unable to toggle subscription due to unusable subscription ID.")
+            return
+        }
+        if (!active && isEmergencyCallbackMode(subId)) {
+            val intent = Intent(ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS).apply {
+                setPackage(Utils.PHONE_PACKAGE_NAME)
+            }
+            context.startActivity(intent)
+            return
+        }
+        if (active && Flags.isDualSimOnboardingEnabled()) {
+            startSimOnboardingActivity(context, subId)
+            return
+        }
+        context.startActivity(ToggleSubscriptionDialogActivity.getIntent(context, subId, active))
+    }
+
+    private suspend fun isEmergencyCallbackMode(subId: Int) = withContext(Dispatchers.Default) {
+        context.telephonyManager(subId).emergencyCallbackMode
+    }
+
+    private companion object {
+        private const val TAG = "SubscriptionActivationR"
+    }
 }
diff --git a/src/com/android/settings/spa/network/SimsSection.kt b/src/com/android/settings/spa/network/SimsSection.kt
index 07da034..842656e 100644
--- a/src/com/android/settings/spa/network/SimsSection.kt
+++ b/src/com/android/settings/spa/network/SimsSection.kt
@@ -30,6 +30,7 @@
 import androidx.compose.runtime.State
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -47,6 +48,7 @@
 import com.android.settingslib.spaprivileged.template.preference.RestrictedPreference
 import com.android.settingslib.spaprivileged.template.preference.RestrictedTwoTargetSwitchPreference
 import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.launch
 
 @Composable
 fun SimsSection(subscriptionInfoList: List<SubscriptionInfo>) {
@@ -71,9 +73,11 @@
             emit(SubscriptionUtil.isConvertedPsimSubscription(subInfo))
         }
     }.collectAsStateWithLifecycle(initialValue = false)
+    val subscriptionActivationRepository = remember { SubscriptionActivationRepository(context) }
     val isActivationChangeable by remember {
-        SubscriptionActivationRepository(context).isActivationChangeableFlow()
+        subscriptionActivationRepository.isActivationChangeableFlow()
     }.collectAsStateWithLifecycle(initialValue = false)
+    val coroutineScope = rememberCoroutineScope()
     RestrictedTwoTargetSwitchPreference(
         model = object : SwitchPreferenceModel {
             override val title = subInfo.displayName.toString()
@@ -87,12 +91,10 @@
             override val icon = @Composable { SimIcon(subInfo.isEmbedded) }
             override val changeable = { isActivationChangeable && !isConvertedPsim }
             override val checked = { checked.value }
-            override val onCheckedChange = { newChecked: Boolean ->
-                SubscriptionUtil.startToggleSubscriptionDialogActivity(
-                    context,
-                    subInfo.subscriptionId,
-                    newChecked,
-                )
+            override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
+                coroutineScope.launch {
+                    subscriptionActivationRepository.setActive(subInfo.subscriptionId, newChecked)
+                }
             }
         },
         restrictions = Restrictions(keys = listOf(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)),
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt
index dd9c505..427ab7b 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt
@@ -17,6 +17,9 @@
 package com.android.settings.network.telephony
 
 import android.content.Context
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settings.network.SatelliteRepository
@@ -26,14 +29,29 @@
 import kotlinx.coroutines.runBlocking
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argThat
+import org.mockito.kotlin.doNothing
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.spy
 import org.mockito.kotlin.stub
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
 
 @RunWith(AndroidJUnit4::class)
 class SubscriptionActivationRepositoryTest {
 
-    private val context: Context = ApplicationProvider.getApplicationContext()
+    private val mockTelephonyManager = mock<TelephonyManager> {
+        on { createForSubscriptionId(SUB_ID) } doReturn mock
+    }
+
+    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+        doNothing().whenever(mock).startActivity(any())
+        on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
+    }
+
     private val mockCallStateRepository = mock<CallStateRepository>()
     private val mockSatelliteRepository = mock<SatelliteRepository>()
 
@@ -81,4 +99,39 @@
 
         assertThat(changeable).isFalse()
     }
+
+    @Test
+    fun setActive_defaultSubId_doNothing() = runBlocking {
+        repository.setActive(subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, active = true)
+
+        verify(context, never()).startActivity(any())
+    }
+
+    @Test
+    fun setActive_turnOffAndIsEmergencyCallbackMode() = runBlocking {
+        mockTelephonyManager.stub {
+            on { emergencyCallbackMode } doReturn true
+        }
+
+        repository.setActive(subId = SUB_ID, active = false)
+
+        verify(context).startActivity(argThat { action == ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS })
+    }
+
+    @Test
+    fun setActive_turnOffAndNotEmergencyCallbackMode() = runBlocking {
+        mockTelephonyManager.stub {
+            on { emergencyCallbackMode } doReturn false
+        }
+
+        repository.setActive(subId = SUB_ID, active = false)
+
+        verify(context).startActivity(argThat {
+            component?.className == ToggleSubscriptionDialogActivity::class.qualifiedName
+        })
+    }
+
+    private companion object {
+        const val SUB_ID = 1
+    }
 }