Merge "Fix readOnlyApnFields not applied" into main

This commit is contained in:
Chaohui Wang
2024-03-21 09:52:41 +00:00
committed by Android (Google) Code Review
5 changed files with 68 additions and 105 deletions

View File

@@ -18,6 +18,7 @@ package com.android.settings.network.apn
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.Telephony
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -142,39 +143,39 @@ fun ApnPage(apnDataInit: ApnData, apnDataCur: MutableState<ApnData>, uriInit: Ur
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.name, value = apnData.name,
label = stringResource(R.string.apn_name), label = stringResource(R.string.apn_name),
enabled = apnData.nameEnabled, enabled = apnData.isFieldEnabled(Telephony.Carriers.NAME),
errorMessage = validateName(apnData.validEnabled, apnData.name, context) errorMessage = validateName(apnData.validEnabled, apnData.name, context)
) { apnData = apnData.copy(name = it) } ) { apnData = apnData.copy(name = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.apn, value = apnData.apn,
label = stringResource(R.string.apn_apn), label = stringResource(R.string.apn_apn),
enabled = apnData.apnEnabled, enabled = apnData.isFieldEnabled(Telephony.Carriers.APN),
errorMessage = validateAPN(apnData.validEnabled, apnData.apn, context) errorMessage = validateAPN(apnData.validEnabled, apnData.apn, context)
) { apnData = apnData.copy(apn = it) } ) { apnData = apnData.copy(apn = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.proxy, value = apnData.proxy,
label = stringResource(R.string.apn_http_proxy), label = stringResource(R.string.apn_http_proxy),
enabled = apnData.proxyEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.PROXY),
) { apnData = apnData.copy(proxy = it) } ) { apnData = apnData.copy(proxy = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.port, value = apnData.port,
label = stringResource(R.string.apn_http_port), label = stringResource(R.string.apn_http_port),
enabled = apnData.portEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.PORT),
) { apnData = apnData.copy(port = it) } ) { apnData = apnData.copy(port = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.userName, value = apnData.userName,
label = stringResource(R.string.apn_user), label = stringResource(R.string.apn_user),
enabled = apnData.userNameEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.USER),
) { apnData = apnData.copy(userName = it) } ) { apnData = apnData.copy(userName = it) }
SettingsTextFieldPassword( SettingsTextFieldPassword(
value = apnData.passWord, value = apnData.passWord,
label = stringResource(R.string.apn_password), label = stringResource(R.string.apn_password),
enabled = apnData.passWordEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.PASSWORD),
) { apnData = apnData.copy(passWord = it) } ) { apnData = apnData.copy(passWord = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.server, value = apnData.server,
label = stringResource(R.string.apn_server), label = stringResource(R.string.apn_server),
enabled = apnData.serverEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.SERVER),
) { apnData = apnData.copy(server = it) } ) { apnData = apnData.copy(server = it) }
ApnTypeCheckBox( ApnTypeCheckBox(
apnData = apnData, apnData = apnData,
@@ -186,42 +187,45 @@ fun ApnPage(apnDataInit: ApnData, apnDataCur: MutableState<ApnData>, uriInit: Ur
value = apnData.mmsc, value = apnData.mmsc,
label = stringResource(R.string.apn_mmsc), label = stringResource(R.string.apn_mmsc),
errorMessage = validateMMSC(apnData.validEnabled, apnData.mmsc, context), errorMessage = validateMMSC(apnData.validEnabled, apnData.mmsc, context),
enabled = apnData.mmscEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.MMSC),
) { apnData = apnData.copy(mmsc = it) } ) { apnData = apnData.copy(mmsc = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.mmsProxy, value = apnData.mmsProxy,
label = stringResource(R.string.apn_mms_proxy), label = stringResource(R.string.apn_mms_proxy),
enabled = apnData.mmsProxyEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.MMSPROXY),
) { apnData = apnData.copy(mmsProxy = it) } ) { apnData = apnData.copy(mmsProxy = it) }
SettingsOutlinedTextField( SettingsOutlinedTextField(
value = apnData.mmsPort, value = apnData.mmsPort,
label = stringResource(R.string.apn_mms_port), label = stringResource(R.string.apn_mms_port),
enabled = apnData.mmsPortEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.MMSPORT),
) { apnData = apnData.copy(mmsPort = it) } ) { apnData = apnData.copy(mmsPort = it) }
} }
SettingsDropdownBox( SettingsDropdownBox(
label = stringResource(R.string.apn_auth_type), label = stringResource(R.string.apn_auth_type),
options = authTypeOptions, options = authTypeOptions,
selectedOptionIndex = apnData.authType, selectedOptionIndex = apnData.authType,
enabled = apnData.authTypeEnabled, enabled = apnData.isFieldEnabled(Telephony.Carriers.AUTH_TYPE),
) { apnData = apnData.copy(authType = it) } ) { apnData = apnData.copy(authType = it) }
SettingsDropdownBox( SettingsDropdownBox(
label = stringResource(R.string.apn_protocol), label = stringResource(R.string.apn_protocol),
options = apnProtocolOptions, options = apnProtocolOptions,
selectedOptionIndex = apnData.apnProtocol, selectedOptionIndex = apnData.apnProtocol,
enabled = apnData.apnProtocolEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.PROTOCOL),
) { apnData = apnData.copy(apnProtocol = it) } ) { apnData = apnData.copy(apnProtocol = it) }
SettingsDropdownBox( SettingsDropdownBox(
label = stringResource(R.string.apn_roaming_protocol), label = stringResource(R.string.apn_roaming_protocol),
options = apnProtocolOptions, options = apnProtocolOptions,
selectedOptionIndex = apnData.apnRoaming, selectedOptionIndex = apnData.apnRoaming,
enabled = apnData.apnRoamingEnabled enabled = apnData.isFieldEnabled(Telephony.Carriers.ROAMING_PROTOCOL),
) { apnData = apnData.copy(apnRoaming = it) } ) { apnData = apnData.copy(apnRoaming = it) }
ApnNetworkTypeCheckBox(apnData) { apnData = apnData.copy(networkType = it) } ApnNetworkTypeCheckBox(apnData) { apnData = apnData.copy(networkType = it) }
SwitchPreference( SwitchPreference(
object : SwitchPreferenceModel { object : SwitchPreferenceModel {
override val title = context.resources.getString(R.string.carrier_enabled) override val title = stringResource(R.string.carrier_enabled)
override val changeable = { apnData.apnEnableEnabled } override val changeable = {
apnData.apnEnableEnabled &&
apnData.isFieldEnabled(Telephony.Carriers.CARRIER_ENABLED)
}
override val checked = { apnData.apnEnable } override val checked = { apnData.apnEnable }
override val onCheckedChange = { newChecked: Boolean -> override val onCheckedChange = { newChecked: Boolean ->
apnData = apnData.copy(apnEnable = newChecked) apnData = apnData.copy(apnEnable = newChecked)

View File

@@ -16,6 +16,7 @@
package com.android.settings.network.apn package com.android.settings.network.apn
import android.provider.Telephony
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -29,7 +30,11 @@ fun ApnNetworkTypeCheckBox(apnData: ApnData, onNetworkTypeChanged: (Long) -> Uni
label = stringResource(R.string.network_type), label = stringResource(R.string.network_type),
options = options, options = options,
emptyText = stringResource(R.string.network_type_unspecified), 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)) onNetworkTypeChanged(ApnNetworkTypes.optionsToNetworkType(options))
} }

View File

@@ -48,22 +48,7 @@ data class ApnData(
val networkType: Long = 0, val networkType: Long = 0,
val edited: Int = Telephony.Carriers.USER_EDITED, val edited: Int = Telephony.Carriers.USER_EDITED,
val userEditable: Int = 1, 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 apnEnableEnabled: Boolean = true,
val networkTypeEnabled: Boolean = true,
val newApn: Boolean = false, val newApn: Boolean = false,
val subId: Int = -1, val subId: Int = -1,
val validEnabled: Boolean = false, val validEnabled: Boolean = false,
@@ -93,6 +78,10 @@ data class ApnData(
if (newApn) context.getApnIdMap(subId).forEach(::putObject) if (newApn) context.getApnIdMap(subId).forEach(::putObject)
getContentValueMap(context).forEach(::putObject) getContentValueMap(context).forEach(::putObject)
} }
fun isFieldEnabled(vararg fieldName: String): Boolean =
!customizedConfig.readOnlyApn &&
fieldName.all { it !in customizedConfig.readOnlyApnFields }
} }
data class CustomizedConfig( data class CustomizedConfig(
@@ -271,83 +260,17 @@ private fun ApnData.isReadOnly(): Boolean {
fun disableInit(apnDataInit: ApnData): ApnData { fun disableInit(apnDataInit: ApnData): ApnData {
if (apnDataInit.isReadOnly()) { if (apnDataInit.isReadOnly()) {
Log.d(TAG, "disableInit: read-only APN") Log.d(TAG, "disableInit: read-only APN")
val apnData = apnDataInit.copy( return apnDataInit.copy(
customizedConfig = apnDataInit.customizedConfig.copy(readOnlyApn = true) customizedConfig = apnDataInit.customizedConfig.copy(readOnlyApn = true)
) )
return disableAllFields(apnData)
} }
val readOnlyApnFields = apnDataInit.customizedConfig.readOnlyApnFields val readOnlyApnFields = apnDataInit.customizedConfig.readOnlyApnFields
if (readOnlyApnFields.isNotEmpty()) { if (readOnlyApnFields.isNotEmpty()) {
Log.d(TAG, "disableInit: readOnlyApnFields $readOnlyApnFields)") Log.d(TAG, "disableInit: readOnlyApnFields $readOnlyApnFields)")
return disableFields(readOnlyApnFields, apnDataInit)
} }
return 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<String>, 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) { fun deleteApn(uri: Uri, context: Context) {
val contentResolver = context.contentResolver val contentResolver = context.contentResolver
contentResolver.delete(uri, null, null) contentResolver.delete(uri, null, null)

View File

@@ -16,6 +16,7 @@
package com.android.settings.network.apn package com.android.settings.network.apn
import android.provider.Telephony
import android.telephony.data.ApnSetting import android.telephony.data.ApnSetting
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -45,7 +46,7 @@ fun ApnTypeCheckBox(
SettingsDropdownCheckBox( SettingsDropdownCheckBox(
label = stringResource(R.string.apn_type), label = stringResource(R.string.apn_type),
options = apnTypeOptions, options = apnTypeOptions,
enabled = apnData.apnTypeEnabled, enabled = apnData.isFieldEnabled(Telephony.Carriers.TYPE),
) { ) {
onTypeChanged(apnTypeOptions.toApnType()) onTypeChanged(apnTypeOptions.toApnType())
updateMmsSelected() updateMmsSelected()

View File

@@ -17,8 +17,10 @@
package com.android.settings.network.apn package com.android.settings.network.apn
import android.os.PersistableBundle import android.os.PersistableBundle
import android.provider.Telephony
import android.telephony.CarrierConfigManager import android.telephony.CarrierConfigManager
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
@@ -26,11 +28,8 @@ import org.mockito.kotlin.mock
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class ApnStatusTest { class ApnStatusTest {
private val apnData = mock<ApnData> { private val apnData = ApnData(subId = 1)
on {
it.subId
} doReturn 1
}
private val configManager = mock<CarrierConfigManager> { private val configManager = mock<CarrierConfigManager> {
val p = PersistableBundle() val p = PersistableBundle()
p.putBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL, true) p.putBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL, true)
@@ -51,4 +50,35 @@ class ApnStatusTest {
fun getCarrierCustomizedConfig_test() { fun getCarrierCustomizedConfig_test() {
assert(getCarrierCustomizedConfig(apnData, configManager).isAddApnAllowed) assert(getCarrierCustomizedConfig(apnData, configManager).isAddApnAllowed)
} }
@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()
}
} }