Refine CrossSimCalling updating

Currently, this setting depends on whether wifi calling is supported,
since wifi calling could takes some time to provision after sim is
turned on, this state could be wrong when set cross sim calling.

Use wifiCallingReadyFlow() to retrieve the latest state, and update
setting when state changes.

Fix: 352736998
Fix: 348529996
Flag: EXEMPT bug fix
Test: manual - by turn on / off sim
Change-Id: Id4b099e0c5d7cf47b007f37e6f278d1c46e58659
diff --git a/src/com/android/settings/network/telephony/ims/ImsMmTelRepository.kt b/src/com/android/settings/network/telephony/ims/ImsMmTelRepository.kt
index c5d1200..e891204 100644
--- a/src/com/android/settings/network/telephony/ims/ImsMmTelRepository.kt
+++ b/src/com/android/settings/network/telephony/ims/ImsMmTelRepository.kt
@@ -27,6 +27,7 @@
 import android.telephony.ims.RegistrationManager
 import android.telephony.ims.feature.MmTelFeature
 import android.util.Log
+import androidx.annotation.VisibleForTesting
 import kotlin.coroutines.resume
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.asExecutor
@@ -53,11 +54,6 @@
         @AccessNetworkConstants.TransportType transportType: Int,
     ): Flow<Boolean>
 
-    suspend fun isSupported(
-        @MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
-        @AccessNetworkConstants.TransportType transportType: Int,
-    ): Boolean
-
     suspend fun setCrossSimCallingEnabled(enabled: Boolean)
 }
 
@@ -143,7 +139,8 @@
     override fun isSupportedFlow(capability: Int, transportType: Int): Flow<Boolean> =
         imsReadyFlow().map { imsReady -> imsReady && isSupported(capability, transportType) }
 
