Merge "Refine CrossSimCalling updating" into main
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 {