Merge "Refine CrossSimCalling updating" into main
This commit is contained in:
@@ -27,6 +27,7 @@ import android.telephony.ims.ImsStateCallback
|
|||||||
import android.telephony.ims.RegistrationManager
|
import android.telephony.ims.RegistrationManager
|
||||||
import android.telephony.ims.feature.MmTelFeature
|
import android.telephony.ims.feature.MmTelFeature
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.asExecutor
|
import kotlinx.coroutines.asExecutor
|
||||||
@@ -53,11 +54,6 @@ interface ImsMmTelRepository {
|
|||||||
@AccessNetworkConstants.TransportType transportType: Int,
|
@AccessNetworkConstants.TransportType transportType: Int,
|
||||||
): Flow<Boolean>
|
): Flow<Boolean>
|
||||||
|
|
||||||
suspend fun isSupported(
|
|
||||||
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
|
||||||
@AccessNetworkConstants.TransportType transportType: Int,
|
|
||||||
): Boolean
|
|
||||||
|
|
||||||
suspend fun setCrossSimCallingEnabled(enabled: Boolean)
|
suspend fun setCrossSimCallingEnabled(enabled: Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +139,8 @@ class ImsMmTelRepositoryImpl(
|
|||||||
override fun isSupportedFlow(capability: Int, transportType: Int): Flow<Boolean> =
|
override fun isSupportedFlow(capability: Int, transportType: Int): Flow<Boolean> =
|
||||||
imsReadyFlow().map { imsReady -> imsReady && isSupported(capability, transportType) }
|
imsReadyFlow().map { imsReady -> imsReady && isSupported(capability, transportType) }
|
||||||
|
|
||||||
override suspend fun isSupported(
|
@VisibleForTesting
|
||||||
|
suspend fun isSupported(
|
||||||
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
||||||
@AccessNetworkConstants.TransportType transportType: Int,
|
@AccessNetworkConstants.TransportType transportType: Int,
|
||||||
): Boolean = withContext(Dispatchers.Default) {
|
): Boolean = withContext(Dispatchers.Default) {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import android.app.settings.SettingsEnums
|
|||||||
import android.telephony.CarrierConfigManager
|
import android.telephony.CarrierConfigManager
|
||||||
import android.telephony.SubscriptionManager
|
import android.telephony.SubscriptionManager
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
|
import android.util.Log
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
@@ -34,6 +35,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.conflate
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
@@ -43,9 +45,8 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class CrossSimCallingViewModel(
|
class CrossSimCallingViewModel(private val application: Application) :
|
||||||
private val application: Application,
|
AndroidViewModel(application) {
|
||||||
) : AndroidViewModel(application) {
|
|
||||||
|
|
||||||
private val subscriptionRepository = SubscriptionRepository(application)
|
private val subscriptionRepository = SubscriptionRepository(application)
|
||||||
private val dataSubscriptionRepository = DataSubscriptionRepository(application)
|
private val dataSubscriptionRepository = DataSubscriptionRepository(application)
|
||||||
@@ -61,38 +62,45 @@ class CrossSimCallingViewModel(
|
|||||||
subscriptionRepository.activeSubscriptionIdListFlow(),
|
subscriptionRepository.activeSubscriptionIdListFlow(),
|
||||||
dataSubscriptionRepository.defaultDataSubscriptionIdFlow(),
|
dataSubscriptionRepository.defaultDataSubscriptionIdFlow(),
|
||||||
) { activeSubIds, defaultDataSubId ->
|
) { activeSubIds, defaultDataSubId ->
|
||||||
activeSubIds to crossSimCallNewEnabled(activeSubIds, defaultDataSubId)
|
updatableSubIdsFlow(activeSubIds) to
|
||||||
|
crossSimCallNewEnabledFlow(activeSubIds, defaultDataSubId)
|
||||||
}
|
}
|
||||||
.flatMapLatest { (activeSubIds, newEnabledFlow) ->
|
.flatMapLatest { (updatableSubIdsFlow, crossSimCallNewEnabledFlow) ->
|
||||||
newEnabledFlow.map { newEnabled -> activeSubIds to newEnabled }
|
combine(updatableSubIdsFlow, crossSimCallNewEnabledFlow) {
|
||||||
|
updatableSubIds,
|
||||||
|
newEnabled ->
|
||||||
|
updatableSubIds to newEnabled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.onEach { (activeSubIds, newEnabled) ->
|
.conflate()
|
||||||
updateCrossSimCalling(activeSubIds, newEnabled)
|
.onEach { (updatableSubIds, newEnabled) ->
|
||||||
|
Log.d(TAG, "updatableSubIds: $updatableSubIds newEnabled: $newEnabled")
|
||||||
|
updateCrossSimCalling(updatableSubIds, newEnabled)
|
||||||
}
|
}
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun updateCrossSimCalling(activeSubIds: List<Int>, newEnabled: Boolean) {
|
private fun updatableSubIdsFlow(activeSubIds: List<Int>): Flow<List<Int>> {
|
||||||
metricsFeatureProvider.action(
|
val updatableSubIdFlows =
|
||||||
application,
|
activeSubIds.map { subId ->
|
||||||
SettingsEnums.ACTION_UPDATE_CROSS_SIM_CALLING_ON_AUTO_DATA_SWITCH_EVENT,
|
WifiCallingRepository(application, subId).wifiCallingReadyFlow().map { isReady ->
|
||||||
newEnabled,
|
subId.takeIf { isReady && isCrossSimImsAvailable(subId) }
|
||||||
)
|
}
|
||||||
activeSubIds
|
|
||||||
.filter { subId -> crossSimAvailable(subId) }
|
|
||||||
.forEach { subId ->
|
|
||||||
ImsMmTelRepositoryImpl(application, subId).setCrossSimCallingEnabled(newEnabled)
|
|
||||||
}
|
}
|
||||||
|
return combine(updatableSubIdFlows) { subIds -> subIds.filterNotNull() }
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.conflate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun crossSimAvailable(subId: Int): Boolean =
|
private fun isCrossSimImsAvailable(subId: Int) =
|
||||||
WifiCallingRepository(application, subId).isWifiCallingSupported() &&
|
carrierConfigRepository.getBoolean(
|
||||||
carrierConfigRepository.getBoolean(
|
subId,
|
||||||
subId, CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL)
|
CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL,
|
||||||
|
)
|
||||||
|
|
||||||
private fun crossSimCallNewEnabled(
|
private fun crossSimCallNewEnabledFlow(
|
||||||
activeSubscriptionIdList: List<Int>,
|
activeSubscriptionIdList: List<Int>,
|
||||||
defaultDataSubId: Int,
|
defaultDataSubId: Int,
|
||||||
): Flow<Boolean> {
|
): Flow<Boolean> {
|
||||||
@@ -102,8 +110,27 @@ class CrossSimCallingViewModel(
|
|||||||
.filter { subId -> subId != defaultDataSubId }
|
.filter { subId -> subId != defaultDataSubId }
|
||||||
.map { subId ->
|
.map { subId ->
|
||||||
mobileDataRepository.isMobileDataPolicyEnabledFlow(
|
mobileDataRepository.isMobileDataPolicyEnabledFlow(
|
||||||
subId, TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
|
subId,
|
||||||
|
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return combine(isMobileDataPolicyEnabledFlows) { true in it }
|
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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.ims.ImsMmTelRepositoryImpl
|
||||||
import com.android.settings.network.telephony.telephonyManager
|
import com.android.settings.network.telephony.telephonyManager
|
||||||
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
interface IWifiCallingRepository {
|
interface IWifiCallingRepository {
|
||||||
/** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
|
/** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
|
||||||
@@ -75,11 +73,4 @@ constructor(
|
|||||||
tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
|
tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
|
||||||
transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
|
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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,22 +102,6 @@ class WifiCallingRepositoryTest {
|
|||||||
assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED)
|
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) {
|
private fun mockUseWfcHomeModeForRoaming(config: Boolean) {
|
||||||
mockCarrierConfigManager.stub {
|
mockCarrierConfigManager.stub {
|
||||||
on {
|
on {
|
||||||
|
|||||||
Reference in New Issue
Block a user