Refactor AutomaticDataSwitchingPreference
Split into AutomaticDataSwitchingPreference.kt, and use
isMobileDataPolicyEnabledFlow.
Bug: 329061940
Test: manual - Set Automatic data switching
Test: unit test
Change-Id: I878ed70328307c0a5dba6dfb461ff5a85efbcf88
diff --git a/src/com/android/settings/network/SimOnboardingService.kt b/src/com/android/settings/network/SimOnboardingService.kt
index 2ec1ad3..f99a2b9 100644
--- a/src/com/android/settings/network/SimOnboardingService.kt
+++ b/src/com/android/settings/network/SimOnboardingService.kt
@@ -24,6 +24,7 @@
import android.telephony.UiccSlotInfo
import android.util.Log
import com.android.settings.network.SimOnboardingActivity.Companion.CallbackType
+import com.android.settings.network.telephony.TelephonyRepository
import com.android.settings.sim.SimActivationNotifier
import com.android.settings.spa.network.setAutomaticData
import com.android.settings.spa.network.setDefaultData
@@ -31,6 +32,7 @@
import com.android.settings.spa.network.setDefaultVoice
import com.android.settingslib.utils.ThreadUtils
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withContext
class SimOnboardingService {
@@ -46,7 +48,7 @@
var targetPrimarySimCalls: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
var targetPrimarySimTexts: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
var targetPrimarySimMobileData: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
- var targetPrimarySimAutoDataSwitch: Boolean = false
+ val targetPrimarySimAutoDataSwitch = MutableStateFlow(false)
var targetNonDds: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
get() {
if(targetPrimarySimMobileData == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
@@ -349,19 +351,10 @@
null,
targetPrimarySimMobileData
)
-
- var nonDds = targetNonDds
- Log.d(
- TAG,
- "setAutomaticData: targetNonDds: $nonDds," +
- " targetPrimarySimAutoDataSwitch: $targetPrimarySimAutoDataSwitch"
+ TelephonyRepository(context).setAutomaticData(
+ targetNonDds,
+ targetPrimarySimAutoDataSwitch.value
)
- if (nonDds != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- val telephonyManagerForNonDds: TelephonyManager? =
- context.getSystemService(TelephonyManager::class.java)
- ?.createForSubscriptionId(nonDds)
- setAutomaticData(telephonyManagerForNonDds, targetPrimarySimAutoDataSwitch)
- }
}
// no next action, send finish
callback(CallbackType.CALLBACK_FINISH)
diff --git a/src/com/android/settings/network/telephony/TelephonyRepository.kt b/src/com/android/settings/network/telephony/TelephonyRepository.kt
index 678aaac..18af621 100644
--- a/src/com/android/settings/network/telephony/TelephonyRepository.kt
+++ b/src/com/android/settings/network/telephony/TelephonyRepository.kt
@@ -17,8 +17,10 @@
package com.android.settings.network.telephony
import android.content.Context
+import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
+import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.ProducerScope
@@ -26,15 +28,51 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+
+class TelephonyRepository(
+ private val context: Context,
+ private val subscriptionsChangedFlow: Flow<Unit> = context.subscriptionsChangedFlow(),
+) {
+ fun isMobileDataPolicyEnabledFlow(
+ subId: Int,
+ @TelephonyManager.MobileDataPolicy policy: Int,
+ ): Flow<Boolean> {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
+
+ val telephonyManager = context.telephonyManager(subId)
+
+ return subscriptionsChangedFlow.map {
+ telephonyManager.isMobileDataPolicyEnabled(policy)
+ .also { Log.d(TAG, "[$subId] isMobileDataPolicyEnabled($policy): $it") }
+ }.conflate().flowOn(Dispatchers.Default)
+ }
+
+ fun setMobileDataPolicyEnabled(
+ subId: Int,
+ @TelephonyManager.MobileDataPolicy policy: Int,
+ enabled: Boolean,
+ ) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return
+
+ val telephonyManager = context.telephonyManager(subId)
+ Log.d(TAG, "[$subId] setMobileDataPolicyEnabled($policy): $enabled")
+ telephonyManager.setMobileDataPolicyEnabled(policy, enabled)
+ }
+
+ private companion object {
+ private const val TAG = "TelephonyRepository"
+ }
+}
/** Creates an instance of a cold Flow for Telephony callback of given [subId]. */
fun <T> Context.telephonyCallbackFlow(
subId: Int,
block: ProducerScope<T>.() -> TelephonyCallback,
): Flow<T> = callbackFlow {
- val telephonyManager = getSystemService(TelephonyManager::class.java)!!
- .createForSubscriptionId(subId)
+ val telephonyManager = telephonyManager(subId)
val callback = block()
@@ -42,3 +80,7 @@
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
}.conflate().flowOn(Dispatchers.Default)
+
+fun Context.telephonyManager(subId: Int): TelephonyManager =
+ getSystemService(TelephonyManager::class.java)!!
+ .createForSubscriptionId(subId)
diff --git a/src/com/android/settings/spa/network/AutomaticDataSwitchingPreference.kt b/src/com/android/settings/spa/network/AutomaticDataSwitchingPreference.kt
new file mode 100644
index 0000000..824a935
--- /dev/null
+++ b/src/com/android/settings/spa/network/AutomaticDataSwitchingPreference.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.spa.network
+
+import android.telephony.TelephonyManager
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.res.stringResource
+import com.android.settings.R
+import com.android.settings.network.telephony.TelephonyRepository
+import com.android.settingslib.spa.widget.preference.SwitchPreference
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+@Composable
+fun AutomaticDataSwitchingPreference(
+ isAutoDataEnabled: () -> Boolean?,
+ setAutoDataEnabled: (newEnabled: Boolean) -> Unit,
+) {
+ val autoDataSummary = stringResource(id = R.string.primary_sim_automatic_data_msg)
+ val coroutineScope = rememberCoroutineScope()
+ SwitchPreference(
+ object : SwitchPreferenceModel {
+ override val title = stringResource(id = R.string.primary_sim_automatic_data_title)
+ override val summary = { autoDataSummary }
+ override val checked = { isAutoDataEnabled() }
+ override val onCheckedChange: (Boolean) -> Unit = { newEnabled ->
+ coroutineScope.launch(Dispatchers.Default) {
+ setAutoDataEnabled(newEnabled)
+ }
+ }
+ }
+ )
+}
+
+fun TelephonyRepository.setAutomaticData(subId: Int, newEnabled: Boolean) {
+ setMobileDataPolicyEnabled(
+ subId = subId,
+ policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
+ enabled = newEnabled,
+ )
+ //TODO: setup backup calling
+}
diff --git a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
index 5a2a394..bc5a4b7 100644
--- a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
+++ b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
@@ -30,7 +30,6 @@
import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
@@ -44,6 +43,7 @@
import com.android.settings.R
import com.android.settings.network.SubscriptionInfoListViewModel
import com.android.settings.network.telephony.MobileNetworkUtils
+import com.android.settings.network.telephony.TelephonyRepository
import com.android.settings.spa.network.PrimarySimRepository.PrimarySimInfo
import com.android.settings.wifi.WifiPickerTrackerHelper
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
@@ -53,8 +53,6 @@
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
-import com.android.settingslib.spa.widget.preference.SwitchPreference
-import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.Category
import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverFlow
@@ -193,7 +191,6 @@
callsSelectedId: MutableIntState,
textsSelectedId: MutableIntState,
mobileDataSelectedId: MutableIntState,
- nonDds: MutableIntState,
subscriptionManager: SubscriptionManager? =
LocalContext.current.getSystemService(SubscriptionManager::class.java),
coroutineScope: CoroutineScope = rememberCoroutineScope(),
@@ -223,23 +220,9 @@
)
}
},
- actionSetAutoDataSwitch: (Boolean) -> Unit = { newState ->
- coroutineScope.launch {
- val telephonyManagerForNonDds: TelephonyManager? =
- context.getSystemService(TelephonyManager::class.java)
- ?.createForSubscriptionId(nonDds.intValue)
- Log.d(NetworkCellularGroupProvider.name, "NonDds:${nonDds.intValue} setAutomaticData")
- setAutomaticData(telephonyManagerForNonDds, newState)
- }
- },
+ isAutoDataEnabled: () -> Boolean?,
+ setAutoDataEnabled: (newEnabled: Boolean) -> Unit,
) {
- val telephonyManagerForNonDds: TelephonyManager? =
- context.getSystemService(TelephonyManager::class.java)
- ?.createForSubscriptionId(nonDds.intValue)
- val automaticDataChecked = rememberSaveable() {
- mutableStateOf(false)
- }
-
CreatePrimarySimListPreference(
stringResource(id = R.string.primary_sim_calls_title),
primarySimInfo.callsAndSmsList,
@@ -262,31 +245,7 @@
actionSetMobileData
)
- val autoDataTitle = stringResource(id = R.string.primary_sim_automatic_data_title)
- val autoDataSummary = stringResource(id = R.string.primary_sim_automatic_data_msg)
- SwitchPreference(
- object : SwitchPreferenceModel {
- override val title = autoDataTitle
- override val summary = { autoDataSummary }
- override val checked = {
- if (nonDds.intValue != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- coroutineScope.launch {
- automaticDataChecked.value = getAutomaticData(telephonyManagerForNonDds)
- Log.d(
- NetworkCellularGroupProvider.name,
- "NonDds:${nonDds.intValue}" +
- "getAutomaticData:${automaticDataChecked.value}"
- )
- }
- }
- automaticDataChecked.value
- }
- override val onCheckedChange: ((Boolean) -> Unit)? = {
- automaticDataChecked.value = it
- actionSetAutoDataSwitch(it)
- }
- }
- )
+ AutomaticDataSwitchingPreference(isAutoDataEnabled, setAutoDataEnabled)
}
@Composable
@@ -308,12 +267,21 @@
}.collectAsStateWithLifecycle(initialValue = null).value ?: return
Category(title = stringResource(id = R.string.primary_sim_title)) {
+ val isAutoDataEnabled by remember(nonDds.intValue) {
+ TelephonyRepository(context).isMobileDataPolicyEnabledFlow(
+ subId = nonDds.intValue,
+ policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
+ )
+ }.collectAsStateWithLifecycle(initialValue = null)
PrimarySimImpl(
primarySimInfo,
callsSelectedId,
textsSelectedId,
mobileDataSelectedId,
- nonDds
+ isAutoDataEnabled = { isAutoDataEnabled },
+ setAutoDataEnabled = { newEnabled ->
+ TelephonyRepository(context).setAutomaticData(nonDds.intValue, newEnabled)
+ },
)
}
}
@@ -381,23 +349,3 @@
wifiPickerTrackerHelper.setCarrierNetworkEnabled(true)
}
}
-
-suspend fun getAutomaticData(telephonyManagerForNonDds: TelephonyManager?): Boolean =
- withContext(Dispatchers.Default) {
- telephonyManagerForNonDds != null
- && telephonyManagerForNonDds.isMobileDataPolicyEnabled(
- TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
- }
-
-suspend fun setAutomaticData(telephonyManager: TelephonyManager?, newState: Boolean): Unit =
- withContext(Dispatchers.Default) {
- Log.d(
- NetworkCellularGroupProvider.name,
- "setAutomaticData: MOBILE_DATA_POLICY_AUTO_DATA_SWITCH as $newState"
- )
- telephonyManager?.setMobileDataPolicyEnabled(
- TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
- newState
- )
- //TODO: setup backup calling
- }
\ No newline at end of file
diff --git a/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt b/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
index a8c0575..4fad332 100644
--- a/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
+++ b/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
@@ -23,6 +23,7 @@
import androidx.compose.material.icons.outlined.SignalCellularAlt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableIntState
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
@@ -75,9 +76,6 @@
val mobileDataSelectedId = rememberSaveable {
mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
}
- val nonDdsRemember = rememberSaveable {
- mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
- }
Column(Modifier.padding(SettingsDimension.itemPadding)) {
SettingsBody(stringResource(id = R.string.sim_onboarding_primary_sim_msg))
@@ -94,12 +92,14 @@
callsSelectedId.intValue = onboardingService.targetPrimarySimCalls
textsSelectedId.intValue = onboardingService.targetPrimarySimTexts
mobileDataSelectedId.intValue = onboardingService.targetPrimarySimMobileData
+ val isAutoDataEnabled by
+ onboardingService.targetPrimarySimAutoDataSwitch
+ .collectAsStateWithLifecycle(initialValue = null)
PrimarySimImpl(
primarySimInfo = primarySimInfo,
callsSelectedId = callsSelectedId,
textsSelectedId = textsSelectedId,
mobileDataSelectedId = mobileDataSelectedId,
- nonDds = nonDdsRemember,
actionSetCalls = {
callsSelectedId.intValue = it
onboardingService.targetPrimarySimCalls = it},
@@ -109,8 +109,10 @@
actionSetMobileData = {
mobileDataSelectedId.intValue = it
onboardingService.targetPrimarySimMobileData = it},
- actionSetAutoDataSwitch = {
- onboardingService.targetPrimarySimAutoDataSwitch = it},
+ isAutoDataEnabled = { isAutoDataEnabled },
+ setAutoDataEnabled = { newEnabled ->
+ onboardingService.targetPrimarySimAutoDataSwitch.value = newEnabled
+ },
)
}
}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyRepositoryTest.kt
index b7e1dcc..ce27ed4 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyRepositoryTest.kt
@@ -17,12 +17,14 @@
package com.android.settings.network.telephony
import android.content.Context
+import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
@@ -31,6 +33,7 @@
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
import org.mockito.kotlin.verify
@RunWith(AndroidJUnit4::class)
@@ -48,6 +51,46 @@
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
}
+ private val repository = TelephonyRepository(context, flowOf(Unit))
+
+ @Test
+ fun isMobileDataPolicyEnabledFlow_invalidSub_returnFalse() = runBlocking {
+ val flow = repository.isMobileDataPolicyEnabledFlow(
+ subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+ policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
+ )
+
+ assertThat(flow.firstWithTimeoutOrNull()).isFalse()
+ }
+
+ @Test
+ fun isMobileDataPolicyEnabledFlow_validSub_returnPolicyState() = runBlocking {
+ mockTelephonyManager.stub {
+ on {
+ isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
+ } doReturn true
+ }
+
+ val flow = repository.isMobileDataPolicyEnabledFlow(
+ subId = SUB_ID,
+ policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
+ )
+
+ assertThat(flow.firstWithTimeoutOrNull()).isTrue()
+ }
+
+ @Test
+ fun setMobileDataPolicyEnabled() = runBlocking {
+ repository.setMobileDataPolicyEnabled(
+ subId = SUB_ID,
+ policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
+ enabled = true
+ )
+
+ verify(mockTelephonyManager)
+ .setMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, true)
+ }
+
@Test
fun telephonyCallbackFlow_callbackRegistered() = runBlocking {
val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) {