Always set cross sim calling

By CrossSimCallingViewModel, in SIMs and per SIM settings page.
To ensure the status is always right, including the case after the
onboarding set up finished.

Fix: 347882381
Fix: 348529996
Flag: EXEMPT bug fix
Test: manual - turn on / off "Automatic data switching" on SIMs
Test: manual - turn off "Automatic data switching" during onboarding
Change-Id: Icc2eacb67850fa7b3aa0fe310cd09a0e0147912b
This commit is contained in:
Chaohui Wang
2024-07-16 17:38:17 +08:00
parent d133ec93ab
commit fb0583404f
6 changed files with 47 additions and 59 deletions

View File

@@ -38,7 +38,6 @@ import com.android.settings.datausage.DataUsageUtils;
import com.android.settings.flags.Flags;
import com.android.settings.network.MobileDataContentObserver;
import com.android.settings.network.SubscriptionsChangeListener;
import com.android.settings.network.telephony.wificalling.CrossSimCallingViewModel;
/**
* Controls whether switch mobile data to the non-default SIM if the non-default SIM has better
@@ -63,8 +62,6 @@ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenc
@Nullable
private MobileDataContentObserver mMobileDataContentObserver;
@Nullable
private CrossSimCallingViewModel mCrossSimCallingViewModel;
@Nullable
private PreferenceScreen mScreen;
public AutoDataSwitchPreferenceController(
@@ -72,10 +69,9 @@ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenc
super(context, preferenceKey);
}
void init(int subId, @Nullable CrossSimCallingViewModel crossSimCallingViewModel) {
void init(int subId) {
this.mSubId = subId;
mManager = mContext.getSystemService(TelephonyManager.class).createForSubscriptionId(subId);
mCrossSimCallingViewModel = crossSimCallingViewModel;
}
@OnLifecycleEvent(ON_RESUME)
@@ -122,9 +118,6 @@ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenc
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
isChecked);
}
if (mCrossSimCallingViewModel != null) {
mCrossSimCallingViewModel.updateCrossSimCalling();
}
return true;
}

View File

@@ -33,6 +33,7 @@ import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
class DataSubscriptionRepository(
@@ -53,6 +54,7 @@ class DataSubscriptionRepository(
.onStart { emit(SubscriptionManager.getDefaultDataSubscriptionId()) }
.distinctUntilChanged()
.conflate()
.onEach { Log.d(TAG, "defaultDataSubscriptionIdFlow: $it") }
.flowOn(Dispatchers.Default)
fun activeDataSubscriptionIdFlow(): Flow<Int> =

View File

@@ -247,9 +247,10 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme
use(CarrierSettingsVersionPreferenceController.class).init(mSubId);
use(BillingCyclePreferenceController.class).init(mSubId);
use(MmsMessagePreferenceController.class).init(mSubId);
final var crossSimCallingViewModel =
// CrossSimCallingViewModel is responsible for maintaining the correct cross sim calling
// settings (backup calling).
new ViewModelProvider(this).get(CrossSimCallingViewModel.class);
use(AutoDataSwitchPreferenceController.class).init(mSubId, crossSimCallingViewModel);
use(AutoDataSwitchPreferenceController.class).init(mSubId);
use(DisabledSubscriptionController.class).init(mSubId);
use(DeleteSimProfilePreferenceController.class).init(mSubId);
use(DisableSimFooterPreferenceController.class).init(mSubId);

View File

@@ -24,22 +24,22 @@ import android.telephony.TelephonyManager
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.android.settings.R
import com.android.settings.network.telephony.CarrierConfigRepository
import com.android.settings.network.telephony.DataSubscriptionRepository
import com.android.settings.network.telephony.MobileDataRepository
import com.android.settings.network.telephony.SubscriptionRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
import com.android.settings.network.telephony.safeGetConfig
import com.android.settings.network.telephony.telephonyManager
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.plus
@OptIn(ExperimentalCoroutinesApi::class)
@@ -48,24 +48,23 @@ class CrossSimCallingViewModel(
) : AndroidViewModel(application) {
private val subscriptionRepository = SubscriptionRepository(application)
private val carrierConfigManager =
application.getSystemService(CarrierConfigManager::class.java)!!
private val dataSubscriptionRepository = DataSubscriptionRepository(application)
private val mobileDataRepository = MobileDataRepository(application)
private val carrierConfigRepository = CarrierConfigRepository(application)
private val scope = viewModelScope + Dispatchers.Default
private val metricsFeatureProvider = featureFactory.metricsFeatureProvider
private val updateChannel = Channel<Unit>()
private val mobileDataRepository = MobileDataRepository(application)
init {
val resources = application.resources
if (resources.getBoolean(R.bool.config_auto_data_switch_enables_cross_sim_calling)) {
subscriptionRepository.activeSubscriptionIdListFlow()
.flatMapLatest { activeSubIds ->
merge(
activeSubIds.anyMobileDataEnableChangedFlow(),
updateChannel.receiveAsFlow(),
).map {
activeSubIds to crossSimCallNewEnabled(activeSubIds)
combine(
subscriptionRepository.activeSubscriptionIdListFlow(),
dataSubscriptionRepository.defaultDataSubscriptionIdFlow(),
) { activeSubIds, defaultDataSubId ->
activeSubIds to crossSimCallNewEnabled(activeSubIds, defaultDataSubId)
}
.flatMapLatest { (activeSubIds, newEnabledFlow) ->
newEnabledFlow.map { newEnabled -> activeSubIds to newEnabled }
}
.distinctUntilChanged()
.onEach { (activeSubIds, newEnabled) ->
@@ -75,44 +74,36 @@ class CrossSimCallingViewModel(
}
}
fun updateCrossSimCalling() {
updateChannel.trySend(Unit)
}
private fun List<Int>.anyMobileDataEnableChangedFlow() = map { subId ->
mobileDataRepository.mobileDataEnabledChangedFlow(subId = subId, sendInitialValue = false)
}.merge()
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 { crossSimAvailable(it) }.forEach { subId ->
ImsMmTelRepositoryImpl(application, subId)
.setCrossSimCallingEnabled(newEnabled)
activeSubIds
.filter { subId -> crossSimAvailable(subId) }
.forEach { subId ->
ImsMmTelRepositoryImpl(application, subId).setCrossSimCallingEnabled(newEnabled)
}
}
private suspend fun crossSimAvailable(subId: Int): Boolean =
WifiCallingRepository(application, subId).isWifiCallingSupported() &&
crossSimImsAvailable(subId)
carrierConfigRepository.getBoolean(
subId, CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL)
private fun crossSimImsAvailable(subId: Int): Boolean =
carrierConfigManager.safeGetConfig(
keys = listOf(CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL),
subId = subId,
).getBoolean(CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL, false)
private fun crossSimCallNewEnabled(activeSubscriptionIdList: List<Int>): Boolean {
val defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId()
return SubscriptionManager.isValidSubscriptionId(defaultDataSubId) &&
activeSubscriptionIdList.any { subId ->
subId != defaultDataSubId &&
application.telephonyManager(subId).isMobileDataPolicyEnabled(
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
)
private fun crossSimCallNewEnabled(
activeSubscriptionIdList: List<Int>,
defaultDataSubId: Int,
): Flow<Boolean> {
if (!SubscriptionManager.isValidSubscriptionId(defaultDataSubId)) return flowOf(false)
val isMobileDataPolicyEnabledFlows =
activeSubscriptionIdList
.filter { subId -> subId != defaultDataSubId }
.map { subId ->
mobileDataRepository.isMobileDataPolicyEnabledFlow(
subId, TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
}
return combine(isMobileDataPolicyEnabledFlows) { true in it }
}
}

View File

@@ -34,7 +34,9 @@ fun AutomaticDataSwitchingPreference(
) {
val autoDataSummary = stringResource(id = R.string.primary_sim_automatic_data_msg)
val coroutineScope = rememberCoroutineScope()
val crossSimCallingViewModel = viewModel<CrossSimCallingViewModel>() // handles backup calling
// CrossSimCallingViewModel is responsible for maintaining the correct cross sim calling
// settings (backup calling).
viewModel<CrossSimCallingViewModel>()
SwitchPreference(
object : SwitchPreferenceModel {
override val title = stringResource(id = R.string.primary_sim_automatic_data_title)
@@ -43,7 +45,6 @@ fun AutomaticDataSwitchingPreference(
override val onCheckedChange: (Boolean) -> Unit = { newEnabled ->
coroutineScope.launch(Dispatchers.Default) {
setAutoDataEnabled(newEnabled)
crossSimCallingViewModel.updateCrossSimCalling()
}
}
}

View File

@@ -85,7 +85,7 @@ public class AutoDataSwitchPreferenceControllerTest {
return true;
}
};
mController.init(SUB_ID_1, null);
mController.init(SUB_ID_1);
}
@Test