Loading src/com/android/settings/network/telephony/ims/ImsMmTelRepository.kt +3 −6 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.telephony.ims.ImsStateCallback 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 Loading @@ -53,11 +54,6 @@ interface ImsMmTelRepository { @AccessNetworkConstants.TransportType transportType: Int, ): Flow<Boolean> suspend fun isSupported( @MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int, @AccessNetworkConstants.TransportType transportType: Int, ): Boolean suspend fun setCrossSimCallingEnabled(enabled: Boolean) } Loading Loading @@ -143,7 +139,8 @@ class ImsMmTelRepositoryImpl( 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) { Loading src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt +51 −24 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.app.settings.SettingsEnums 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 Loading @@ -34,6 +35,7 @@ import kotlinx.coroutines.Dispatchers 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 Loading @@ -43,9 +45,8 @@ import kotlinx.coroutines.flow.onEach 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) Loading @@ -61,38 +62,45 @@ class CrossSimCallingViewModel( subscriptionRepository.activeSubscriptionIdListFlow(), dataSubscriptionRepository.defaultDataSubscriptionIdFlow(), ) { activeSubIds, defaultDataSubId -> activeSubIds to crossSimCallNewEnabled(activeSubIds, defaultDataSubId) updatableSubIdsFlow(activeSubIds) to crossSimCallNewEnabledFlow(activeSubIds, defaultDataSubId) } .flatMapLatest { (updatableSubIdsFlow, crossSimCallNewEnabledFlow) -> combine(updatableSubIdsFlow, crossSimCallNewEnabledFlow) { updatableSubIds, newEnabled -> updatableSubIds to newEnabled } .flatMapLatest { (activeSubIds, newEnabledFlow) -> newEnabledFlow.map { newEnabled -> activeSubIds 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() && private fun isCrossSimImsAvailable(subId: Int) = carrierConfigRepository.getBoolean( subId, CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL) subId, CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL, ) private fun crossSimCallNewEnabled( private fun crossSimCallNewEnabledFlow( activeSubscriptionIdList: List<Int>, defaultDataSubId: Int, ): Flow<Boolean> { Loading @@ -102,8 +110,27 @@ class CrossSimCallingViewModel( .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" } } src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt +0 −9 Original line number Diff line number Diff line Loading @@ -29,9 +29,7 @@ import com.android.settings.network.telephony.ims.ImsMmTelRepository 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. */ Loading Loading @@ -75,11 +73,4 @@ constructor( 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, ) } } tests/spa_unit/src/com/android/settings/network/telephony/wificalling/WifiCallingRepositoryTest.kt +0 −16 Original line number Diff line number Diff line Loading @@ -102,22 +102,6 @@ class WifiCallingRepositoryTest { 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 { Loading Loading
src/com/android/settings/network/telephony/ims/ImsMmTelRepository.kt +3 −6 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.telephony.ims.ImsStateCallback 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 Loading @@ -53,11 +54,6 @@ interface ImsMmTelRepository { @AccessNetworkConstants.TransportType transportType: Int, ): Flow<Boolean> suspend fun isSupported( @MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int, @AccessNetworkConstants.TransportType transportType: Int, ): Boolean suspend fun setCrossSimCallingEnabled(enabled: Boolean) } Loading Loading @@ -143,7 +139,8 @@ class ImsMmTelRepositoryImpl( 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) { Loading
src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt +51 −24 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.app.settings.SettingsEnums 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 Loading @@ -34,6 +35,7 @@ import kotlinx.coroutines.Dispatchers 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 Loading @@ -43,9 +45,8 @@ import kotlinx.coroutines.flow.onEach 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) Loading @@ -61,38 +62,45 @@ class CrossSimCallingViewModel( subscriptionRepository.activeSubscriptionIdListFlow(), dataSubscriptionRepository.defaultDataSubscriptionIdFlow(), ) { activeSubIds, defaultDataSubId -> activeSubIds to crossSimCallNewEnabled(activeSubIds, defaultDataSubId) updatableSubIdsFlow(activeSubIds) to crossSimCallNewEnabledFlow(activeSubIds, defaultDataSubId) } .flatMapLatest { (updatableSubIdsFlow, crossSimCallNewEnabledFlow) -> combine(updatableSubIdsFlow, crossSimCallNewEnabledFlow) { updatableSubIds, newEnabled -> updatableSubIds to newEnabled } .flatMapLatest { (activeSubIds, newEnabledFlow) -> newEnabledFlow.map { newEnabled -> activeSubIds 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() && private fun isCrossSimImsAvailable(subId: Int) = carrierConfigRepository.getBoolean( subId, CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL) subId, CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL, ) private fun crossSimCallNewEnabled( private fun crossSimCallNewEnabledFlow( activeSubscriptionIdList: List<Int>, defaultDataSubId: Int, ): Flow<Boolean> { Loading @@ -102,8 +110,27 @@ class CrossSimCallingViewModel( .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" } }
src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt +0 −9 Original line number Diff line number Diff line Loading @@ -29,9 +29,7 @@ import com.android.settings.network.telephony.ims.ImsMmTelRepository 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. */ Loading Loading @@ -75,11 +73,4 @@ constructor( 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, ) } }
tests/spa_unit/src/com/android/settings/network/telephony/wificalling/WifiCallingRepositoryTest.kt +0 −16 Original line number Diff line number Diff line Loading @@ -102,22 +102,6 @@ class WifiCallingRepositoryTest { 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 { Loading