diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml index 62a88b75646..038688e390c 100644 --- a/res/xml/mobile_network_settings.xml +++ b/res/xml/mobile_network_settings.xml @@ -210,7 +210,7 @@ android:title="@string/network_operator_category" settings:controller="com.android.settings.network.telephony.NetworkPreferenceCategoryController"> - diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index dbe8ae86817..0812ccc83cd 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -276,7 +276,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme use(OpenNetworkSelectPagePreferenceController.class).init(mSubId); final AutoSelectPreferenceController autoSelectPreferenceController = use(AutoSelectPreferenceController.class) - .init(getLifecycle(), mSubId) + .init(mSubId) .addListener(openNetworkSelectPagePreferenceController); use(NetworkPreferenceCategoryController.class).init(mSubId) .setChildren(Arrays.asList(autoSelectPreferenceController)); diff --git a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java deleted file mode 100644 index 36e2aa8e935..00000000000 --- a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2018 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.gsm; - -import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME; - -import android.app.ProgressDialog; -import android.content.Context; -import android.content.Intent; -import android.os.Handler; -import android.os.HandlerExecutor; -import android.os.Looper; -import android.os.PersistableBundle; -import android.os.SystemClock; -import android.provider.Settings; -import android.telephony.CarrierConfigManager; -import android.telephony.ServiceState; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; -import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleEventObserver; -import androidx.lifecycle.LifecycleOwner; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; -import androidx.preference.TwoStatePreference; - -import com.android.settings.R; -import com.android.settings.network.AllowedNetworkTypesListener; -import com.android.settings.network.CarrierConfigCache; -import com.android.settings.network.helper.ServiceStateStatus; -import com.android.settings.network.telephony.MobileNetworkUtils; -import com.android.settings.network.telephony.TelephonyTogglePreferenceController; -import com.android.settingslib.utils.ThreadUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Preference controller for "Auto Select Network" - */ -public class AutoSelectPreferenceController extends TelephonyTogglePreferenceController - implements LifecycleEventObserver{ - private static final long MINIMUM_DIALOG_TIME_MILLIS = TimeUnit.SECONDS.toMillis(1); - private static final String LOG_TAG = "AutoSelectPreferenceController"; - private static final String INTERNAL_LOG_TAG_ONRESUME = "OnResume"; - private static final String INTERNAL_LOG_TAG_AFTERSET = "AfterSet"; - - private final Handler mUiHandler; - private PreferenceScreen mPreferenceScreen; - private AllowedNetworkTypesListener mAllowedNetworkTypesListener; - private TelephonyManager mTelephonyManager; - private boolean mOnlyAutoSelectInHome; - private List mListeners; - @VisibleForTesting - ProgressDialog mProgressDialog; - @VisibleForTesting - TwoStatePreference mSwitchPreference; - private AtomicBoolean mUpdatingConfig; - private int mCacheOfModeStatus; - private AtomicLong mRecursiveUpdate; - ServiceStateStatus mServiceStateStatus; - - public AutoSelectPreferenceController(Context context, String key) { - super(context, key); - mTelephonyManager = context.getSystemService(TelephonyManager.class); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - mRecursiveUpdate = new AtomicLong(); - mUpdatingConfig = new AtomicBoolean(); - mCacheOfModeStatus = TelephonyManager.NETWORK_SELECTION_MODE_UNKNOWN; - mListeners = new ArrayList<>(); - mUiHandler = new Handler(Looper.getMainLooper()); - mAllowedNetworkTypesListener = new AllowedNetworkTypesListener( - new HandlerExecutor(mUiHandler)); - mAllowedNetworkTypesListener.setAllowedNetworkTypesListener( - () -> updatePreference()); - } - - private void updatePreference() { - if (mPreferenceScreen != null) { - displayPreference(mPreferenceScreen); - } - if (mSwitchPreference != null) { - mRecursiveUpdate.getAndIncrement(); - updateState(mSwitchPreference); - mRecursiveUpdate.decrementAndGet(); - } - } - - /** - * Implementation of LifecycleEventObserver. - */ - @SuppressWarnings("FutureReturnValueIgnored") - public void onStateChanged(@NonNull LifecycleOwner lifecycleOwner, - @NonNull Lifecycle.Event event) { - switch (event) { - case ON_START: - mAllowedNetworkTypesListener.register(mContext, mSubId); - break; - case ON_RESUME: - ThreadUtils.postOnBackgroundThread(() -> { - queryNetworkSelectionMode(INTERNAL_LOG_TAG_ONRESUME); - //Update UI in UI thread - mUiHandler.post(() -> { - if (mSwitchPreference != null) { - mRecursiveUpdate.getAndIncrement(); - mSwitchPreference.setChecked(isChecked()); - mRecursiveUpdate.decrementAndGet(); - updateListenerValue(); - } - }); - }); - break; - case ON_STOP: - mAllowedNetworkTypesListener.unregister(mContext, mSubId); - break; - default: - // Do nothing - break; - } - } - - @Override - public int getAvailabilityStatus(int subId) { - return MobileNetworkUtils.shouldDisplayNetworkSelectOptions(mContext, subId) - ? AVAILABLE - : CONDITIONALLY_UNAVAILABLE; - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mPreferenceScreen = screen; - mSwitchPreference = screen.findPreference(getPreferenceKey()); - } - - @Override - public boolean isChecked() { - return mCacheOfModeStatus == TelephonyManager.NETWORK_SELECTION_MODE_AUTO; - } - - @Override - public void updateState(Preference preference) { - super.updateState(preference); - - preference.setSummary(null); - final ServiceState serviceState = mTelephonyManager.getServiceState(); - if (serviceState == null) { - preference.setEnabled(false); - return; - } - - if (serviceState.getRoaming()) { - preference.setEnabled(true); - } else { - preference.setEnabled(!mOnlyAutoSelectInHome); - if (mOnlyAutoSelectInHome) { - preference.setSummary(mContext.getString( - R.string.manual_mode_disallowed_summary, - mTelephonyManager.getSimOperatorName())); - } - } - } - - @Override - public boolean setChecked(boolean isChecked) { - if (mRecursiveUpdate.get() != 0) { - // Changing from software are allowed and changing presentation only. - return true; - } - if (isChecked) { - setAutomaticSelectionMode(); - } else { - if (mSwitchPreference != null) { - Intent intent = new Intent(); - intent.setClassName(SETTINGS_PACKAGE_NAME, - SETTINGS_PACKAGE_NAME + ".Settings$NetworkSelectActivity"); - intent.putExtra(Settings.EXTRA_SUB_ID, mSubId); - mSwitchPreference.setIntent(intent); - } - } - return false; - } - - @VisibleForTesting - Future setAutomaticSelectionMode() { - final long startMillis = SystemClock.elapsedRealtime(); - showAutoSelectProgressBar(); - if (mSwitchPreference != null) { - mSwitchPreference.setIntent(null); - mSwitchPreference.setEnabled(false); - } - return ThreadUtils.postOnBackgroundThread(() -> { - // set network selection mode in background - mUpdatingConfig.set(true); - mTelephonyManager.setNetworkSelectionModeAutomatic(); - mUpdatingConfig.set(false); - - //Update UI in UI thread - final long durationMillis = SystemClock.elapsedRealtime() - startMillis; - - mUiHandler.postDelayed(() -> { - ThreadUtils.postOnBackgroundThread(() -> { - queryNetworkSelectionMode(INTERNAL_LOG_TAG_AFTERSET); - - //Update UI in UI thread - mUiHandler.post(() -> { - mRecursiveUpdate.getAndIncrement(); - if (mSwitchPreference != null) { - mSwitchPreference.setEnabled(true); - mSwitchPreference.setChecked(isChecked()); - } - mRecursiveUpdate.decrementAndGet(); - updateListenerValue(); - dismissProgressBar(); - }); - }); - }, Math.max(MINIMUM_DIALOG_TIME_MILLIS - durationMillis, 0)); - }); - } - - /** - * Initialization based on given subscription id. - **/ - public AutoSelectPreferenceController init(Lifecycle lifecycle, int subId) { - mSubId = subId; - mTelephonyManager = mContext.getSystemService(TelephonyManager.class) - .createForSubscriptionId(mSubId); - final PersistableBundle carrierConfig = - CarrierConfigCache.getInstance(mContext).getConfigForSubId(mSubId); - mOnlyAutoSelectInHome = carrierConfig != null - ? carrierConfig.getBoolean( - CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL) - : false; - - mServiceStateStatus = new ServiceStateStatus(lifecycle, mTelephonyManager, - new HandlerExecutor(mUiHandler)) { - @Override - protected void setValue(ServiceState status) { - if (status == null) { - return; - } - updateUiAutoSelectValue(status); - } - }; - return this; - } - - public AutoSelectPreferenceController addListener(OnNetworkSelectModeListener lsn) { - mListeners.add(lsn); - - return this; - } - - private void queryNetworkSelectionMode(String tag) { - mCacheOfModeStatus = mTelephonyManager.getNetworkSelectionMode(); - Log.d(LOG_TAG, tag + ": query command done. mCacheOfModeStatus: " + mCacheOfModeStatus); - } - - @VisibleForTesting - void updateUiAutoSelectValue(ServiceState status) { - if (status == null) { - return; - } - if (!mUpdatingConfig.get()) { - int networkSelectionMode = status.getIsManualSelection() - ? TelephonyManager.NETWORK_SELECTION_MODE_MANUAL - : TelephonyManager.NETWORK_SELECTION_MODE_AUTO; - if (mCacheOfModeStatus == networkSelectionMode) { - return; - } - mCacheOfModeStatus = networkSelectionMode; - Log.d(LOG_TAG, "updateUiAutoSelectValue: mCacheOfModeStatus: " + mCacheOfModeStatus); - - mRecursiveUpdate.getAndIncrement(); - updateState(mSwitchPreference); - mRecursiveUpdate.decrementAndGet(); - updateListenerValue(); - } - } - - private void updateListenerValue() { - for (OnNetworkSelectModeListener lsn : mListeners) { - lsn.onNetworkSelectModeUpdated(mCacheOfModeStatus); - } - } - - private void showAutoSelectProgressBar() { - if (mProgressDialog == null) { - mProgressDialog = new ProgressDialog(mContext); - mProgressDialog.setMessage( - mContext.getResources().getString(R.string.register_automatically)); - mProgressDialog.setCanceledOnTouchOutside(false); - mProgressDialog.setCancelable(false); - mProgressDialog.setIndeterminate(true); - } - mProgressDialog.show(); - } - - private void dismissProgressBar() { - if (mProgressDialog != null && mProgressDialog.isShowing()) { - try { - mProgressDialog.dismiss(); - } catch (IllegalArgumentException e) { - // Ignore exception since the dialog will be gone anyway. - } - } - } - - /** - * Callback when network select mode might get updated - * - * @see TelephonyManager#getNetworkSelectionMode() - */ - public interface OnNetworkSelectModeListener { - void onNetworkSelectModeUpdated(int mode); - } -} diff --git a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt new file mode 100644 index 00000000000..1ed9d9aceda --- /dev/null +++ b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt @@ -0,0 +1,224 @@ +/* + * 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.telephony.gsm + +import android.app.ProgressDialog +import android.content.Context +import android.content.Intent +import android.os.PersistableBundle +import android.provider.Settings +import android.telephony.CarrierConfigManager +import android.telephony.ServiceState +import android.telephony.TelephonyManager +import androidx.annotation.VisibleForTesting +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.LifecycleOwner +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.preference.Preference +import androidx.preference.PreferenceScreen +import com.android.settings.R +import com.android.settings.Settings.NetworkSelectActivity +import com.android.settings.network.CarrierConfigCache +import com.android.settings.network.telephony.MobileNetworkUtils +import com.android.settings.network.telephony.allowedNetworkTypesFlow +import com.android.settings.network.telephony.serviceStateFlow +import com.android.settings.spa.preference.ComposePreferenceController +import com.android.settingslib.spa.framework.compose.OverridableFlow +import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle +import com.android.settingslib.spa.widget.preference.SwitchPreference +import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel +import kotlin.properties.Delegates.notNull +import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** + * Preference controller for "Auto Select Network" + */ +class AutoSelectPreferenceController @JvmOverloads constructor( + context: Context, + key: String, + private val allowedNetworkTypesFlowFactory: (subId: Int) -> Flow = + context::allowedNetworkTypesFlow, + private val serviceStateFlowFactory: (subId: Int) -> Flow = + context::serviceStateFlow, + private val getConfigForSubId: (subId: Int) -> PersistableBundle = { subId -> + CarrierConfigCache.getInstance(context).getConfigForSubId(subId) + }, +) : ComposePreferenceController(context, key) { + + private lateinit var telephonyManager: TelephonyManager + private val listeners = mutableListOf() + + @VisibleForTesting + var progressDialog: ProgressDialog? = null + + private lateinit var preference: Preference + + private var subId by notNull() + + /** + * Initialization based on given subscription id. + */ + fun init(subId: Int): AutoSelectPreferenceController { + this.subId = subId + telephonyManager = mContext.getSystemService(TelephonyManager::class.java)!! + .createForSubscriptionId(subId) + + return this + } + + override fun getAvailabilityStatus() = + if (MobileNetworkUtils.shouldDisplayNetworkSelectOptions(mContext, subId)) AVAILABLE + else CONDITIONALLY_UNAVAILABLE + + override fun displayPreference(screen: PreferenceScreen) { + super.displayPreference(screen) + preference = screen.findPreference(preferenceKey)!! + } + + @Composable + override fun Content() { + val coroutineScope = rememberCoroutineScope() + val serviceStateFlow = remember { + serviceStateFlowFactory(subId) + .stateIn(coroutineScope, SharingStarted.Lazily, null) + .filterNotNull() + } + val isAutoOverridableFlow = remember { + OverridableFlow(serviceStateFlow.map { !it.isManualSelection }) + } + val isAuto by isAutoOverridableFlow.flow + .onEach(::updateListenerValue) + .collectAsStateWithLifecycle(initialValue = null) + val disallowedSummary by serviceStateFlow.map(::getDisallowedSummary) + .collectAsStateWithLifecycle(initialValue = "") + SwitchPreference(object : SwitchPreferenceModel { + override val title = stringResource(R.string.select_automatically) + override val summary = { disallowedSummary } + override val changeable = { disallowedSummary.isEmpty() } + override val checked = { isAuto } + override val onCheckedChange: (Boolean) -> Unit = { newChecked -> + if (newChecked) { + coroutineScope.launch { setAutomaticSelectionMode(isAutoOverridableFlow) } + } else { + mContext.startActivity(Intent().apply { + setClass(mContext, NetworkSelectActivity::class.java) + putExtra(Settings.EXTRA_SUB_ID, subId) + }) + } + } + }) + } + + private suspend fun getDisallowedSummary(serviceState: ServiceState): String = + withContext(Dispatchers.Default) { + if (!serviceState.roaming && onlyAutoSelectInHome()) { + mContext.getString( + R.string.manual_mode_disallowed_summary, + telephonyManager.simOperatorName + ) + } else "" + } + + private fun onlyAutoSelectInHome(): Boolean = + getConfigForSubId(subId) + .getBoolean(CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL) + + private suspend fun setAutomaticSelectionMode(overrideChannel: OverridableFlow) { + showAutoSelectProgressBar() + + withContext(Dispatchers.Default) { + val minimumDialogTimeDeferred = async { delay(MINIMUM_DIALOG_TIME) } + telephonyManager.setNetworkSelectionModeAutomatic() + minimumDialogTimeDeferred.await() + } + overrideChannel.override(true) + + dismissProgressBar() + } + + override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) { + allowedNetworkTypesFlowFactory(subId).collectLatestWithLifecycle(viewLifecycleOwner) { + preference.isVisible = withContext(Dispatchers.Default) { + MobileNetworkUtils.shouldDisplayNetworkSelectOptions(mContext, subId) + } + } + } + + fun addListener(listener: OnNetworkSelectModeListener): AutoSelectPreferenceController { + listeners.add(listener) + return this + } + + private fun updateListenerValue(isAuto: Boolean) { + for (listener in listeners) { + listener.onNetworkSelectModeUpdated( + if (isAuto) TelephonyManager.NETWORK_SELECTION_MODE_AUTO + else TelephonyManager.NETWORK_SELECTION_MODE_MANUAL + ) + } + } + + private fun showAutoSelectProgressBar() { + if (progressDialog == null) { + progressDialog = ProgressDialog(mContext).apply { + setMessage(mContext.resources.getString(R.string.register_automatically)) + setCanceledOnTouchOutside(false) + setCancelable(false) + isIndeterminate = true + } + } + progressDialog?.show() + } + + private fun dismissProgressBar() { + if (progressDialog?.isShowing == true) { + try { + progressDialog?.dismiss() + } catch (e: IllegalArgumentException) { + // Ignore exception since the dialog will be gone anyway. + } + } + } + + /** + * Callback when network select mode might get updated + * + * @see TelephonyManager.getNetworkSelectionMode + */ + interface OnNetworkSelectModeListener { + fun onNetworkSelectModeUpdated(mode: Int) + } + + companion object { + private val MINIMUM_DIALOG_TIME = 1.seconds + } +} diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt new file mode 100644 index 00000000000..f821e1a76fd --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt @@ -0,0 +1,197 @@ +/* + * 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.telephony.gsm + +import android.content.Context +import android.content.Intent +import android.provider.Settings +import android.telephony.CarrierConfigManager +import android.telephony.ServiceState +import android.telephony.TelephonyManager +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.core.os.persistableBundleOf +import androidx.preference.PreferenceManager +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settings.Settings.NetworkSelectActivity +import com.android.settings.spa.preference.ComposePreference +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.runBlocking +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.doNothing +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(AndroidJUnit4::class) +class AutoSelectPreferenceControllerTest { + @get:Rule + val composeTestRule = createComposeRule() + + private val mockTelephonyManager = mock { + on { createForSubscriptionId(SUB_ID) } doReturn mock + on { simOperatorName } doReturn OPERATOR_NAME + } + + private val context: Context = spy(ApplicationProvider.getApplicationContext()) { + on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager + doNothing().whenever(mock).startActivity(any()) + } + + private val preference = ComposePreference(context).apply { key = TEST_KEY } + private val preferenceScreen = PreferenceManager(context).createPreferenceScreen(context) + + private val serviceState = ServiceState() + + private val carrierConfig = persistableBundleOf() + + private val controller = AutoSelectPreferenceController( + context = context, + key = TEST_KEY, + allowedNetworkTypesFlowFactory = { emptyFlow() }, + serviceStateFlowFactory = { flowOf(serviceState) }, + getConfigForSubId = { carrierConfig }, + ).init(subId = SUB_ID) + + @Before + fun setUp() { + preferenceScreen.addPreference(preference) + controller.displayPreference(preferenceScreen) + } + + @Test + fun isChecked_isAutoSelection_on() { + serviceState.isManualSelection = false + + composeTestRule.setContent { + controller.Content() + } + + composeTestRule.onNodeWithText(context.getString(R.string.select_automatically)) + .assertIsOn() + } + + @Test + fun isChecked_isManualSelection_off() { + serviceState.isManualSelection = true + + composeTestRule.setContent { + controller.Content() + } + + composeTestRule.onNodeWithText(context.getString(R.string.select_automatically)) + .assertIsOff() + } + + + @Test + fun isEnabled_isRoaming_enabled() { + serviceState.roaming = true + + composeTestRule.setContent { + controller.Content() + } + + composeTestRule.onNodeWithText(context.getString(R.string.select_automatically)) + .assertIsEnabled() + } + + @Test + fun isEnabled_notOnlyAutoSelectInHome_enabled() { + serviceState.roaming = false + carrierConfig.putBoolean( + CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL, false + ) + + composeTestRule.setContent { + controller.Content() + } + + composeTestRule.onNodeWithText(context.getString(R.string.select_automatically)) + .assertIsEnabled() + } + + @Test + fun isEnabled_onlyAutoSelectInHome_notEnabled() { + serviceState.roaming = false + carrierConfig.putBoolean( + CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL, true + ) + + composeTestRule.setContent { + controller.Content() + } + + composeTestRule.onNodeWithText("Unavailable when connected to T-mobile") + .assertIsNotEnabled() + } + + @Test + fun onClick_turnOff_startNetworkSelectActivity() { + serviceState.isManualSelection = false + + composeTestRule.setContent { + controller.Content() + } + composeTestRule.onRoot().performClick() + + val intent = argumentCaptor { + verify(context).startActivity(capture()) + }.firstValue + assertThat(intent.component!!.className).isEqualTo(NetworkSelectActivity::class.java.name) + assertThat(intent.getIntExtra(Settings.EXTRA_SUB_ID, 0)).isEqualTo(SUB_ID) + } + + @Test + fun onClick_turnOn_setNetworkSelectionModeAutomatic() = runBlocking { + serviceState.isManualSelection = true + controller.progressDialog = mock() + + composeTestRule.setContent { + controller.Content() + } + composeTestRule.onRoot().performClick() + delay(100) + + verify(controller.progressDialog!!).show() + verify(mockTelephonyManager).setNetworkSelectionModeAutomatic() + } + + private companion object { + const val TEST_KEY = "test_key" + const val SUB_ID = 2 + const val OPERATOR_NAME = "T-mobile" + } +} diff --git a/tests/unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java deleted file mode 100644 index 39f2050b7f7..00000000000 --- a/tests/unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2020 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.gsm; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.ProgressDialog; -import android.content.Context; -import android.os.PersistableBundle; -import android.telephony.CarrierConfigManager; -import android.telephony.ServiceState; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; - -import androidx.lifecycle.Lifecycle; -import androidx.preference.SwitchPreference; -import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.android.settings.network.CarrierConfigCache; -import com.android.settings.testutils.ResourcesUtils; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Answers; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -@RunWith(AndroidJUnit4.class) -public class AutoSelectPreferenceControllerTest { - private static final int SUB_ID = 2; - private static final String OPERATOR_NAME = "T-mobile"; - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private TelephonyManager mTelephonyManager; - @Mock - private SubscriptionManager mSubscriptionManager; - @Mock - private CarrierConfigCache mCarrierConfigCache; - @Mock - private ProgressDialog mProgressDialog; - @Mock - private ServiceState mTestServiceState; - @Mock - private Lifecycle mLifecycle; - - private PersistableBundle mCarrierConfig; - private AutoSelectPreferenceController mController; - private SwitchPreference mSwitchPreference; - 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); - when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager); - - mCarrierConfig = new PersistableBundle(); - mCarrierConfig.putBoolean(CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL, - true); - when(mCarrierConfigCache.getConfigForSubId(SUB_ID)).thenReturn(mCarrierConfig); - - mSwitchPreference = new SwitchPreference(mContext); - mController = new AutoSelectPreferenceController(mContext, "auto_select"); - mController.mProgressDialog = mProgressDialog; - mController.mSwitchPreference = mSwitchPreference; - mController.init(mLifecycle, SUB_ID); - sleepAfterInit(); - } - - private void sleepAfterInit() { - try { - Thread.sleep(2000); - } catch (Exception e) { - fail("Sleep timeout " + e); - } - } - - @Test - public void setChecked_isChecked_showProgressDialog() { - when(mTelephonyManager.getNetworkSelectionMode()).thenReturn( - TelephonyManager.NETWORK_SELECTION_MODE_AUTO); - - // Wait for asynchronous thread to finish, otherwise test will flake. - Future thread = mController.setAutomaticSelectionMode(); - try { - thread.get(); - } catch (ExecutionException | InterruptedException e) { - e.printStackTrace(); - fail("Exception during automatic selection"); - } - - verify(mProgressDialog).show(); - verify(mTelephonyManager).setNetworkSelectionModeAutomatic(); - } - - @Test - public void updateState_isRoaming_enabled() { - when(mTelephonyManager.getServiceState()).thenReturn(mTestServiceState); - when(mTestServiceState.getRoaming()).thenReturn(true); - - mController.updateState(mSwitchPreference); - - assertThat(mSwitchPreference.isEnabled()).isTrue(); - } - - @Test - public void updateState_notRoamingWithAutoSelectOn_disabled() { - when(mTelephonyManager.getServiceState()).thenReturn(mTestServiceState); - when(mTestServiceState.getRoaming()).thenReturn(false); - doReturn(OPERATOR_NAME).when(mTelephonyManager).getSimOperatorName(); - - mController.updateState(mSwitchPreference); - - assertThat(mSwitchPreference.isEnabled()).isFalse(); - assertThat(mSwitchPreference.getSummary()).isEqualTo( - ResourcesUtils.getResourcesString(mContext, "manual_mode_disallowed_summary", - mTelephonyManager.getSimOperatorName())); - } - - @Test - public void init_carrierConfigNull_shouldNotCrash() { - when(mCarrierConfigCache.getConfigForSubId(SUB_ID)).thenReturn(null); - - // Should not crash - mController.init(mLifecycle, SUB_ID); - } - - @Test - public void updateUiAutoSelectValue_serviceStateGetIsManualSelection_isCheckedFalse() { - when(mTelephonyManager.getNetworkSelectionMode()).thenReturn( - TelephonyManager.NETWORK_SELECTION_MODE_AUTO); - when(mTestServiceState.getIsManualSelection()).thenReturn(true); - mController.init(mLifecycle, SUB_ID); - sleepAfterInit(); - - mController.updateUiAutoSelectValue(mTestServiceState); - - assertThat(mController.isChecked()).isFalse(); - assertThat(mSwitchPreference.isChecked()).isFalse(); - } - - @Test - public void updateUiAutoSelectValue_serviceStateGetIsAutoSelection_isCheckedTrue() { - when(mTelephonyManager.getNetworkSelectionMode()).thenReturn( - TelephonyManager.NETWORK_SELECTION_MODE_MANUAL); - when(mTestServiceState.getIsManualSelection()).thenReturn(false); - mController.init(mLifecycle, SUB_ID); - sleepAfterInit(); - - mController.updateUiAutoSelectValue(mTestServiceState); - - assertThat(mController.isChecked()).isTrue(); - assertThat(mSwitchPreference.isChecked()).isTrue(); - } -}