Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 54b03da3 authored by Chaohui Wang's avatar Chaohui Wang
Browse files

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
parent dd5b4d3d
Loading
Loading
Loading
Loading
+19 −15
Original line number Diff line number Diff line
@@ -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<ApnData>, 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<ApnData>, 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)
+6 −1
Original line number Diff line number Diff line
@@ -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))
    }
+5 −82
Original line number Diff line number Diff line
@@ -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<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) {
    val contentResolver = context.contentResolver
    contentResolver.delete(uri, null, null)
+2 −1
Original line number Diff line number Diff line
@@ -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()
+36 −6
Original line number Diff line number Diff line
@@ -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<ApnData> {
        on {
            it.subId
        } doReturn 1
    }
    private val apnData = ApnData(subId = 1)

    private val configManager = mock<CarrierConfigManager> {
        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)
    }

    @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()
    }
}