1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.network.telephony.wificalling 18 19 import android.app.Application 20 import android.app.settings.SettingsEnums 21 import android.telephony.CarrierConfigManager 22 import android.telephony.SubscriptionManager 23 import android.telephony.TelephonyManager 24 import androidx.lifecycle.AndroidViewModel 25 import androidx.lifecycle.viewModelScope 26 import com.android.settings.R 27 import com.android.settings.network.mobileDataEnabledFlow 28 import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl 29 import com.android.settings.network.telephony.requireSubscriptionManager 30 import com.android.settings.network.telephony.safeGetConfig 31 import com.android.settings.network.telephony.subscriptionsChangedFlow 32 import com.android.settings.network.telephony.telephonyManager 33 import com.android.settings.overlay.FeatureFactory.Companion.featureFactory 34 import kotlinx.coroutines.Dispatchers 35 import kotlinx.coroutines.ExperimentalCoroutinesApi 36 import kotlinx.coroutines.channels.Channel 37 import kotlinx.coroutines.flow.distinctUntilChanged 38 import kotlinx.coroutines.flow.flatMapLatest 39 import kotlinx.coroutines.flow.launchIn 40 import kotlinx.coroutines.flow.map 41 import kotlinx.coroutines.flow.merge 42 import kotlinx.coroutines.flow.onEach 43 import kotlinx.coroutines.flow.receiveAsFlow 44 import kotlinx.coroutines.plus 45 46 @OptIn(ExperimentalCoroutinesApi::class) 47 class CrossSimCallingViewModel( 48 private val application: Application, 49 ) : AndroidViewModel(application) { 50 51 private val subscriptionManager = application.requireSubscriptionManager() 52 private val carrierConfigManager = 53 application.getSystemService(CarrierConfigManager::class.java)!! 54 private val scope = viewModelScope + Dispatchers.Default 55 private val metricsFeatureProvider = featureFactory.metricsFeatureProvider 56 private val updateChannel = Channel<Unit>() 57 58 init { 59 val resources = application.resources 60 if (resources.getBoolean(R.bool.config_auto_data_switch_enables_cross_sim_calling)) { 61 application.subscriptionsChangedFlow() 62 .flatMapLatest { 63 val activeSubIds = subscriptionManager.activeSubscriptionIdList.toList() 64 merge( 65 activeSubIds.anyMobileDataEnableChangedFlow(), 66 updateChannel.receiveAsFlow(), 67 ).map { 68 activeSubIds to crossSimCallNewEnabled(activeSubIds) 69 } 70 } 71 .distinctUntilChanged() 72 .onEach { (activeSubIds, newEnabled) -> 73 updateCrossSimCalling(activeSubIds, newEnabled) 74 } 75 .launchIn(scope) 76 } 77 } 78 79 fun updateCrossSimCalling() { 80 updateChannel.trySend(Unit) 81 } 82 83 private fun List<Int>.anyMobileDataEnableChangedFlow() = map { subId -> 84 application.mobileDataEnabledFlow(subId = subId, sendInitialValue = false) 85 }.merge() 86 87 private suspend fun updateCrossSimCalling(activeSubIds: List<Int>, newEnabled: Boolean) { 88 metricsFeatureProvider.action( 89 application, 90 SettingsEnums.ACTION_UPDATE_CROSS_SIM_CALLING_ON_AUTO_DATA_SWITCH_EVENT, 91 newEnabled, 92 ) 93 activeSubIds.filter { crossSimAvailable(it) }.forEach { subId -> 94 ImsMmTelRepositoryImpl(application, subId) 95 .setCrossSimCallingEnabled(newEnabled) 96 } 97 } 98 99 private suspend fun crossSimAvailable(subId: Int): Boolean = 100 WifiCallingRepository(application, subId).isWifiCallingSupported() && 101 crossSimImsAvailable(subId) 102 103 private fun crossSimImsAvailable(subId: Int): Boolean = 104 carrierConfigManager.safeGetConfig( 105 keys = listOf(CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL), 106 subId = subId, 107 ).getBoolean(CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL, false) 108 109 private fun crossSimCallNewEnabled(activeSubscriptionIdList: List<Int>): Boolean { 110 val defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId() 111 return SubscriptionManager.isValidSubscriptionId(defaultDataSubId) && 112 activeSubscriptionIdList.any { subId -> 113 subId != defaultDataSubId && 114 application.telephonyManager(subId).isMobileDataPolicyEnabled( 115 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH 116 ) 117 } 118 } 119 } 120