-    override suspend fun isSupported(
+    @VisibleForTesting
+    suspend fun isSupported(
         @MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
         @AccessNetworkConstants.TransportType transportType: Int,
     ): Boolean = withContext(Dispatchers.Default) {
diff --git a/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt b/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt
index dda147b..cab27ca 100644
--- a/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt
+++ b/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt
@@ -21,6 +21,7 @@
 import android.telephony.CarrierConfigManager
 import android.telephony.SubscriptionManager
 import android.telephony.TelephonyManager
+import android.util.Log
 import androidx.lifecycle.AndroidViewModel
 import androidx.lifecycle.viewModelScope
 import com.android.settings.R
@@ -34,6 +35,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.conflate
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
@@ -43,9 +45,8 @@
 import kotlinx.coroutines.plus
 
 @OptIn(ExperimentalCoroutinesApi::class)
-class CrossSimCallingViewModel(
-    private val application: Application,
-) : AndroidViewModel(application) {
+class CrossSimCallingViewModel(private val application: Application) :
+    AndroidViewModel(application) {
 
     private val subscriptionRepository = SubscriptionRepository(application)
     private val dataSubscriptionRepository = DataSubscriptionRepository(application)
@@ -61,38 +62,45 @@
                     subscriptionRepository.activeSubscriptionIdListFlow(),
                     dataSubscriptionRepository.defaultDataSubscriptionIdFlow(),
                 ) { activeSubIds, defaultDataSubId ->
-                    activeSubIds to crossSimCallNewEnabled(activeSubIds, defaultDataSubId)
+                    updatableSubIdsFlow(activeSubIds) to
+                        crossSimCallNewEnabledFlow(activeSubIds, defaultDataSubId)
                 }
-                .flatMapLatest { (activeSubIds, newEnabledFlow) ->
-                    newEnabledFlow.map { newEnabled -> activeSubIds to newEnabled }
+                .flatMapLatest { (updatableSubIdsFlow, crossSimCallNewEnabledFlow) ->
+                    combine(updatableSubIdsFlow, crossSimCallNewEnabledFlow) {
+                        updatableSubIds,
+                        newEnabled ->
+                        updatableSubIds to newEnabled
+                    }
                 }
                 .distinctUntilChanged()
-                .onEach { (activeSubIds, newEnabled) ->
-                    updateCrossSimCalling(activeSubIds, newEnabled)
+                .conflate()
+                .onEach { (updatableSubIds, newEnabled) ->
+                    Log.d(TAG, "updatableSubIds: $updatableSubIds newEnabled: $newEnabled")
+                    updateCrossSimCalling(updatableSubIds, newEnabled)
                 }
                 .launchIn(scope)
         }
     }
 
-    private suspend fun updateCrossSimCalling(activeSubIds: List<Int>, newEnabled: Boolean) {
-        metricsFeatureProvider.action(
-            application,
-            SettingsEnums.ACTION_UPDATE_CROSS_SIM_CALLING_ON_AUTO_DATA_SWITCH_EVENT,
-            newEnabled,
-        )
-        activeSubIds
-            .filter { subId -> crossSimAvailable(subId) }
-            .forEach { subId ->
-                ImsMmTelRepositoryImpl(application, subId).setCrossSimCallingEnabled(newEnabled)
+    private fun updatableSubIdsFlow(activeSubIds: List<Int>): Flow<List<Int>> {
+        val updatableSubIdFlows =
+            activeSubIds.map { subId ->
+                WifiCallingRepository(application, subId).wifiCallingReadyFlow().map { isReady ->
+                    subId.takeIf { isReady && isCrossSimImsAvailable(subId) }
+                }
             }
+        return combine(updatableSubIdFlows) { subIds -> subIds.filterNotNull() }
+            .distinctUntilChanged()
+            .conflate()
     }
 
-    private suspend fun crossSimAvailable(subId: Int): Boolean =
-        WifiCallingRepository(application, subId).isWifiCallingSupported() &&
-            carrierConfigRepository.getBoolean(
-                subId, CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL)
+    private fun isCrossSimImsAvailable(subId: Int) =
+        carrierConfigRepository.getBoolean(
+            subId,
+            CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL,
+        )
 
-    private fun crossSimCallNewEnabled(
+    private fun crossSimCallNewEnabledFlow(
         activeSubscriptionIdList: List<Int>,
         defaultDataSubId: Int,
     ): Flow<Boolean> {
@@ -102,8 +110,27 @@
                 .filter { subId -> subId != defaultDataSubId }
                 .map { subId ->
                     mobileDataRepository.isMobileDataPolicyEnabledFlow(
-                        subId, TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
+                        subId,
+                        TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
+                    )
                 }
         return combine(isMobileDataPolicyEnabledFlows) { true in it }
+            .distinctUntilChanged()
+            .conflate()
+    }
+
+    private suspend fun updateCrossSimCalling(subIds: List<Int>, newEnabled: Boolean) {
+        metricsFeatureProvider.action(
+            application,
+            SettingsEnums.ACTION_UPDATE_CROSS_SIM_CALLING_ON_AUTO_DATA_SWITCH_EVENT,
+            newEnabled,
+        )
+        for (subId in subIds) {
+            ImsMmTelRepositoryImpl(application, subId).setCrossSimCallingEnabled(newEnabled)
+        }
+    }
+
+    companion object {
+        private const val TAG = "CrossSimCallingVM"
     }
 }
diff --git a/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt b/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt
index 6af0559..a6a47fa 100644
--- a/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt
+++ b/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt
@@ -29,9 +29,7 @@
 import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
 import com.android.settings.network.telephony.telephonyManager
 import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
-import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.withContext
 
 interface IWifiCallingRepository {
     /** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
@@ -75,11 +73,4 @@
             tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
             transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
         )
-
-    suspend fun isWifiCallingSupported(): Boolean = withContext(Dispatchers.Default) {
-        imsMmTelRepository.isSupported(
-            capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-            transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
-        )
-    }
 }
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/wificalling/WifiCallingRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/wificalling/WifiCallingRepositoryTest.kt
index f0a23eb..9b71465 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/wificalling/WifiCallingRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/wificalling/WifiCallingRepositoryTest.kt
@@ -102,22 +102,6 @@
         assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED)
     }
 
-    @Test
-    fun isWifiCallingSupported() = runBlocking {
-        mockImsMmTelRepository.stub {
-            onBlocking {
-                isSupported(
-                    capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                    transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
-                )
-            } doReturn true
-        }
-
-        val isSupported = repository.isWifiCallingSupported()
-
-        assertThat(isSupported).isTrue()
-    }
-
     private fun mockUseWfcHomeModeForRoaming(config: Boolean) {
         mockCarrierConfigManager.stub {
             on {