Create NrRepository
To unify the isNrAvailable logic. Bug: 358000881 Flag: EXEMPT refactor Test: manual - on mobile settings Test: atest NrRepositoryTest Change-Id: I60fed4be10f0cc7b8b1a942abd598e82c53d1473
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package com.android.settings.network.telephony
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.PersistableBundle
|
||||
import android.telephony.CarrierConfigManager
|
||||
import android.telephony.SubscriptionManager
|
||||
@@ -35,7 +36,8 @@ class CarrierConfigRepository(private val context: Context) {
|
||||
private enum class KeyType {
|
||||
BOOLEAN,
|
||||
INT,
|
||||
STRING
|
||||
INT_ARRAY,
|
||||
STRING,
|
||||
}
|
||||
|
||||
interface CarrierConfigAccessor {
|
||||
@@ -43,17 +45,20 @@ class CarrierConfigRepository(private val context: Context) {
|
||||
|
||||
fun getInt(key: String): Int
|
||||
|
||||
fun getIntArray(key: String): IntArray?
|
||||
|
||||
fun getString(key: String): String?
|
||||
}
|
||||
|
||||
private class Accessor(private val cache: ConfigCache) : CarrierConfigAccessor {
|
||||
private val keysToRetrieve = mutableMapOf<String, KeyType>()
|
||||
private var isKeysToRetrieveFrozen = false
|
||||
|
||||
override fun getBoolean(key: String): Boolean {
|
||||
checkBooleanKey(key)
|
||||
val value = cache[key]
|
||||
return if (value == null) {
|
||||
keysToRetrieve += key to KeyType.BOOLEAN
|
||||
addKeyToRetrieve(key, KeyType.BOOLEAN)
|
||||
DefaultConfig.getBoolean(key)
|
||||
} else {
|
||||
check(value is BooleanConfigValue) { "Boolean value type wrong" }
|
||||
@@ -65,7 +70,7 @@ class CarrierConfigRepository(private val context: Context) {
|
||||
check(key.endsWith("_int")) { "Int key should ends with _int" }
|
||||
val value = cache[key]
|
||||
return if (value == null) {
|
||||
keysToRetrieve += key to KeyType.INT
|
||||
addKeyToRetrieve(key, KeyType.INT)
|
||||
DefaultConfig.getInt(key)
|
||||
} else {
|
||||
check(value is IntConfigValue) { "Int value type wrong" }
|
||||
@@ -73,11 +78,23 @@ class CarrierConfigRepository(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getIntArray(key: String): IntArray? {
|
||||
checkIntArrayKey(key)
|
||||
val value = cache[key]
|
||||
return if (value == null) {
|
||||
addKeyToRetrieve(key, KeyType.INT_ARRAY)
|
||||
DefaultConfig.getIntArray(key)
|
||||
} else {
|
||||
check(value is IntArrayConfigValue) { "Int array value type wrong" }
|
||||
value.value
|
||||
}
|
||||
}
|
||||
|
||||
override fun getString(key: String): String? {
|
||||
check(key.endsWith("_string")) { "String key should ends with _string" }
|
||||
val value = cache[key]
|
||||
return if (value == null) {
|
||||
keysToRetrieve += key to KeyType.STRING
|
||||
addKeyToRetrieve(key, KeyType.STRING)
|
||||
DefaultConfig.getString(key)
|
||||
} else {
|
||||
check(value is StringConfigValue) { "String value type wrong" }
|
||||
@@ -85,20 +102,35 @@ class CarrierConfigRepository(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun getKeysToRetrieve(): Map<String, KeyType> = keysToRetrieve
|
||||
private fun addKeyToRetrieve(key: String, type: KeyType) {
|
||||
if (keysToRetrieve.put(key, type) == null && Build.IS_DEBUGGABLE) {
|
||||
check(!isKeysToRetrieveFrozen) { "implement error for key $key" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the keys to retrieve.
|
||||
*
|
||||
* After this function is called, the keys to retrieve is frozen.
|
||||
*/
|
||||
fun getAndFrozeKeysToRetrieve(): Map<String, KeyType> {
|
||||
isKeysToRetrieveFrozen = true
|
||||
return keysToRetrieve
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configuration values for the given [subId].
|
||||
*
|
||||
* Configuration values could be accessed in [block]. Note: [block] could be called multiple
|
||||
* times, so it should be pure function without side effort.
|
||||
* times, so it should be pure function without side effort. Please also make sure every key is
|
||||
* retrieved every time, for example, we need avoid expression shortcut.
|
||||
*/
|
||||
fun <T> transformConfig(subId: Int, block: CarrierConfigAccessor.() -> T): T {
|
||||
val perSubCache = getPerSubCache(subId)
|
||||
val accessor = Accessor(perSubCache)
|
||||
val result = accessor.block()
|
||||
val keysToRetrieve = accessor.getKeysToRetrieve()
|
||||
val keysToRetrieve = accessor.getAndFrozeKeysToRetrieve()
|
||||
// If all keys found in the first pass, no need to collect again
|
||||
if (keysToRetrieve.isEmpty()) return result
|
||||
|
||||
@@ -113,6 +145,10 @@ class CarrierConfigRepository(private val context: Context) {
|
||||
/** Gets the configuration int for the given [subId] and [key]. */
|
||||
fun getInt(subId: Int, key: String): Int = transformConfig(subId) { getInt(key) }
|
||||
|
||||
/** Gets the configuration int array for the given [subId] and [key]. */
|
||||
fun getIntArray(subId: Int, key: String): IntArray? =
|
||||
transformConfig(subId) { getIntArray(key) }
|
||||
|
||||
/** Gets the configuration string for the given [subId] and [key]. */
|
||||
fun getString(subId: Int, key: String): String? = transformConfig(subId) { getString(key) }
|
||||
|
||||
@@ -122,6 +158,7 @@ class CarrierConfigRepository(private val context: Context) {
|
||||
when (type) {
|
||||
KeyType.BOOLEAN -> this[key] = BooleanConfigValue(config.getBoolean(key))
|
||||
KeyType.INT -> this[key] = IntConfigValue(config.getInt(key))
|
||||
KeyType.INT_ARRAY -> this[key] = IntArrayConfigValue(config.getIntArray(key))
|
||||
KeyType.STRING -> this[key] = StringConfigValue(config.getString(key))
|
||||
}
|
||||
}
|
||||
@@ -195,6 +232,10 @@ class CarrierConfigRepository(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkIntArrayKey(key: String) {
|
||||
check(key.endsWith("_int_array")) { "Int array key should ends with _int_array" }
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun setBooleanForTest(subId: Int, key: String, value: Boolean) {
|
||||
checkBooleanKey(key)
|
||||
@@ -207,6 +248,12 @@ class CarrierConfigRepository(private val context: Context) {
|
||||
getPerSubCache(subId)[key] = IntConfigValue(value)
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun setIntArrayForTest(subId: Int, key: String, value: IntArray?) {
|
||||
checkIntArrayKey(key)
|
||||
getPerSubCache(subId)[key] = IntArrayConfigValue(value)
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun setStringForTest(subId: Int, key: String, value: String?) {
|
||||
check(key.endsWith("_string")) { "String key should ends with _string" }
|
||||
@@ -221,6 +268,8 @@ private data class BooleanConfigValue(val value: Boolean) : ConfigValue
|
||||
|
||||
private data class IntConfigValue(val value: Int) : ConfigValue
|
||||
|
||||
private class IntArrayConfigValue(val value: IntArray?) : ConfigValue
|
||||
|
||||
private data class StringConfigValue(val value: String?) : ConfigValue
|
||||
|
||||
private typealias ConfigCache = ConcurrentHashMap<String, ConfigValue>
|
||||
|
||||
@@ -34,7 +34,6 @@ import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
import com.android.internal.telephony.flags.Flags;
|
||||
import com.android.internal.telephony.util.ArrayUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.network.ims.VolteQueryImsState;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
@@ -56,8 +55,6 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc
|
||||
Preference mPreference;
|
||||
private PhoneCallStateTelephonyCallback mTelephonyCallback;
|
||||
private boolean mShow5gLimitedDialog;
|
||||
boolean mIsNrEnabledFromCarrierConfig;
|
||||
private boolean mHas5gCapability;
|
||||
private Integer mCallState;
|
||||
private final List<On4gLteUpdateListener> m4gLteListeners;
|
||||
|
||||
@@ -94,9 +91,6 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc
|
||||
mShow5gLimitedDialog = carrierConfig.getBoolean(
|
||||
CarrierConfigManager.KEY_VOLTE_5G_LIMITED_ALERT_DIALOG_BOOL);
|
||||
|
||||
int[] nrAvailabilities = carrierConfig.getIntArray(
|
||||
CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY);
|
||||
mIsNrEnabledFromCarrierConfig = !ArrayUtils.isEmpty(nrAvailabilities);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -247,10 +241,6 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc
|
||||
}
|
||||
mTelephonyManager.registerTelephonyCallback(
|
||||
mContext.getMainExecutor(), mTelephonyCallback);
|
||||
|
||||
final long supportedRadioBitmask = mTelephonyManager.getSupportedRadioAccessFamily();
|
||||
mHas5gCapability =
|
||||
(supportedRadioBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_NR) > 0;
|
||||
}
|
||||
|
||||
public void unregister() {
|
||||
@@ -269,8 +259,7 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc
|
||||
}
|
||||
|
||||
private boolean isDialogNeeded() {
|
||||
Log.d(TAG, "Has5gCapability:" + mHas5gCapability);
|
||||
return mShow5gLimitedDialog && mHas5gCapability && mIsNrEnabledFromCarrierConfig;
|
||||
return mShow5gLimitedDialog && new NrRepository(mContext).isNrAvailable(mSubId);
|
||||
}
|
||||
|
||||
private void show5gLimitedDialog(ImsMmTelManager imsMmTelManager) {
|
||||
|
||||
@@ -25,31 +25,28 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.android.settings.R
|
||||
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
|
||||
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
|
||||
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
|
||||
import com.android.settings.spa.preference.ComposePreferenceController
|
||||
import com.android.settingslib.spa.widget.preference.SwitchPreference
|
||||
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Preference controller for "Voice over NR".
|
||||
*/
|
||||
class NrAdvancedCallingPreferenceController @JvmOverloads constructor(
|
||||
/** Preference controller for "Voice over NR". */
|
||||
class NrAdvancedCallingPreferenceController
|
||||
@JvmOverloads
|
||||
constructor(
|
||||
context: Context,
|
||||
key: String,
|
||||
private val callStateRepository : CallStateRepository = CallStateRepository(context),
|
||||
private val voNrRepository: VoNrRepository = VoNrRepository(context),
|
||||
private val callStateRepository: CallStateRepository = CallStateRepository(context),
|
||||
) : ComposePreferenceController(context, key) {
|
||||
private var subId: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||
private var repository: VoNrRepository? = null
|
||||
private val searchItem = NrAdvancedCallingSearchItem(context)
|
||||
|
||||
/** Initial this PreferenceController. */
|
||||
@JvmOverloads
|
||||
fun init(subId: Int, repository: VoNrRepository = VoNrRepository(mContext, subId)) {
|
||||
fun init(subId: Int) {
|
||||
this.subId = subId
|
||||
this.repository = repository
|
||||
}
|
||||
|
||||
override fun getAvailabilityStatus() =
|
||||
@@ -58,30 +55,32 @@ class NrAdvancedCallingPreferenceController @JvmOverloads constructor(
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val summary = stringResource(R.string.nr_advanced_calling_summary)
|
||||
val isInCall by remember { callStateRepository.isInCallFlow() }
|
||||
.collectAsStateWithLifecycle(initialValue = false)
|
||||
val isEnabled by remember {
|
||||
repository?.isVoNrEnabledFlow() ?: flowOf(false)
|
||||
}.collectAsStateWithLifecycle(initialValue = false)
|
||||
val isInCall by
|
||||
remember { callStateRepository.isInCallFlow() }
|
||||
.collectAsStateWithLifecycle(initialValue = false)
|
||||
val isVoNrEnabled by
|
||||
remember { voNrRepository.isVoNrEnabledFlow(subId) }
|
||||
.collectAsStateWithLifecycle(initialValue = false)
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
SwitchPreference(object : SwitchPreferenceModel {
|
||||
override val title = stringResource(R.string.nr_advanced_calling_title)
|
||||
override val summary = { summary }
|
||||
override val changeable = { !isInCall }
|
||||
override val checked = { isEnabled }
|
||||
override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
|
||||
coroutineScope.launch {
|
||||
repository?.setVoNrEnabled(newChecked)
|
||||
SwitchPreference(
|
||||
object : SwitchPreferenceModel {
|
||||
override val title = stringResource(R.string.nr_advanced_calling_title)
|
||||
override val summary = { summary }
|
||||
override val changeable = { !isInCall }
|
||||
override val checked = { isVoNrEnabled }
|
||||
override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
|
||||
coroutineScope.launch { voNrRepository.setVoNrEnabled(subId, newChecked) }
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
class NrAdvancedCallingSearchItem(private val context: Context) :
|
||||
MobileNetworkSettingsSearchItem {
|
||||
private val voNrRepository = VoNrRepository(context)
|
||||
|
||||
fun isAvailable(subId: Int): Boolean = VoNrRepository(context, subId).isVoNrAvailable()
|
||||
fun isAvailable(subId: Int): Boolean = voNrRepository.isVoNrAvailable(subId)
|
||||
|
||||
override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? {
|
||||
if (!isAvailable(subId)) return null
|
||||
|
||||
50
src/com/android/settings/network/telephony/NrRepository.kt
Normal file
50
src/com/android/settings/network/telephony/NrRepository.kt
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.telephony.CarrierConfigManager
|
||||
import android.telephony.SubscriptionManager
|
||||
import android.telephony.TelephonyManager
|
||||
import android.util.Log
|
||||
|
||||
class NrRepository(private val context: Context) {
|
||||
private val carrierConfigRepository = CarrierConfigRepository(context)
|
||||
|
||||
fun isNrAvailable(subId: Int): Boolean {
|
||||
if (!SubscriptionManager.isValidSubscriptionId(subId) || !has5gCapability(subId)) {
|
||||
return false
|
||||
}
|
||||
val carrierNrAvailabilities =
|
||||
carrierConfigRepository.getIntArray(
|
||||
subId = subId,
|
||||
key = CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
|
||||
)
|
||||
return carrierNrAvailabilities?.isNotEmpty() ?: false
|
||||
}
|
||||
|
||||
private fun has5gCapability(subId: Int): Boolean {
|
||||
val telephonyManager = context.telephonyManager(subId)
|
||||
return (telephonyManager.supportedRadioAccessFamily and
|
||||
TelephonyManager.NETWORK_TYPE_BITMASK_NR > 0)
|
||||
.also { Log.d(TAG, "[$subId] has5gCapability: $it") }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val TAG = "NrRepository"
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ package com.android.settings.network.telephony
|
||||
import android.content.Context
|
||||
import android.telephony.CarrierConfigManager
|
||||
import android.telephony.SubscriptionManager
|
||||
import android.telephony.TelephonyManager
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -29,43 +28,43 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class VoNrRepository(private val context: Context, private val subId: Int) {
|
||||
private val telephonyManager = context.telephonyManager(subId)
|
||||
private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!!
|
||||
class VoNrRepository(
|
||||
private val context: Context,
|
||||
private val nrRepository: NrRepository = NrRepository(context),
|
||||
) {
|
||||
private val carrierConfigRepository = CarrierConfigRepository(context)
|
||||
|
||||
fun isVoNrAvailable(): Boolean {
|
||||
if (!SubscriptionManager.isValidSubscriptionId(subId) || !has5gCapability()) return false
|
||||
val carrierConfig = carrierConfigManager.safeGetConfig(
|
||||
keys = listOf(
|
||||
CarrierConfigManager.KEY_VONR_ENABLED_BOOL,
|
||||
CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL,
|
||||
CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
|
||||
),
|
||||
subId = subId,
|
||||
)
|
||||
return carrierConfig.getBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL) &&
|
||||
carrierConfig.getBoolean(CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL) &&
|
||||
(carrierConfig.getIntArray(CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY)
|
||||
?.isNotEmpty() ?: false)
|
||||
fun isVoNrAvailable(subId: Int): Boolean {
|
||||
if (!nrRepository.isNrAvailable(subId)) return false
|
||||
data class Config(val isVoNrEnabled: Boolean, val isVoNrSettingVisibility: Boolean)
|
||||
val carrierConfig =
|
||||
carrierConfigRepository.transformConfig(subId) {
|
||||
Config(
|
||||
isVoNrEnabled = getBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL),
|
||||
isVoNrSettingVisibility =
|
||||
getBoolean(CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL),
|
||||
)
|
||||
}
|
||||
return carrierConfig.isVoNrEnabled && carrierConfig.isVoNrSettingVisibility
|
||||
}
|
||||
|
||||
private fun has5gCapability() =
|
||||
((telephonyManager.supportedRadioAccessFamily and
|
||||
TelephonyManager.NETWORK_TYPE_BITMASK_NR) > 0)
|
||||
.also { Log.d(TAG, "[$subId] has5gCapability: $it") }
|
||||
|
||||
fun isVoNrEnabledFlow(): Flow<Boolean> = context.subscriptionsChangedFlow()
|
||||
.map { telephonyManager.isVoNrEnabled }
|
||||
.conflate()
|
||||
.onEach { Log.d(TAG, "[$subId] isVoNrEnabled: $it") }
|
||||
.flowOn(Dispatchers.Default)
|
||||
|
||||
suspend fun setVoNrEnabled(enabled: Boolean) = withContext(Dispatchers.Default) {
|
||||
if (!SubscriptionManager.isValidSubscriptionId(subId)) return@withContext
|
||||
val result = telephonyManager.setVoNrEnabled(enabled)
|
||||
Log.d(TAG, "[$subId] setVoNrEnabled: $enabled, result: $result")
|
||||
fun isVoNrEnabledFlow(subId: Int): Flow<Boolean> {
|
||||
val telephonyManager = context.telephonyManager(subId)
|
||||
return context
|
||||
.subscriptionsChangedFlow()
|
||||
.map { telephonyManager.isVoNrEnabled }
|
||||
.conflate()
|
||||
.onEach { Log.d(TAG, "[$subId] isVoNrEnabled: $it") }
|
||||
.flowOn(Dispatchers.Default)
|
||||
}
|
||||
|
||||
suspend fun setVoNrEnabled(subId: Int, enabled: Boolean) =
|
||||
withContext(Dispatchers.Default) {
|
||||
if (!SubscriptionManager.isValidSubscriptionId(subId)) return@withContext
|
||||
val result = context.telephonyManager(subId).setVoNrEnabled(enabled)
|
||||
Log.d(TAG, "[$subId] setVoNrEnabled: $enabled, result: $result")
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val TAG = "VoNrRepository"
|
||||
}
|
||||
|
||||
@@ -77,6 +77,19 @@ class CarrierConfigRepositoryTest {
|
||||
assertThat(value).isEqualTo(99)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getIntArray_returnValue() {
|
||||
val key = CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY
|
||||
mockCarrierConfigManager.stub {
|
||||
on { getConfigForSubId(any(), eq(key)) } doReturn
|
||||
persistableBundleOf(key to intArrayOf(99))
|
||||
}
|
||||
|
||||
val value = repository.getIntArray(SUB_ID, key)!!.toList()
|
||||
|
||||
assertThat(value).containsExactly(99)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getString_returnValue() {
|
||||
val key = CarrierConfigManager.KEY_CARRIER_NAME_STRING
|
||||
@@ -104,7 +117,8 @@ class CarrierConfigRepositoryTest {
|
||||
assertThat(carrierName)
|
||||
.isEqualTo(
|
||||
CarrierConfigManager.getDefaultConfig()
|
||||
.getInt(CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT))
|
||||
.getInt(CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -41,91 +41,77 @@ import org.mockito.kotlin.verify
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class NrAdvancedCallingPreferenceControllerTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
@get:Rule val composeTestRule = createComposeRule()
|
||||
|
||||
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {}
|
||||
|
||||
private val callStateRepository = mock<CallStateRepository> {
|
||||
on { isInCallFlow() } doReturn flowOf(false)
|
||||
}
|
||||
private val callStateRepository =
|
||||
mock<CallStateRepository> { on { isInCallFlow() } doReturn flowOf(false) }
|
||||
|
||||
private val voNrRepository = mock<VoNrRepository>()
|
||||
private val voNrRepository =
|
||||
mock<VoNrRepository> { on { isVoNrEnabledFlow(SUB_ID) } doReturn flowOf(true) }
|
||||
|
||||
private val controller = NrAdvancedCallingPreferenceController(
|
||||
context = context,
|
||||
key = TEST_KEY,
|
||||
callStateRepository = callStateRepository,
|
||||
).apply { init(SUB_ID, voNrRepository) }
|
||||
private val controller =
|
||||
NrAdvancedCallingPreferenceController(
|
||||
context = context,
|
||||
key = TEST_KEY,
|
||||
voNrRepository = voNrRepository,
|
||||
callStateRepository = callStateRepository,
|
||||
)
|
||||
.apply { init(SUB_ID) }
|
||||
|
||||
@Test
|
||||
fun isChecked_voNrEnabled_on() {
|
||||
voNrRepository.stub {
|
||||
on { isVoNrEnabledFlow() } doReturn flowOf(true)
|
||||
}
|
||||
voNrRepository.stub { on { isVoNrEnabledFlow(SUB_ID) } doReturn flowOf(true) }
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
composeTestRule.setContent { controller.Content() }
|
||||
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
|
||||
composeTestRule
|
||||
.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
|
||||
.assertIsOn()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isChecked_voNrDisabled_off() {
|
||||
voNrRepository.stub {
|
||||
on { isVoNrEnabledFlow() } doReturn flowOf(false)
|
||||
}
|
||||
voNrRepository.stub { on { isVoNrEnabledFlow(SUB_ID) } doReturn flowOf(false) }
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
composeTestRule.setContent { controller.Content() }
|
||||
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
|
||||
composeTestRule
|
||||
.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
|
||||
.assertIsOff()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isEnabled_notInCall_enabled() {
|
||||
callStateRepository.stub {
|
||||
on { isInCallFlow() } doReturn flowOf(false)
|
||||
}
|
||||
fun isChangeable_notInCall_changeable() {
|
||||
callStateRepository.stub { on { isInCallFlow() } doReturn flowOf(false) }
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
composeTestRule.setContent { controller.Content() }
|
||||
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
|
||||
composeTestRule
|
||||
.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
|
||||
.assertIsEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isEnabled_inCall_notEnabled() {
|
||||
callStateRepository.stub {
|
||||
on { isInCallFlow() } doReturn flowOf(true)
|
||||
}
|
||||
fun isChangeable_inCall_notChangeable() {
|
||||
callStateRepository.stub { on { isInCallFlow() } doReturn flowOf(true) }
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
composeTestRule.setContent { controller.Content() }
|
||||
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
|
||||
composeTestRule
|
||||
.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
|
||||
.assertIsNotEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onClick_setVoNrEnabled(): Unit = runBlocking {
|
||||
voNrRepository.stub {
|
||||
on { isVoNrEnabledFlow() } doReturn flowOf(false)
|
||||
}
|
||||
voNrRepository.stub { on { isVoNrEnabledFlow(SUB_ID) } doReturn flowOf(false) }
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
composeTestRule.setContent { controller.Content() }
|
||||
composeTestRule.onRoot().performClick()
|
||||
|
||||
verify(voNrRepository).setVoNrEnabled(true)
|
||||
verify(voNrRepository).setVoNrEnabled(SUB_ID, true)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.telephony.CarrierConfigManager
|
||||
import android.telephony.TelephonyManager
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
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
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class NrRepositoryTest {
|
||||
private val mockTelephonyManager =
|
||||
mock<TelephonyManager> {
|
||||
on { createForSubscriptionId(SUB_ID) } doReturn mock
|
||||
on { supportedRadioAccessFamily } doReturn TelephonyManager.NETWORK_TYPE_BITMASK_NR
|
||||
}
|
||||
|
||||
private val context: Context =
|
||||
spy(ApplicationProvider.getApplicationContext()) {
|
||||
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
|
||||
}
|
||||
|
||||
private val repository = NrRepository(context)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
CarrierConfigRepository.resetForTest()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNrAvailable_deviceNoNr_returnFalse() {
|
||||
mockTelephonyManager.stub {
|
||||
on { supportedRadioAccessFamily } doReturn TelephonyManager.NETWORK_TYPE_BITMASK_LTE
|
||||
}
|
||||
|
||||
val available = repository.isNrAvailable(SUB_ID)
|
||||
|
||||
assertThat(available).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNrAvailable_carrierConfigNrIsEmpty_returnFalse() {
|
||||
CarrierConfigRepository.setIntArrayForTest(
|
||||
subId = SUB_ID,
|
||||
key = CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
|
||||
value = intArrayOf(),
|
||||
)
|
||||
|
||||
val available = repository.isNrAvailable(SUB_ID)
|
||||
|
||||
assertThat(available).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNrAvailable_carrierConfigNrIsNull_returnFalse() {
|
||||
CarrierConfigRepository.setIntArrayForTest(
|
||||
subId = SUB_ID,
|
||||
key = CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
|
||||
value = null,
|
||||
)
|
||||
|
||||
val available = repository.isNrAvailable(SUB_ID)
|
||||
|
||||
assertThat(available).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNrAvailable_allEnabled_returnTrue() {
|
||||
mockTelephonyManager.stub {
|
||||
on { supportedRadioAccessFamily } doReturn TelephonyManager.NETWORK_TYPE_BITMASK_NR
|
||||
}
|
||||
CarrierConfigRepository.setIntArrayForTest(
|
||||
subId = SUB_ID,
|
||||
key = CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
|
||||
value = intArrayOf(1, 2),
|
||||
)
|
||||
|
||||
val available = repository.isNrAvailable(SUB_ID)
|
||||
|
||||
assertThat(available).isTrue()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val SUB_ID = 10
|
||||
}
|
||||
}
|
||||
@@ -19,17 +19,15 @@ package com.android.settings.network.telephony
|
||||
import android.content.Context
|
||||
import android.telephony.CarrierConfigManager
|
||||
import android.telephony.TelephonyManager
|
||||
import androidx.core.os.persistableBundleOf
|
||||
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.runBlocking
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.anyVararg
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.eq
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.stub
|
||||
@@ -38,127 +36,107 @@ import org.mockito.kotlin.verify
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class VoNrRepositoryTest {
|
||||
|
||||
private val mockTelephonyManager = mock<TelephonyManager> {
|
||||
on { createForSubscriptionId(SUB_ID) } doReturn mock
|
||||
on { supportedRadioAccessFamily } doReturn TelephonyManager.NETWORK_TYPE_BITMASK_NR
|
||||
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 mockNrRepository = mock<NrRepository> { on { isNrAvailable(SUB_ID) } doReturn true }
|
||||
|
||||
private val repository = VoNrRepository(context, mockNrRepository)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
CarrierConfigRepository.resetForTest()
|
||||
CarrierConfigRepository.setBooleanForTest(
|
||||
subId = SUB_ID,
|
||||
key = CarrierConfigManager.KEY_VONR_ENABLED_BOOL,
|
||||
value = true,
|
||||
)
|
||||
CarrierConfigRepository.setBooleanForTest(
|
||||
subId = SUB_ID,
|
||||
key = CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL,
|
||||
value = true,
|
||||
)
|
||||
}
|
||||
|
||||
private val carrierConfig = persistableBundleOf(
|
||||
CarrierConfigManager.KEY_VONR_ENABLED_BOOL to true,
|
||||
CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL to true,
|
||||
CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY to intArrayOf(1, 2),
|
||||
)
|
||||
|
||||
private val mockCarrierConfigManager = mock<CarrierConfigManager> {
|
||||
on { getConfigForSubId(eq(SUB_ID), anyVararg()) } doReturn carrierConfig
|
||||
}
|
||||
|
||||
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
|
||||
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
|
||||
on { getSystemService(CarrierConfigManager::class.java) } doReturn mockCarrierConfigManager
|
||||
}
|
||||
|
||||
private val repository = VoNrRepository(context, SUB_ID)
|
||||
|
||||
@Test
|
||||
fun isVoNrAvailable_visibleDisable_returnFalse() {
|
||||
carrierConfig.apply {
|
||||
putBoolean(CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL, false)
|
||||
}
|
||||
CarrierConfigRepository.setBooleanForTest(
|
||||
subId = SUB_ID,
|
||||
key = CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL,
|
||||
value = false,
|
||||
)
|
||||
|
||||
val available = repository.isVoNrAvailable()
|
||||
val available = repository.isVoNrAvailable(SUB_ID)
|
||||
|
||||
assertThat(available).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isVoNrAvailable_voNrDisabled_returnFalse() {
|
||||
carrierConfig.apply {
|
||||
putBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL, false)
|
||||
}
|
||||
CarrierConfigRepository.setBooleanForTest(
|
||||
subId = SUB_ID,
|
||||
key = CarrierConfigManager.KEY_VONR_ENABLED_BOOL,
|
||||
value = false,
|
||||
)
|
||||
|
||||
val available = repository.isVoNrAvailable()
|
||||
val available = repository.isVoNrAvailable(SUB_ID)
|
||||
|
||||
assertThat(available).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isVoNrAvailable_allEnabled_returnTrue() {
|
||||
mockTelephonyManager.stub {
|
||||
on { supportedRadioAccessFamily } doReturn TelephonyManager.NETWORK_TYPE_BITMASK_NR
|
||||
}
|
||||
carrierConfig.apply {
|
||||
putBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL, true)
|
||||
putBoolean(CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL, true)
|
||||
putIntArray(
|
||||
CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
|
||||
intArrayOf(1, 2),
|
||||
)
|
||||
}
|
||||
CarrierConfigRepository.setBooleanForTest(
|
||||
subId = SUB_ID,
|
||||
key = CarrierConfigManager.KEY_VONR_ENABLED_BOOL,
|
||||
value = true,
|
||||
)
|
||||
CarrierConfigRepository.setBooleanForTest(
|
||||
subId = SUB_ID,
|
||||
key = CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL,
|
||||
value = true,
|
||||
)
|
||||
|
||||
val available = repository.isVoNrAvailable()
|
||||
val available = repository.isVoNrAvailable(SUB_ID)
|
||||
|
||||
assertThat(available).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isVoNrAvailable_deviceNoNr_returnFalse() {
|
||||
mockTelephonyManager.stub {
|
||||
on { supportedRadioAccessFamily } doReturn TelephonyManager.NETWORK_TYPE_BITMASK_LTE
|
||||
}
|
||||
fun isVoNrAvailable_noNr_returnFalse() {
|
||||
mockNrRepository.stub { on { isNrAvailable(SUB_ID) } doReturn false }
|
||||
|
||||
val available = repository.isVoNrAvailable()
|
||||
|
||||
assertThat(available).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isVoNrAvailable_carrierNoNr_returnFalse() {
|
||||
carrierConfig.apply {
|
||||
putIntArray(CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, intArrayOf())
|
||||
}
|
||||
|
||||
val available = repository.isVoNrAvailable()
|
||||
|
||||
assertThat(available).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isVoNrAvailable_carrierConfigNrIsNull_returnFalse() {
|
||||
carrierConfig.apply {
|
||||
putIntArray(CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, null)
|
||||
}
|
||||
|
||||
val available = repository.isVoNrAvailable()
|
||||
val available = repository.isVoNrAvailable(SUB_ID)
|
||||
|
||||
assertThat(available).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isVoNrEnabledFlow_voNrDisabled() = runBlocking {
|
||||
mockTelephonyManager.stub {
|
||||
on { isVoNrEnabled } doReturn false
|
||||
}
|
||||
mockTelephonyManager.stub { on { isVoNrEnabled } doReturn false }
|
||||
|
||||
val isVoNrEnabled = repository.isVoNrEnabledFlow().firstWithTimeoutOrNull()
|
||||
val isVoNrEnabled = repository.isVoNrEnabledFlow(SUB_ID).firstWithTimeoutOrNull()
|
||||
|
||||
assertThat(isVoNrEnabled).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isVoNrEnabledFlow_voNrEnabled() = runBlocking {
|
||||
mockTelephonyManager.stub {
|
||||
on { isVoNrEnabled } doReturn true
|
||||
}
|
||||
mockTelephonyManager.stub { on { isVoNrEnabled } doReturn true }
|
||||
|
||||
val isVoNrEnabled = repository.isVoNrEnabledFlow().firstWithTimeoutOrNull()
|
||||
val isVoNrEnabled = repository.isVoNrEnabledFlow(SUB_ID).firstWithTimeoutOrNull()
|
||||
|
||||
assertThat(isVoNrEnabled).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setVoNrEnabled(): Unit = runBlocking {
|
||||
repository.setVoNrEnabled(true)
|
||||
repository.setVoNrEnabled(SUB_ID, true)
|
||||
|
||||
verify(mockTelephonyManager).setVoNrEnabled(true)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user