From 54b03da369a474ff1811938bc2840529c6859649 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Thu, 21 Mar 2024 16:32:38 +0800 Subject: [PATCH] Fix readOnlyApnFields not applied Some enabled not set correctly. Remove the enabled values, and check readOnlyApnFields directly to fix. Fix: 330566517 Test: manual with carrier config KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY Test: unit test Change-Id: Ifd6d4a0d9a96a900c9d124c9e357562e84bbc6c7 --- .../network/apn/ApnEditPageProvider.kt | 34 ++++---- .../network/apn/ApnNetworkTypeCheckBox.kt | 7 +- .../android/settings/network/apn/ApnStatus.kt | 87 ++----------------- .../settings/network/apn/ApnTypeCheckBox.kt | 3 +- .../settings/network/apn/ApnStatusTest.kt | 42 +++++++-- 5 files changed, 68 insertions(+), 105 deletions(-) diff --git a/src/com/android/settings/network/apn/ApnEditPageProvider.kt b/src/com/android/settings/network/apn/ApnEditPageProvider.kt index 1abcbdb953c..a287b848474 100644 --- a/src/com/android/settings/network/apn/ApnEditPageProvider.kt +++ b/src/com/android/settings/network/apn/ApnEditPageProvider.kt @@ -18,6 +18,7 @@ package com.android.settings.network.apn import android.net.Uri import android.os.Bundle +import android.provider.Telephony import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -142,39 +143,39 @@ fun ApnPage(apnDataInit: ApnData, apnDataCur: MutableState, uriInit: Ur SettingsOutlinedTextField( value = apnData.name, label = stringResource(R.string.apn_name), - enabled = apnData.nameEnabled, + enabled = apnData.isFieldEnabled(Telephony.Carriers.NAME), errorMessage = validateName(apnData.validEnabled, apnData.name, context) ) { apnData = apnData.copy(name = it) } SettingsOutlinedTextField( value = apnData.apn, label = stringResource(R.string.apn_apn), - enabled = apnData.apnEnabled, + enabled = apnData.isFieldEnabled(Telephony.Carriers.APN), errorMessage = validateAPN(apnData.validEnabled, apnData.apn, context) ) { apnData = apnData.copy(apn = it) } SettingsOutlinedTextField( value = apnData.proxy, label = stringResource(R.string.apn_http_proxy), - enabled = apnData.proxyEnabled + enabled = apnData.isFieldEnabled(Telephony.Carriers.PROXY), ) { apnData = apnData.copy(proxy = it) } SettingsOutlinedTextField( value = apnData.port, label = stringResource(R.string.apn_http_port), - enabled = apnData.portEnabled + enabled = apnData.isFieldEnabled(Telephony.Carriers.PORT), ) { apnData = apnData.copy(port = it) } SettingsOutlinedTextField( value = apnData.userName, label = stringResource(R.string.apn_user), - enabled = apnData.userNameEnabled + enabled = apnData.isFieldEnabled(Telephony.Carriers.USER), ) { apnData = apnData.copy(userName = it) } SettingsTextFieldPassword( value = apnData.passWord, label = stringResource(R.string.apn_password), - enabled = apnData.passWordEnabled + enabled = apnData.isFieldEnabled(Telephony.Carriers.PASSWORD), ) { apnData = apnData.copy(passWord = it) } SettingsOutlinedTextField( value = apnData.server, label = stringResource(R.string.apn_server), - enabled = apnData.serverEnabled + enabled = apnData.isFieldEnabled(Telephony.Carriers.SERVER), ) { apnData = apnData.copy(server = it) } ApnTypeCheckBox( apnData = apnData, @@ -186,42 +187,45 @@ fun ApnPage(apnDataInit: ApnData, apnDataCur: MutableState, uriInit: Ur value = apnData.mmsc, label = stringResource(R.string.apn_mmsc), errorMessage = validateMMSC(apnData.validEnabled, apnData.mmsc, context), - enabled = apnData.mmscEnabled + enabled = apnData.isFieldEnabled(Telephony.Carriers.MMSC), ) { apnData = apnData.copy(mmsc = it) } SettingsOutlinedTextField( value = apnData.mmsProxy, label = stringResource(R.string.apn_mms_proxy), - enabled = apnData.mmsProxyEnabled + enabled = apnData.isFieldEnabled(Telephony.Carriers.MMSPROXY), ) { apnData = apnData.copy(mmsProxy = it) } SettingsOutlinedTextField( value = apnData.mmsPort, label = stringResource(R.string.apn_mms_port), - enabled = apnData.mmsPortEnabled + enabled = apnData.isFieldEnabled(Telephony.Carriers.MMSPORT), ) { apnData = apnData.copy(mmsPort = it) } } SettingsDropdownBox( label = stringResource(R.string.apn_auth_type), options = authTypeOptions, selectedOptionIndex = apnData.authType, - enabled = apnData.authTypeEnabled, + enabled = apnData.isFieldEnabled(Telephony.Carriers.AUTH_TYPE), ) { apnData = apnData.copy(authType = it) } SettingsDropdownBox( label = stringResource(R.string.apn_protocol), options = apnProtocolOptions, selectedOptionIndex = apnData.apnProtocol, - enabled = apnData.apnProtocolEnabled + enabled = apnData.isFieldEnabled(Telephony.Carriers.PROTOCOL), ) { apnData = apnData.copy(apnProtocol = it) } SettingsDropdownBox( label = stringResource(R.string.apn_roaming_protocol), options = apnProtocolOptions, selectedOptionIndex = apnData.apnRoaming, - enabled = apnData.apnRoamingEnabled + enabled = apnData.isFieldEnabled(Telephony.Carriers.ROAMING_PROTOCOL), ) { apnData = apnData.copy(apnRoaming = it) } ApnNetworkTypeCheckBox(apnData) { apnData = apnData.copy(networkType = it) } SwitchPreference( object : SwitchPreferenceModel { - override val title = context.resources.getString(R.string.carrier_enabled) - override val changeable = { apnData.apnEnableEnabled } + override val title = stringResource(R.string.carrier_enabled) + override val changeable = { + apnData.apnEnableEnabled && + apnData.isFieldEnabled(Telephony.Carriers.CARRIER_ENABLED) + } override val checked = { apnData.apnEnable } override val onCheckedChange = { newChecked: Boolean -> apnData = apnData.copy(apnEnable = newChecked) diff --git a/src/com/android/settings/network/apn/ApnNetworkTypeCheckBox.kt b/src/com/android/settings/network/apn/ApnNetworkTypeCheckBox.kt index a42031b388a..305f7b6061a 100644 --- a/src/com/android/settings/network/apn/ApnNetworkTypeCheckBox.kt +++ b/src/com/android/settings/network/apn/ApnNetworkTypeCheckBox.kt @@ -16,6 +16,7 @@ package com.android.settings.network.apn +import android.provider.Telephony import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.res.stringResource @@ -29,7 +30,11 @@ fun ApnNetworkTypeCheckBox(apnData: ApnData, onNetworkTypeChanged: (Long) -> Uni label = stringResource(R.string.network_type), options = options, emptyText = stringResource(R.string.network_type_unspecified), - enabled = apnData.networkTypeEnabled, + enabled = apnData.isFieldEnabled( + Telephony.Carriers.BEARER, + Telephony.Carriers.BEARER_BITMASK, + Telephony.Carriers.NETWORK_TYPE_BITMASK + ), ) { onNetworkTypeChanged(ApnNetworkTypes.optionsToNetworkType(options)) } diff --git a/src/com/android/settings/network/apn/ApnStatus.kt b/src/com/android/settings/network/apn/ApnStatus.kt index ab16f1ca5d2..aa816fc8a62 100644 --- a/src/com/android/settings/network/apn/ApnStatus.kt +++ b/src/com/android/settings/network/apn/ApnStatus.kt @@ -48,22 +48,7 @@ data class ApnData( val networkType: Long = 0, val edited: Int = Telephony.Carriers.USER_EDITED, val userEditable: Int = 1, - val nameEnabled: Boolean = true, - val apnEnabled: Boolean = true, - val proxyEnabled: Boolean = true, - val portEnabled: Boolean = true, - val userNameEnabled: Boolean = true, - val passWordEnabled: Boolean = true, - val serverEnabled: Boolean = true, - val mmscEnabled: Boolean = true, - val mmsProxyEnabled: Boolean = true, - val mmsPortEnabled: Boolean = true, - val authTypeEnabled: Boolean = true, - val apnTypeEnabled: Boolean = true, - val apnProtocolEnabled: Boolean = true, - val apnRoamingEnabled: Boolean = true, val apnEnableEnabled: Boolean = true, - val networkTypeEnabled: Boolean = true, val newApn: Boolean = false, val subId: Int = -1, val validEnabled: Boolean = false, @@ -93,6 +78,10 @@ data class ApnData( if (newApn) context.getApnIdMap(subId).forEach(::putObject) getContentValueMap(context).forEach(::putObject) } + + fun isFieldEnabled(vararg fieldName: String): Boolean = + !customizedConfig.readOnlyApn && + fieldName.all { it !in customizedConfig.readOnlyApnFields } } data class CustomizedConfig( @@ -271,83 +260,17 @@ private fun ApnData.isReadOnly(): Boolean { fun disableInit(apnDataInit: ApnData): ApnData { if (apnDataInit.isReadOnly()) { Log.d(TAG, "disableInit: read-only APN") - val apnData = apnDataInit.copy( + return apnDataInit.copy( customizedConfig = apnDataInit.customizedConfig.copy(readOnlyApn = true) ) - return disableAllFields(apnData) } val readOnlyApnFields = apnDataInit.customizedConfig.readOnlyApnFields if (readOnlyApnFields.isNotEmpty()) { Log.d(TAG, "disableInit: readOnlyApnFields $readOnlyApnFields)") - return disableFields(readOnlyApnFields, apnDataInit) } return apnDataInit } -/** - * Disables all fields so that user cannot modify the APN - */ -private fun disableAllFields(apnDataInit: ApnData): ApnData { - var apnData = apnDataInit - apnData = apnData.copy(nameEnabled = false) - apnData = apnData.copy(apnEnabled = false) - apnData = apnData.copy(proxyEnabled = false) - apnData = apnData.copy(portEnabled = false) - apnData = apnData.copy(userNameEnabled = false) - apnData = apnData.copy(passWordEnabled = false) - apnData = apnData.copy(serverEnabled = false) - apnData = apnData.copy(mmscEnabled = false) - apnData = apnData.copy(mmsProxyEnabled = false) - apnData = apnData.copy(mmsPortEnabled = false) - apnData = apnData.copy(authTypeEnabled = false) - apnData = apnData.copy(apnTypeEnabled = false) - apnData = apnData.copy(apnProtocolEnabled = false) - apnData = apnData.copy(apnRoamingEnabled = false) - apnData = apnData.copy(apnEnableEnabled = false) - apnData = apnData.copy(networkTypeEnabled = false) - return apnData -} - -/** - * Disables given fields so that user cannot modify them - * - * @param apnFields fields to be disabled - */ -private fun disableFields(apnFields: List, apnDataInit: ApnData): ApnData { - var apnData = apnDataInit - for (apnField in apnFields) { - apnData = disableByFieldName(apnField, apnDataInit) - } - return apnData -} - -private fun disableByFieldName(apnField: String, apnDataInit: ApnData): ApnData { - var apnData = apnDataInit - when (apnField) { - Telephony.Carriers.NAME -> apnData = apnData.copy(nameEnabled = false) - Telephony.Carriers.APN -> apnData = apnData.copy(apnEnabled = false) - Telephony.Carriers.PROXY -> apnData = apnData.copy(proxyEnabled = false) - Telephony.Carriers.PORT -> apnData = apnData.copy(portEnabled = false) - Telephony.Carriers.USER -> apnData = apnData.copy(userNameEnabled = false) - Telephony.Carriers.SERVER -> apnData = apnData.copy(serverEnabled = false) - Telephony.Carriers.PASSWORD -> apnData = apnData.copy(passWordEnabled = false) - Telephony.Carriers.MMSPROXY -> apnData = apnData.copy(mmsProxyEnabled = false) - Telephony.Carriers.MMSPORT -> apnData = apnData.copy(mmsPortEnabled = false) - Telephony.Carriers.MMSC -> apnData = apnData.copy(mmscEnabled = false) - Telephony.Carriers.TYPE -> apnData = apnData.copy(apnTypeEnabled = false) - Telephony.Carriers.AUTH_TYPE -> apnData = apnData.copy(authTypeEnabled = false) - Telephony.Carriers.PROTOCOL -> apnData = apnData.copy(apnProtocolEnabled = false) - Telephony.Carriers.ROAMING_PROTOCOL -> apnData = apnData.copy(apnRoamingEnabled = false) - Telephony.Carriers.CARRIER_ENABLED -> apnData = apnData.copy(apnEnableEnabled = false) - Telephony.Carriers.BEARER, Telephony.Carriers.BEARER_BITMASK, - Telephony.Carriers.NETWORK_TYPE_BITMASK -> apnData = apnData.copy( - networkTypeEnabled = - false - ) - } - return apnData -} - fun deleteApn(uri: Uri, context: Context) { val contentResolver = context.contentResolver contentResolver.delete(uri, null, null) diff --git a/src/com/android/settings/network/apn/ApnTypeCheckBox.kt b/src/com/android/settings/network/apn/ApnTypeCheckBox.kt index 4d0659c659c..aa757cc9513 100644 --- a/src/com/android/settings/network/apn/ApnTypeCheckBox.kt +++ b/src/com/android/settings/network/apn/ApnTypeCheckBox.kt @@ -16,6 +16,7 @@ package com.android.settings.network.apn +import android.provider.Telephony import android.telephony.data.ApnSetting import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -45,7 +46,7 @@ fun ApnTypeCheckBox( SettingsDropdownCheckBox( label = stringResource(R.string.apn_type), options = apnTypeOptions, - enabled = apnData.apnTypeEnabled, + enabled = apnData.isFieldEnabled(Telephony.Carriers.TYPE), ) { onTypeChanged(apnTypeOptions.toApnType()) updateMmsSelected() diff --git a/tests/spa_unit/src/com/android/settings/network/apn/ApnStatusTest.kt b/tests/spa_unit/src/com/android/settings/network/apn/ApnStatusTest.kt index 539783c18a3..6b61eba0f9b 100644 --- a/tests/spa_unit/src/com/android/settings/network/apn/ApnStatusTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/apn/ApnStatusTest.kt @@ -17,8 +17,10 @@ package com.android.settings.network.apn import android.os.PersistableBundle +import android.provider.Telephony import android.telephony.CarrierConfigManager import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.doReturn @@ -26,11 +28,8 @@ import org.mockito.kotlin.mock @RunWith(AndroidJUnit4::class) class ApnStatusTest { - private val apnData = mock { - on { - it.subId - } doReturn 1 - } + private val apnData = ApnData(subId = 1) + private val configManager = mock { val p = PersistableBundle() p.putBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL, true) @@ -51,4 +50,35 @@ class ApnStatusTest { fun getCarrierCustomizedConfig_test() { assert(getCarrierCustomizedConfig(apnData, configManager).isAddApnAllowed) } -} \ No newline at end of file + + @Test + fun isFieldEnabled_default() { + val apnData = ApnData() + + val enabled = apnData.isFieldEnabled(Telephony.Carriers.NAME) + + assertThat(enabled).isTrue() + } + + @Test + fun isFieldEnabled_readOnlyApn() { + val apnData = ApnData(customizedConfig = CustomizedConfig(readOnlyApn = true)) + + val enabled = apnData.isFieldEnabled(Telephony.Carriers.NAME) + + assertThat(enabled).isFalse() + } + + @Test + fun isFieldEnabled_readOnlyApnFields() { + val apnData = ApnData( + customizedConfig = CustomizedConfig( + readOnlyApnFields = listOf(Telephony.Carriers.NAME, Telephony.Carriers.PROXY), + ), + ) + + assertThat(apnData.isFieldEnabled(Telephony.Carriers.NAME)).isFalse() + assertThat(apnData.isFieldEnabled(Telephony.Carriers.PROXY)).isFalse() + assertThat(apnData.isFieldEnabled(Telephony.Carriers.APN)).isTrue() + } +}