Move mobile data logic into MobileDataRepository
Bug: 347224962 Flag: EXEMPT refactor Test: manual on Mobile Settings Test: unit Change-Id: I2b54f9e6c4addafd31d7d96f2a44870cd54fe185
This commit is contained in:
@@ -21,7 +21,7 @@ import android.os.INetworkManagementService
|
|||||||
import android.os.ServiceManager
|
import android.os.ServiceManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.OpenForTesting
|
import androidx.annotation.OpenForTesting
|
||||||
import com.android.settings.network.telephony.TelephonyRepository
|
import com.android.settings.network.telephony.MobileDataRepository
|
||||||
import com.android.settingslib.spaprivileged.framework.common.userManager
|
import com.android.settingslib.spaprivileged.framework.common.userManager
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@@ -36,13 +36,13 @@ open class BillingCycleRepository @JvmOverloads constructor(
|
|||||||
INetworkManagementService.Stub.asInterface(
|
INetworkManagementService.Stub.asInterface(
|
||||||
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)
|
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)
|
||||||
),
|
),
|
||||||
private val telephonyRepository: TelephonyRepository = TelephonyRepository(context),
|
private val mobileDataRepository: MobileDataRepository = MobileDataRepository(context),
|
||||||
) {
|
) {
|
||||||
private val userManager = context.userManager
|
private val userManager = context.userManager
|
||||||
|
|
||||||
fun isModifiableFlow(subId: Int): Flow<Boolean> =
|
fun isModifiableFlow(subId: Int): Flow<Boolean> =
|
||||||
telephonyRepository.isDataEnabledFlow(subId).map { isDataEnabled ->
|
mobileDataRepository.isMobileDataEnabledFlow(subId).map { mobileDataEnabled ->
|
||||||
isDataEnabled && isBandwidthControlEnabled() && userManager.isAdminUser
|
mobileDataEnabled && isBandwidthControlEnabled() && userManager.isAdminUser
|
||||||
}.conflate().flowOn(Dispatchers.Default)
|
}.conflate().flowOn(Dispatchers.Default)
|
||||||
|
|
||||||
open fun isBandwidthControlEnabled(): Boolean = try {
|
open fun isBandwidthControlEnabled(): Boolean = try {
|
||||||
|
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2023 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.network
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.provider.Settings
|
|
||||||
import android.telephony.SubscriptionManager
|
|
||||||
import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalChangeFlow
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.merge
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flow for mobile data enabled changed event.
|
|
||||||
*
|
|
||||||
* Note: This flow can only notify enabled status changes, cannot provide the latest status.
|
|
||||||
*/
|
|
||||||
fun Context.mobileDataEnabledFlow(subId: Int, sendInitialValue: Boolean = true): Flow<Unit> {
|
|
||||||
val flow = settingsGlobalChangeFlow(Settings.Global.MOBILE_DATA, sendInitialValue)
|
|
||||||
return when (subId) {
|
|
||||||
SubscriptionManager.INVALID_SUBSCRIPTION_ID -> flow
|
|
||||||
else -> {
|
|
||||||
val subIdFlow = settingsGlobalChangeFlow(
|
|
||||||
name = Settings.Global.MOBILE_DATA + subId,
|
|
||||||
sendInitialValue = false,
|
|
||||||
)
|
|
||||||
merge(flow, subIdFlow)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -27,9 +27,8 @@ import android.telephony.UiccCardInfo
|
|||||||
import android.telephony.UiccSlotInfo
|
import android.telephony.UiccSlotInfo
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.android.settings.network.SimOnboardingActivity.Companion.CallbackType
|
import com.android.settings.network.SimOnboardingActivity.Companion.CallbackType
|
||||||
import com.android.settings.network.telephony.TelephonyRepository
|
import com.android.settings.network.telephony.MobileDataRepository
|
||||||
import com.android.settings.sim.SimActivationNotifier
|
import com.android.settings.sim.SimActivationNotifier
|
||||||
import com.android.settings.spa.network.setAutomaticData
|
|
||||||
import com.android.settings.spa.network.setDefaultData
|
import com.android.settings.spa.network.setDefaultData
|
||||||
import com.android.settings.spa.network.setDefaultSms
|
import com.android.settings.spa.network.setDefaultSms
|
||||||
import com.android.settings.spa.network.setDefaultVoice
|
import com.android.settings.spa.network.setDefaultVoice
|
||||||
@@ -366,7 +365,7 @@ class SimOnboardingService {
|
|||||||
wifiPickerTrackerHelper,
|
wifiPickerTrackerHelper,
|
||||||
targetPrimarySimMobileData
|
targetPrimarySimMobileData
|
||||||
)
|
)
|
||||||
TelephonyRepository(context).setAutomaticData(
|
MobileDataRepository(context).setAutoDataSwitch(
|
||||||
targetNonDds,
|
targetNonDds,
|
||||||
targetPrimarySimAutoDataSwitch.value
|
targetPrimarySimAutoDataSwitch.value
|
||||||
)
|
)
|
||||||
|
@@ -22,7 +22,6 @@ import android.telephony.TelephonyManager
|
|||||||
import android.telephony.data.ApnSetting
|
import android.telephony.data.ApnSetting
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import com.android.settings.network.mobileDataEnabledFlow
|
|
||||||
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
|
||||||
@@ -71,7 +70,7 @@ class MmsMessagePreferenceController @JvmOverloads constructor(
|
|||||||
|
|
||||||
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
|
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
|
||||||
combine(
|
combine(
|
||||||
mContext.mobileDataEnabledFlow(mSubId),
|
MobileDataRepository(mContext).mobileDataEnabledChangedFlow(mSubId),
|
||||||
mContext.subscriptionsChangedFlow(), // Capture isMobileDataPolicyEnabled() changes
|
mContext.subscriptionsChangedFlow(), // Capture isMobileDataPolicyEnabled() changes
|
||||||
) { _, _ -> }.collectLatestWithLifecycle(viewLifecycleOwner) {
|
) { _, _ -> }.collectLatestWithLifecycle(viewLifecycleOwner) {
|
||||||
preferenceScreen?.let { super.displayPreference(it) }
|
preferenceScreen?.let { super.displayPreference(it) }
|
||||||
|
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* 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.network.telephony
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.telephony.SubscriptionManager
|
||||||
|
import android.telephony.TelephonyManager
|
||||||
|
import android.telephony.TelephonyManager.MobileDataPolicy
|
||||||
|
import android.util.Log
|
||||||
|
import com.android.settings.wifi.WifiPickerTrackerHelper
|
||||||
|
import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalChangeFlow
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.catch
|
||||||
|
import kotlinx.coroutines.flow.conflate
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
||||||
|
class MobileDataRepository(
|
||||||
|
private val context: Context,
|
||||||
|
private val subscriptionsChangedFlow: Flow<Unit> = context.subscriptionsChangedFlow(),
|
||||||
|
) {
|
||||||
|
fun isMobileDataPolicyEnabledFlow(subId: Int, @MobileDataPolicy policy: Int): Flow<Boolean> {
|
||||||
|
if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
|
||||||
|
val telephonyManager = context.telephonyManager(subId)
|
||||||
|
return subscriptionsChangedFlow
|
||||||
|
.map { telephonyManager.isMobileDataPolicyEnabled(policy) }
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.conflate()
|
||||||
|
.onEach { Log.d(TAG, "[$subId] isMobileDataPolicyEnabled($policy): $it") }
|
||||||
|
.flowOn(Dispatchers.Default)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMobileDataPolicyEnabled(subId: Int, @MobileDataPolicy policy: Int, enabled: Boolean) {
|
||||||
|
if (!SubscriptionManager.isValidSubscriptionId(subId)) return
|
||||||
|
Log.d(TAG, "[$subId] setMobileDataPolicyEnabled($policy): $enabled")
|
||||||
|
context.telephonyManager(subId).setMobileDataPolicyEnabled(policy, enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAutoDataSwitch(subId: Int, newEnabled: Boolean) {
|
||||||
|
setMobileDataPolicyEnabled(
|
||||||
|
subId = subId,
|
||||||
|
policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
|
||||||
|
enabled = newEnabled,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flow for mobile data enabled changed event.
|
||||||
|
*
|
||||||
|
* Note: This flow can only notify enabled status changes, cannot provide the latest status.
|
||||||
|
*/
|
||||||
|
fun mobileDataEnabledChangedFlow(subId: Int, sendInitialValue: Boolean = true): Flow<Unit> =
|
||||||
|
mobileSettingsGlobalChangedFlow(Settings.Global.MOBILE_DATA, subId, sendInitialValue)
|
||||||
|
|
||||||
|
private fun mobileSettingsGlobalChangedFlow(
|
||||||
|
name: String,
|
||||||
|
subId: Int,
|
||||||
|
sendInitialValue: Boolean = true,
|
||||||
|
): Flow<Unit> {
|
||||||
|
val flow = context.settingsGlobalChangeFlow(name, sendInitialValue)
|
||||||
|
if (!SubscriptionManager.isValidSubscriptionId(subId)) return flow
|
||||||
|
val subIdFlow =
|
||||||
|
context.settingsGlobalChangeFlow(name = name + subId, sendInitialValue = false)
|
||||||
|
return merge(flow, subIdFlow)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isMobileDataEnabledFlow(subId: Int): Flow<Boolean> {
|
||||||
|
if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
|
||||||
|
val telephonyManager = context.telephonyManager(subId)
|
||||||
|
return mobileDataEnabledChangedFlow(subId)
|
||||||
|
.map {
|
||||||
|
telephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
|
||||||
|
}
|
||||||
|
.catch { e ->
|
||||||
|
Log.w(TAG, "[$subId] isMobileDataEnabledFlow: exception", e)
|
||||||
|
emit(false)
|
||||||
|
}
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.conflate()
|
||||||
|
.onEach { Log.d(TAG, "[$subId] isMobileDataEnabledFlow: $it") }
|
||||||
|
.flowOn(Dispatchers.Default)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMobileDataEnabled(
|
||||||
|
subId: Int,
|
||||||
|
enabled: Boolean,
|
||||||
|
wifiPickerTrackerHelper: WifiPickerTrackerHelper? = null,
|
||||||
|
) {
|
||||||
|
if (!SubscriptionManager.isValidSubscriptionId(subId)) return
|
||||||
|
|
||||||
|
Log.d(TAG, "setMobileDataEnabled: $enabled")
|
||||||
|
MobileNetworkUtils.setMobileDataEnabled(
|
||||||
|
context, subId, enabled, /* disableOtherSubscriptions= */ true)
|
||||||
|
|
||||||
|
if (wifiPickerTrackerHelper != null &&
|
||||||
|
!wifiPickerTrackerHelper.isCarrierNetworkProvisionEnabled(subId)) {
|
||||||
|
wifiPickerTrackerHelper.setCarrierNetworkEnabled(enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private const val TAG = "MobileDataRepository"
|
||||||
|
}
|
||||||
|
}
|
@@ -17,98 +17,16 @@
|
|||||||
package com.android.settings.network.telephony
|
package com.android.settings.network.telephony
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.telephony.SubscriptionManager
|
|
||||||
import android.telephony.TelephonyCallback
|
import android.telephony.TelephonyCallback
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
import android.util.Log
|
|
||||||
import com.android.settings.network.mobileDataEnabledFlow
|
|
||||||
import com.android.settings.wifi.WifiPickerTrackerHelper
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.asExecutor
|
import kotlinx.coroutines.asExecutor
|
||||||
import kotlinx.coroutines.channels.ProducerScope
|
import kotlinx.coroutines.channels.ProducerScope
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.catch
|
|
||||||
import kotlinx.coroutines.flow.conflate
|
import kotlinx.coroutines.flow.conflate
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isDataEnabledFlow(subId: Int): Flow<Boolean> {
|
|
||||||
if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
|
|
||||||
|
|
||||||
return context.mobileDataEnabledFlow(subId)
|
|
||||||
.map {
|
|
||||||
val telephonyManager = context.telephonyManager(subId)
|
|
||||||
telephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
|
|
||||||
}
|
|
||||||
.catch {
|
|
||||||
Log.w(TAG, "[$subId] isDataEnabledFlow: exception", it)
|
|
||||||
emit(false)
|
|
||||||
}
|
|
||||||
.onEach { Log.d(TAG, "[$subId] isDataEnabledFlow: isDataEnabled() = $it") }
|
|
||||||
.conflate()
|
|
||||||
.flowOn(Dispatchers.Default)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setMobileData(
|
|
||||||
subId: Int,
|
|
||||||
enabled: Boolean,
|
|
||||||
wifiPickerTrackerHelper: WifiPickerTrackerHelper? = null
|
|
||||||
) {
|
|
||||||
if (!SubscriptionManager.isValidSubscriptionId(subId)) return
|
|
||||||
|
|
||||||
Log.d(TAG, "setMobileData: $enabled")
|
|
||||||
MobileNetworkUtils.setMobileDataEnabled(
|
|
||||||
context,
|
|
||||||
subId,
|
|
||||||
enabled /* enabled */,
|
|
||||||
true /* disableOtherSubscriptions */
|
|
||||||
)
|
|
||||||
|
|
||||||
if (wifiPickerTrackerHelper != null
|
|
||||||
&& !wifiPickerTrackerHelper.isCarrierNetworkProvisionEnabled(subId)
|
|
||||||
) {
|
|
||||||
wifiPickerTrackerHelper.setCarrierNetworkEnabled(enabled)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
private const val TAG = "TelephonyRepository"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates an instance of a cold Flow for Telephony callback of given [subId]. */
|
/** Creates an instance of a cold Flow for Telephony callback of given [subId]. */
|
||||||
fun <T> Context.telephonyCallbackFlow(
|
fun <T> Context.telephonyCallbackFlow(
|
||||||
|
@@ -24,7 +24,7 @@ import android.telephony.TelephonyManager
|
|||||||
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
|
||||||
import com.android.settings.network.mobileDataEnabledFlow
|
import com.android.settings.network.telephony.MobileDataRepository
|
||||||
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
|
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
|
||||||
import com.android.settings.network.telephony.requireSubscriptionManager
|
import com.android.settings.network.telephony.requireSubscriptionManager
|
||||||
import com.android.settings.network.telephony.safeGetConfig
|
import com.android.settings.network.telephony.safeGetConfig
|
||||||
@@ -54,6 +54,7 @@ class CrossSimCallingViewModel(
|
|||||||
private val scope = viewModelScope + Dispatchers.Default
|
private val scope = viewModelScope + Dispatchers.Default
|
||||||
private val metricsFeatureProvider = featureFactory.metricsFeatureProvider
|
private val metricsFeatureProvider = featureFactory.metricsFeatureProvider
|
||||||
private val updateChannel = Channel<Unit>()
|
private val updateChannel = Channel<Unit>()
|
||||||
|
private val mobileDataRepository = MobileDataRepository(application)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val resources = application.resources
|
val resources = application.resources
|
||||||
@@ -81,7 +82,7 @@ class CrossSimCallingViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun List<Int>.anyMobileDataEnableChangedFlow() = map { subId ->
|
private fun List<Int>.anyMobileDataEnableChangedFlow() = map { subId ->
|
||||||
application.mobileDataEnabledFlow(subId = subId, sendInitialValue = false)
|
mobileDataRepository.mobileDataEnabledChangedFlow(subId = subId, sendInitialValue = false)
|
||||||
}.merge()
|
}.merge()
|
||||||
|
|
||||||
private suspend fun updateCrossSimCalling(activeSubIds: List<Int>, newEnabled: Boolean) {
|
private suspend fun updateCrossSimCalling(activeSubIds: List<Int>, newEnabled: Boolean) {
|
||||||
|
@@ -16,13 +16,11 @@
|
|||||||
|
|
||||||
package com.android.settings.spa.network
|
package com.android.settings.spa.network
|
||||||
|
|
||||||
import android.telephony.TelephonyManager
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.network.telephony.TelephonyRepository
|
|
||||||
import com.android.settings.network.telephony.wificalling.CrossSimCallingViewModel
|
import com.android.settings.network.telephony.wificalling.CrossSimCallingViewModel
|
||||||
import com.android.settingslib.spa.widget.preference.SwitchPreference
|
import com.android.settingslib.spa.widget.preference.SwitchPreference
|
||||||
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
||||||
@@ -51,11 +49,3 @@ fun AutomaticDataSwitchingPreference(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TelephonyRepository.setAutomaticData(subId: Int, newEnabled: Boolean) {
|
|
||||||
setMobileDataPolicyEnabled(
|
|
||||||
subId = subId,
|
|
||||||
policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
|
|
||||||
enabled = newEnabled,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@@ -16,12 +16,10 @@
|
|||||||
|
|
||||||
package com.android.settings.spa.network
|
package com.android.settings.spa.network
|
||||||
|
|
||||||
import android.telephony.TelephonyManager
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.android.settings.R
|
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.SwitchPreference
|
||||||
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@@ -48,13 +48,14 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
|||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.network.SubscriptionInfoListViewModel
|
import com.android.settings.network.SubscriptionInfoListViewModel
|
||||||
import com.android.settings.network.telephony.DataSubscriptionRepository
|
import com.android.settings.network.telephony.DataSubscriptionRepository
|
||||||
import com.android.settings.network.telephony.TelephonyRepository
|
import com.android.settings.network.telephony.MobileDataRepository
|
||||||
import com.android.settings.spa.network.PrimarySimRepository.PrimarySimInfo
|
import com.android.settings.spa.network.PrimarySimRepository.PrimarySimInfo
|
||||||
import com.android.settings.wifi.WifiPickerTrackerHelper
|
import com.android.settings.wifi.WifiPickerTrackerHelper
|
||||||
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
|
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
|
||||||
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||||
import com.android.settingslib.spa.framework.common.createSettingsPage
|
import com.android.settingslib.spa.framework.common.createSettingsPage
|
||||||
import com.android.settingslib.spa.framework.compose.navigator
|
import com.android.settingslib.spa.framework.compose.navigator
|
||||||
|
import com.android.settingslib.spa.framework.compose.rememberContext
|
||||||
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
||||||
import com.android.settingslib.spa.widget.preference.Preference
|
import com.android.settingslib.spa.widget.preference.Preference
|
||||||
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
||||||
@@ -202,21 +203,18 @@ fun MobileDataSectionImpl(
|
|||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val localLifecycleOwner = LocalLifecycleOwner.current
|
val localLifecycleOwner = LocalLifecycleOwner.current
|
||||||
val wifiPickerTrackerHelper = getWifiPickerTrackerHelper(context, localLifecycleOwner)
|
val mobileDataRepository = rememberContext(::MobileDataRepository)
|
||||||
|
|
||||||
val subscriptionManager: SubscriptionManager? =
|
|
||||||
context.getSystemService(SubscriptionManager::class.java)
|
|
||||||
|
|
||||||
Category(title = stringResource(id = R.string.mobile_data_settings_title)) {
|
Category(title = stringResource(id = R.string.mobile_data_settings_title)) {
|
||||||
val isAutoDataEnabled by remember(nonDds.intValue) {
|
val isAutoDataEnabled by remember(nonDds.intValue) {
|
||||||
TelephonyRepository(context).isMobileDataPolicyEnabledFlow(
|
mobileDataRepository.isMobileDataPolicyEnabledFlow(
|
||||||
subId = nonDds.intValue,
|
subId = nonDds.intValue,
|
||||||
policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
|
policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
|
||||||
)
|
)
|
||||||
}.collectAsStateWithLifecycle(initialValue = null)
|
}.collectAsStateWithLifecycle(initialValue = null)
|
||||||
|
|
||||||
val mobileDataStateChanged by remember(mobileDataSelectedId.intValue) {
|
val mobileDataStateChanged by remember(mobileDataSelectedId.intValue) {
|
||||||
TelephonyRepository(context).isDataEnabledFlow(mobileDataSelectedId.intValue)
|
mobileDataRepository.isMobileDataEnabledFlow(mobileDataSelectedId.intValue)
|
||||||
}.collectAsStateWithLifecycle(initialValue = false)
|
}.collectAsStateWithLifecycle(initialValue = false)
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
@@ -226,8 +224,8 @@ fun MobileDataSectionImpl(
|
|||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
setMobileData(
|
setMobileData(
|
||||||
context,
|
context,
|
||||||
subscriptionManager,
|
context.getSystemService(SubscriptionManager::class.java),
|
||||||
wifiPickerTrackerHelper,
|
getWifiPickerTrackerHelper(context, localLifecycleOwner),
|
||||||
mobileDataSelectedId.intValue,
|
mobileDataSelectedId.intValue,
|
||||||
newEnabled
|
newEnabled
|
||||||
)
|
)
|
||||||
@@ -238,7 +236,7 @@ fun MobileDataSectionImpl(
|
|||||||
AutomaticDataSwitchingPreference(
|
AutomaticDataSwitchingPreference(
|
||||||
isAutoDataEnabled = { isAutoDataEnabled },
|
isAutoDataEnabled = { isAutoDataEnabled },
|
||||||
setAutoDataEnabled = { newEnabled ->
|
setAutoDataEnabled = { newEnabled ->
|
||||||
TelephonyRepository(context).setAutomaticData(nonDds.intValue, newEnabled)
|
mobileDataRepository.setAutoDataSwitch(nonDds.intValue, newEnabled)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -426,6 +424,6 @@ suspend fun setMobileData(
|
|||||||
Log.d(NetworkCellularGroupProvider.fileName, "setDefaultData: [$targetSubId]")
|
Log.d(NetworkCellularGroupProvider.fileName, "setDefaultData: [$targetSubId]")
|
||||||
subscriptionManager?.setDefaultDataSubId(targetSubId)
|
subscriptionManager?.setDefaultDataSubId(targetSubId)
|
||||||
}
|
}
|
||||||
TelephonyRepository(context)
|
MobileDataRepository(context)
|
||||||
.setMobileData(targetSubId, enabled, wifiPickerTrackerHelper)
|
.setMobileDataEnabled(targetSubId, enabled, wifiPickerTrackerHelper)
|
||||||
}
|
}
|
@@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2023 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.network
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.provider.Settings
|
|
||||||
import android.telephony.SubscriptionManager
|
|
||||||
import androidx.test.core.app.ApplicationProvider
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
||||||
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
|
|
||||||
import com.android.settingslib.spa.testutils.toListWithTimeout
|
|
||||||
import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBoolean
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
|
||||||
class MobileDataEnabledFlowTest {
|
|
||||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun mobileDataEnabledFlow_notified(): Unit = runBlocking {
|
|
||||||
val flow = context.mobileDataEnabledFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
|
|
||||||
|
|
||||||
assertThat(flow.firstWithTimeoutOrNull()).isNotNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun mobileDataEnabledFlow_changed_notified(): Unit = runBlocking {
|
|
||||||
var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
|
|
||||||
mobileDataEnabled = false
|
|
||||||
|
|
||||||
val flow = context.mobileDataEnabledFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
|
|
||||||
mobileDataEnabled = true
|
|
||||||
|
|
||||||
assertThat(flow.firstWithTimeoutOrNull()).isNotNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun mobileDataEnabledFlow_forSubIdNotChanged(): Unit = runBlocking {
|
|
||||||
var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
|
|
||||||
mobileDataEnabled = false
|
|
||||||
var mobileDataEnabledForSubId
|
|
||||||
by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA + SUB_ID)
|
|
||||||
mobileDataEnabledForSubId = false
|
|
||||||
|
|
||||||
val listDeferred = async {
|
|
||||||
context.mobileDataEnabledFlow(SUB_ID).toListWithTimeout()
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThat(listDeferred.await()).hasSize(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun mobileDataEnabledFlow_forSubIdChanged(): Unit = runBlocking {
|
|
||||||
var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
|
|
||||||
mobileDataEnabled = false
|
|
||||||
var mobileDataEnabledForSubId
|
|
||||||
by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA + SUB_ID)
|
|
||||||
mobileDataEnabledForSubId = false
|
|
||||||
|
|
||||||
val listDeferred = async {
|
|
||||||
context.mobileDataEnabledFlow(SUB_ID).toListWithTimeout()
|
|
||||||
}
|
|
||||||
delay(100)
|
|
||||||
mobileDataEnabledForSubId = true
|
|
||||||
|
|
||||||
assertThat(listDeferred.await().size).isAtLeast(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
const val SUB_ID = 123
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* 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.network.telephony
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.telephony.SubscriptionManager
|
||||||
|
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.android.settingslib.spa.testutils.toListWithTimeout
|
||||||
|
import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBoolean
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
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)
|
||||||
|
class MobileDataRepositoryTest {
|
||||||
|
private val mockTelephonyManager =
|
||||||
|
mock<TelephonyManager> { on { createForSubscriptionId(SUB_ID) } doReturn mock }
|
||||||
|
|
||||||
|
private val context: Context =
|
||||||
|
spy(ApplicationProvider.getApplicationContext()) {
|
||||||
|
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
|
||||||
|
}
|
||||||
|
|
||||||
|
private val repository = MobileDataRepository(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 mobileDataEnabledChangedFlow_notified(): Unit = runBlocking {
|
||||||
|
val flow =
|
||||||
|
repository.mobileDataEnabledChangedFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
|
||||||
|
|
||||||
|
assertThat(flow.firstWithTimeoutOrNull()).isNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun mobileDataEnabledChangedFlow_changed_notified(): Unit = runBlocking {
|
||||||
|
var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
|
||||||
|
mobileDataEnabled = false
|
||||||
|
|
||||||
|
val flow =
|
||||||
|
repository.mobileDataEnabledChangedFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
|
||||||
|
mobileDataEnabled = true
|
||||||
|
|
||||||
|
assertThat(flow.firstWithTimeoutOrNull()).isNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun mobileDataEnabledChangedFlow_forSubIdNotChanged(): Unit = runBlocking {
|
||||||
|
var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
|
||||||
|
mobileDataEnabled = false
|
||||||
|
var mobileDataEnabledForSubId by
|
||||||
|
context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA + SUB_ID)
|
||||||
|
mobileDataEnabledForSubId = false
|
||||||
|
|
||||||
|
val listDeferred = async {
|
||||||
|
repository.mobileDataEnabledChangedFlow(SUB_ID).toListWithTimeout()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(listDeferred.await()).hasSize(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun mobileDataEnabledChangedFlow_forSubIdChanged(): Unit = runBlocking {
|
||||||
|
var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
|
||||||
|
mobileDataEnabled = false
|
||||||
|
var mobileDataEnabledForSubId by
|
||||||
|
context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA + SUB_ID)
|
||||||
|
mobileDataEnabledForSubId = false
|
||||||
|
|
||||||
|
val listDeferred = async {
|
||||||
|
repository.mobileDataEnabledChangedFlow(SUB_ID).toListWithTimeout()
|
||||||
|
}
|
||||||
|
delay(100)
|
||||||
|
mobileDataEnabledForSubId = true
|
||||||
|
|
||||||
|
assertThat(listDeferred.await().size).isAtLeast(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isMobileDataEnabledFlow_invalidSub_returnFalse() = runBlocking {
|
||||||
|
val state =
|
||||||
|
repository.isMobileDataEnabledFlow(
|
||||||
|
subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(state.firstWithTimeoutOrNull()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isMobileDataEnabledFlow_validSub_returnPolicyState() = runBlocking {
|
||||||
|
mockTelephonyManager.stub {
|
||||||
|
on { isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER) } doReturn true
|
||||||
|
}
|
||||||
|
|
||||||
|
val state = repository.isMobileDataEnabledFlow(subId = SUB_ID)
|
||||||
|
|
||||||
|
assertThat(state.firstWithTimeoutOrNull()).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val SUB_ID = 123
|
||||||
|
}
|
||||||
|
}
|
@@ -17,14 +17,12 @@
|
|||||||
package com.android.settings.network.telephony
|
package com.android.settings.network.telephony
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.telephony.SubscriptionManager
|
|
||||||
import android.telephony.TelephonyCallback
|
import android.telephony.TelephonyCallback
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
|
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
@@ -33,91 +31,29 @@ import org.mockito.kotlin.doAnswer
|
|||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.spy
|
import org.mockito.kotlin.spy
|
||||||
import org.mockito.kotlin.stub
|
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class TelephonyRepositoryTest {
|
class TelephonyRepositoryTest {
|
||||||
private var telephonyCallback: TelephonyCallback? = null
|
private var telephonyCallback: TelephonyCallback? = null
|
||||||
|
|
||||||
private val mockTelephonyManager = mock<TelephonyManager> {
|
private val mockTelephonyManager =
|
||||||
|
mock<TelephonyManager> {
|
||||||
on { createForSubscriptionId(SUB_ID) } doReturn mock
|
on { createForSubscriptionId(SUB_ID) } doReturn mock
|
||||||
on { registerTelephonyCallback(any(), any()) } doAnswer {
|
on { registerTelephonyCallback(any(), any()) } doAnswer
|
||||||
|
{
|
||||||
telephonyCallback = it.arguments[1] as TelephonyCallback
|
telephonyCallback = it.arguments[1] as TelephonyCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
|
private val context: Context =
|
||||||
|
spy(ApplicationProvider.getApplicationContext()) {
|
||||||
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
|
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 isDataEnabled_invalidSub_returnFalse() = runBlocking {
|
|
||||||
val state = repository.isDataEnabledFlow(
|
|
||||||
subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
|
||||||
)
|
|
||||||
|
|
||||||
assertThat(state.firstWithTimeoutOrNull()).isFalse()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun isDataEnabled_validSub_returnPolicyState() = runBlocking {
|
|
||||||
mockTelephonyManager.stub {
|
|
||||||
on {
|
|
||||||
isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
|
|
||||||
} doReturn true
|
|
||||||
}
|
|
||||||
|
|
||||||
val state = repository.isDataEnabledFlow(subId = SUB_ID)
|
|
||||||
|
|
||||||
assertThat(state.firstWithTimeoutOrNull()).isTrue()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun telephonyCallbackFlow_callbackRegistered() = runBlocking {
|
fun telephonyCallbackFlow_callbackRegistered() = runBlocking {
|
||||||
val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) {
|
val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) { object : TelephonyCallback() {} }
|
||||||
object : TelephonyCallback() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
flow.firstWithTimeoutOrNull()
|
flow.firstWithTimeoutOrNull()
|
||||||
|
|
||||||
@@ -126,9 +62,7 @@ class TelephonyRepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun telephonyCallbackFlow_callbackUnregistered() = runBlocking {
|
fun telephonyCallbackFlow_callbackUnregistered() = runBlocking {
|
||||||
val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) {
|
val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) { object : TelephonyCallback() {} }
|
||||||
object : TelephonyCallback() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
flow.firstWithTimeoutOrNull()
|
flow.firstWithTimeoutOrNull()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user