diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml
index 3c011098a9e..eb9f4427533 100644
--- a/res/xml/mobile_network_settings.xml
+++ b/res/xml/mobile_network_settings.xml
@@ -295,11 +295,9 @@
settings:controller=
"com.android.settings.network.telephony.NullAlgorithmsPreferenceController"/>
-
diff --git a/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceController.java b/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceController.java
deleted file mode 100644
index ecf01cb9484..00000000000
--- a/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceController.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2021 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.os.Handler;
-import android.os.Looper;
-import android.os.PersistableBundle;
-import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyCallback;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-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.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
-import com.android.settingslib.utils.ThreadUtils;
-
-/**
- * Preference controller for "Voice over NR".
- */
-public class NrAdvancedCallingPreferenceController extends TelephonyTogglePreferenceController
- implements LifecycleObserver, OnStart, OnStop {
-
- private static final String TAG = "VoNrSettings";
-
- @VisibleForTesting
- Preference mPreference;
- private TelephonyManager mTelephonyManager;
- private PhoneCallStateTelephonyCallback mTelephonyCallback;
- private boolean mIsVonrEnabledFromCarrierConfig = false;
- private boolean mIsVonrVisibleFromCarrierConfig = false;
- private boolean mIsNrEnableFromCarrierConfig = false;
- private boolean mHas5gCapability = false;
- private boolean mIsVoNrEnabled = false;
- private Integer mCallState;
-
- private Handler mHandler = new Handler(Looper.getMainLooper());
-
- public NrAdvancedCallingPreferenceController(Context context, String key) {
- super(context, key);
- mTelephonyManager = context.getSystemService(TelephonyManager.class);
- }
-
- /**
- * Initial this PreferenceController.
- * @param subId The subscription Id.
- * @return This PreferenceController.
- */
- public NrAdvancedCallingPreferenceController init(int subId) {
- Log.d(TAG, "init: ");
- if (mTelephonyCallback == null) {
- mTelephonyCallback = new PhoneCallStateTelephonyCallback();
- }
-
- mSubId = subId;
-
- if (mTelephonyManager == null) {
- mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
- }
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
- mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
- }
- long supportedRadioBitmask = mTelephonyManager.getSupportedRadioAccessFamily();
- mHas5gCapability =
- (supportedRadioBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_NR) > 0;
-
- PersistableBundle carrierConfig = getCarrierConfigForSubId(subId);
- if (carrierConfig == null) {
- return this;
- }
- mIsVonrEnabledFromCarrierConfig = carrierConfig.getBoolean(
- CarrierConfigManager.KEY_VONR_ENABLED_BOOL);
-
- mIsVonrVisibleFromCarrierConfig = carrierConfig.getBoolean(
- CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL);
-
- int[] nrAvailabilities = carrierConfig.getIntArray(
- CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY);
- mIsNrEnableFromCarrierConfig = !ArrayUtils.isEmpty(nrAvailabilities);
-
- updateVoNrState();
-
- Log.d(TAG, "mHas5gCapability: " + mHas5gCapability
- + ",mIsNrEnabledFromCarrierConfig: " + mIsNrEnableFromCarrierConfig
- + ",mIsVonrEnabledFromCarrierConfig: " + mIsVonrEnabledFromCarrierConfig
- + ",mIsVonrVisibleFromCarrierConfig: " + mIsVonrVisibleFromCarrierConfig);
- return this;
- }
-
- @Override
- public int getAvailabilityStatus(int subId) {
- init(subId);
-
- if (mHas5gCapability
- && mIsNrEnableFromCarrierConfig
- && mIsVonrEnabledFromCarrierConfig
- && mIsVonrVisibleFromCarrierConfig) {
- return AVAILABLE;
- }
- return CONDITIONALLY_UNAVAILABLE;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mPreference = screen.findPreference(getPreferenceKey());
- }
-
- @Override
- public void onStart() {
- if (mTelephonyCallback == null) {
- return;
- }
- mTelephonyCallback.register(mTelephonyManager);
- }
-
- @Override
- public void onStop() {
- if (mTelephonyCallback == null) {
- return;
- }
- mTelephonyCallback.unregister();
- }
-
- @Override
- public void updateState(Preference preference) {
- super.updateState(preference);
- if (preference == null) {
- return;
- }
- final TwoStatePreference switchPreference = (TwoStatePreference) preference;
- switchPreference.setEnabled(isUserControlAllowed());
- }
-
- @Override
- public boolean setChecked(boolean isChecked) {
- if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
- return false;
- }
- Log.d(TAG, "setChecked: " + isChecked);
- int result = mTelephonyManager.setVoNrEnabled(isChecked);
- if (result == TelephonyManager.ENABLE_VONR_SUCCESS) {
- return true;
- }
- Log.d(TAG, "Fail to set VoNR result= " + result + ". subId=" + mSubId);
- return false;
- }
-
- @Override
- public boolean isChecked() {
- return mIsVoNrEnabled;
- }
-
- @VisibleForTesting
- protected boolean isCallStateIdle() {
- return (mCallState != null) && (mCallState == TelephonyManager.CALL_STATE_IDLE);
- }
-
- private boolean isUserControlAllowed() {
- return isCallStateIdle();
- }
-
- private void updateVoNrState() {
- ThreadUtils.postOnBackgroundThread(() -> {
- boolean result = mTelephonyManager.isVoNrEnabled();
- if (result != mIsVoNrEnabled) {
- Log.i(TAG, "VoNr state : " + result);
- mIsVoNrEnabled = result;
- mHandler.post(() -> {
- updateState(mPreference);
- });
- }
- });
- }
-
- private class PhoneCallStateTelephonyCallback extends TelephonyCallback implements
- TelephonyCallback.CallStateListener {
-
- private TelephonyManager mLocalTelephonyManager;
-
- @Override
- public void onCallStateChanged(int state) {
- mCallState = state;
- updateState(mPreference);
- }
-
- public void register(TelephonyManager telephonyManager) {
- mLocalTelephonyManager = telephonyManager;
-
- // assign current call state so that it helps to show correct preference state even
- // before first onCallStateChanged() by initial registration.
- if (Flags.enforceTelephonyFeatureMappingForPublicApis()) {
- try {
- mCallState = mLocalTelephonyManager.getCallState();
- } catch (UnsupportedOperationException e) {
- // Device doesn't support FEATURE_TELEPHONY_CALLING
- mCallState = TelephonyManager.CALL_STATE_IDLE;
- }
- } else {
- mCallState = mLocalTelephonyManager.getCallState();
- }
- mLocalTelephonyManager.registerTelephonyCallback(
- mContext.getMainExecutor(), mTelephonyCallback);
- }
-
- public void unregister() {
- mCallState = null;
- if (mLocalTelephonyManager != null) {
- mLocalTelephonyManager.unregisterTelephonyCallback(this);
- }
- }
- }
-}
diff --git a/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceController.kt b/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceController.kt
new file mode 100644
index 00000000000..cf47c1f0cd3
--- /dev/null
+++ b/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceController.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.SubscriptionManager
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+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.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(
+ context: Context,
+ key: String,
+ private val callStateRepository : CallStateRepository = CallStateRepository(context),
+) : ComposePreferenceController(context, key) {
+ private var subId: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ private var repository: VoNrRepository? = null
+
+ /** Initial this PreferenceController. */
+ @JvmOverloads
+ fun init(subId: Int, repository: VoNrRepository = VoNrRepository(mContext, subId)) {
+ this.subId = subId
+ this.repository = repository
+ }
+
+ override fun getAvailabilityStatus() =
+ if (repository?.isVoNrAvailable() == true) AVAILABLE else CONDITIONALLY_UNAVAILABLE
+
+ @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 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)
+ }
+ }
+ })
+ }
+}
diff --git a/src/com/android/settings/network/telephony/VoNrRepository.kt b/src/com/android/settings/network/telephony/VoNrRepository.kt
new file mode 100644
index 00000000000..35af2844609
--- /dev/null
+++ b/src/com/android/settings/network/telephony/VoNrRepository.kt
@@ -0,0 +1,72 @@
+/*
+ * 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
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.flowOn
+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)!!
+
+ 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)
+ }
+
+ private fun has5gCapability() =
+ ((telephonyManager.supportedRadioAccessFamily and
+ TelephonyManager.NETWORK_TYPE_BITMASK_NR) > 0)
+ .also { Log.d(TAG, "[$subId] has5gCapability: $it") }
+
+ fun isVoNrEnabledFlow(): Flow = 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")
+ }
+
+ private companion object {
+ private const val TAG = "VoNrRepository"
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceControllerTest.kt
new file mode 100644
index 00000000000..418a00b057f
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceControllerTest.kt
@@ -0,0 +1,135 @@
+/*
+ * 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 androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsOff
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.runBlocking
+import org.junit.Rule
+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 NrAdvancedCallingPreferenceControllerTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {}
+
+ private val callStateRepository = mock {
+ on { isInCallFlow() } doReturn flowOf(false)
+ }
+
+ private val voNrRepository = mock()
+
+ private val controller = NrAdvancedCallingPreferenceController(
+ context = context,
+ key = TEST_KEY,
+ callStateRepository = callStateRepository,
+ ).apply { init(SUB_ID, voNrRepository) }
+
+ @Test
+ fun isChecked_voNrEnabled_on() {
+ voNrRepository.stub {
+ on { isVoNrEnabledFlow() } doReturn flowOf(true)
+ }
+
+ composeTestRule.setContent {
+ controller.Content()
+ }
+
+ composeTestRule.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
+ .assertIsOn()
+ }
+
+ @Test
+ fun isChecked_voNrDisabled_off() {
+ voNrRepository.stub {
+ on { isVoNrEnabledFlow() } doReturn flowOf(false)
+ }
+
+ composeTestRule.setContent {
+ controller.Content()
+ }
+
+ composeTestRule.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
+ .assertIsOff()
+ }
+
+ @Test
+ fun isEnabled_notInCall_enabled() {
+ callStateRepository.stub {
+ on { isInCallFlow() } doReturn flowOf(false)
+ }
+
+ composeTestRule.setContent {
+ controller.Content()
+ }
+
+ composeTestRule.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
+ .assertIsEnabled()
+ }
+
+ @Test
+ fun isEnabled_inCall_notEnabled() {
+ callStateRepository.stub {
+ on { isInCallFlow() } doReturn flowOf(true)
+ }
+
+ composeTestRule.setContent {
+ controller.Content()
+ }
+
+ composeTestRule.onNodeWithText(context.getString(R.string.nr_advanced_calling_title))
+ .assertIsNotEnabled()
+ }
+
+ @Test
+ fun onClick_setVoNrEnabled(): Unit = runBlocking {
+ voNrRepository.stub {
+ on { isVoNrEnabledFlow() } doReturn flowOf(false)
+ }
+
+ composeTestRule.setContent {
+ controller.Content()
+ }
+ composeTestRule.onRoot().performClick()
+
+ verify(voNrRepository).setVoNrEnabled(true)
+ }
+
+ private companion object {
+ const val TEST_KEY = "test_key"
+ const val SUB_ID = 2
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/VoNrRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/VoNrRepositoryTest.kt
new file mode 100644
index 00000000000..9c20afe5e85
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/VoNrRepositoryTest.kt
@@ -0,0 +1,169 @@
+/*
+ * 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.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.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
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+class VoNrRepositoryTest {
+
+ private val mockTelephonyManager = mock {
+ on { createForSubscriptionId(SUB_ID) } doReturn mock
+ on { supportedRadioAccessFamily } doReturn TelephonyManager.NETWORK_TYPE_BITMASK_NR
+ }
+
+ 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 {
+ 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)
+ }
+
+ val available = repository.isVoNrAvailable()
+
+ assertThat(available).isFalse()
+ }
+
+ @Test
+ fun isVoNrAvailable_voNrDisabled_returnFalse() {
+ carrierConfig.apply {
+ putBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL, false)
+ }
+
+ val available = repository.isVoNrAvailable()
+
+ 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),
+ )
+ }
+
+ val available = repository.isVoNrAvailable()
+
+ assertThat(available).isTrue()
+ }
+
+ @Test
+ fun isVoNrAvailable_deviceNoNr_returnFalse() {
+ mockTelephonyManager.stub {
+ on { supportedRadioAccessFamily } doReturn TelephonyManager.NETWORK_TYPE_BITMASK_LTE
+ }
+
+ 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()
+
+ assertThat(available).isFalse()
+ }
+
+ @Test
+ fun isVoNrEnabledFlow_voNrDisabled() = runBlocking {
+ mockTelephonyManager.stub {
+ on { isVoNrEnabled } doReturn false
+ }
+
+ val isVoNrEnabled = repository.isVoNrEnabledFlow().firstWithTimeoutOrNull()
+
+ assertThat(isVoNrEnabled).isFalse()
+ }
+
+ @Test
+ fun isVoNrEnabledFlow_voNrEnabled() = runBlocking {
+ mockTelephonyManager.stub {
+ on { isVoNrEnabled } doReturn true
+ }
+
+ val isVoNrEnabled = repository.isVoNrEnabledFlow().firstWithTimeoutOrNull()
+
+ assertThat(isVoNrEnabled).isTrue()
+ }
+
+ @Test
+ fun setVoNrEnabled(): Unit = runBlocking {
+ repository.setVoNrEnabled(true)
+
+ verify(mockTelephonyManager).setVoNrEnabled(true)
+ }
+
+ private companion object {
+ const val SUB_ID = 1
+ }
+}
diff --git a/tests/unit/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceControllerTest.java
deleted file mode 100644
index e4c486f6487..00000000000
--- a/tests/unit/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceControllerTest.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2021 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 static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.PersistableBundle;
-import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-
-import androidx.preference.TwoStatePreference;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.settings.core.BasePreferenceController;
-import com.android.settings.network.CarrierConfigCache;
-import com.android.settingslib.RestrictedSwitchPreference;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-public class NrAdvancedCallingPreferenceControllerTest {
- private static final int SUB_ID = 2;
-
- @Mock
- private TelephonyManager mTelephonyManager;
- @Mock
- private TelephonyManager mInvalidTelephonyManager;
- @Mock
- private SubscriptionManager mSubscriptionManager;
- @Mock
- private CarrierConfigCache mCarrierConfigCache;
-
- private NrAdvancedCallingPreferenceController mController;
- private TwoStatePreference mPreference;
- private PersistableBundle mCarrierConfig;
- private Context mContext;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mContext = spy(ApplicationProvider.getApplicationContext());
- when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
- when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
- CarrierConfigCache.setTestInstance(mContext, mCarrierConfigCache);
-
- doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
- doReturn(mInvalidTelephonyManager).when(mTelephonyManager).createForSubscriptionId(
- SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- doReturn(TelephonyManager.NETWORK_TYPE_BITMASK_NR).when(
- mTelephonyManager).getSupportedRadioAccessFamily();
- doReturn(false).when(mTelephonyManager).isVoNrEnabled();
- doReturn(TelephonyManager.ENABLE_VONR_REQUEST_NOT_SUPPORTED).when(
- mTelephonyManager).setVoNrEnabled(anyBoolean());
- mCarrierConfig = new PersistableBundle();
- doReturn(mCarrierConfig).when(mCarrierConfigCache).getConfigForSubId(SUB_ID);
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL, false);
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL, true);
- mCarrierConfig.putIntArray(CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
- new int[]{1, 2});
-
- mPreference = new RestrictedSwitchPreference(mContext);
- mController = spy(new NrAdvancedCallingPreferenceController(mContext, "VoNr"));
- mController.init(SUB_ID);
- doReturn(true).when(mController).isCallStateIdle();
- mPreference.setKey(mController.getPreferenceKey());
- }
-
- @Test
- public void getAvailabilityStatus_vonrEnabledAndVisibleDisable_returnUnavailable() {
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL, true);
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL, false);
-
- mController.init(SUB_ID);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_vonrDisabledAndVisibleDisable_returnUnavailable() {
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL, false);
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL, false);
-
- mController.init(SUB_ID);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_vonrDisabledAndVisibleEnable_returnUnavailable() {
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL, false);
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL, true);
-
- mController.init(SUB_ID);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_vonrEnabledAndVisibleEnable_returnAvailable() {
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL, true);
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_VONR_SETTING_VISIBILITY_BOOL, true);
-
- mController.init(SUB_ID);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- BasePreferenceController.AVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_deviceNoNr_returnUnavailable() {
- doReturn(TelephonyManager.NETWORK_TYPE_BITMASK_LTE).when(
- mTelephonyManager).getSupportedRadioAccessFamily();
-
- mController.init(SUB_ID);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_carrierNoNr_returnUnavailable() {
- mCarrierConfig.putIntArray(CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
- new int[0]);
-
- mController.init(SUB_ID);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_carrierConfigNrIsNull_returnUnavailable() {
- mCarrierConfig.putIntArray(CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
- null);
-
- mController.init(SUB_ID);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
- }
-
- @Test
- public void updateState_callStateNotIdle_prefDisabled() {
- doReturn(false).when(mController).isCallStateIdle();
- mPreference.setEnabled(true);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isFalse();
- }
-
- @Test
- @Ignore("b/339542743")
- public void updateState_configOn_prefChecked() {
- doReturn(TelephonyManager.ENABLE_VONR_SUCCESS).when(
- mTelephonyManager).setVoNrEnabled(anyBoolean());
- doReturn(true).when(mTelephonyManager).isVoNrEnabled();
- mPreference.setChecked(false);
-
- mController.init(SUB_ID);
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isTrue();
- }
-}