Merge "Refine CrossSimCalling updating" into main

This commit is contained in:
Chaohui Wang
2024-09-03 02:58:25 +00:00
committed by Android (Google) Code Review
4 changed files with 54 additions and 55 deletions

View File

@@ -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
@@ -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)
}
@@ -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) {

View File

@@ -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
@@ -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
@@ -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)
@@ -61,38 +62,45 @@ class CrossSimCallingViewModel(
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 @@ 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"
}
}

View File

@@ -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. */
@@ -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,
)
}
}

View File

@@ -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 {