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

Commit 5b2de594 authored by Charlotte Lu's avatar Charlotte Lu
Browse files

Add validateAndSaveApnData.

Fix: 304649927
Test: Visual Test
Change-Id: I900a096a6e27f1db66af204201d4ca2523537c0d
parent 74927c7e
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -19,6 +19,10 @@ package com.android.settings.network.apn
import android.net.Uri
import android.os.Bundle
import androidx.compose.foundation.layout.Column
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Done
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
@@ -70,7 +74,7 @@ object ApnEditPageProvider : SettingsPageProvider {
        val apnDataCur = remember {
            mutableStateOf(apnDataInit)
        }
        ApnPage(apnDataCur)
        ApnPage(apnDataInit, apnDataCur)
    }

    fun getRoute(
@@ -83,7 +87,7 @@ object ApnEditPageProvider : SettingsPageProvider {
}

@Composable
fun ApnPage(apnDataCur: MutableState<ApnData>) {
fun ApnPage(apnDataInit: ApnData, apnDataCur: MutableState<ApnData>) {
    var apnData by apnDataCur
    val context = LocalContext.current
    val authTypeOptions = stringArrayResource(R.array.apn_auth_entries).toList()
@@ -93,6 +97,11 @@ fun ApnPage(apnDataCur: MutableState<ApnData>) {
    }
    RegularScaffold(
        title = stringResource(id = R.string.apn_edit),
        actions = {
            IconButton(onClick = {
                validateAndSaveApnData(apnDataInit, apnData, context)
            }) { Icon(imageVector = Icons.Outlined.Done, contentDescription = "Save APN") }
        }
    ) {
        Column() {
            SettingsOutlinedTextField(
+153 −2
Original line number Diff line number Diff line
@@ -81,6 +81,55 @@ data class CustomizedConfig(
    val defaultApnRoamingProtocol: String = "",
)

/**
 * APN types for data connections.  These are usage categories for an APN
 * entry.  One APN entry may support multiple APN types, eg, a single APN
 * may service regular internet traffic ("default") as well as MMS-specific
 * connections.<br></br>
 * APN_TYPE_ALL is a special type to indicate that this APN entry can
 * service all data connections.
 */
const val APN_TYPE_ALL = "*"
/** APN type for default data traffic  */
const val APN_TYPE_DEFAULT = "default"
/** APN type for MMS traffic  */
const val APN_TYPE_MMS = "mms"
/** APN type for SUPL assisted GPS  */
const val APN_TYPE_SUPL = "supl"
/** APN type for DUN traffic  */
const val APN_TYPE_DUN = "dun"
/** APN type for HiPri traffic  */
const val APN_TYPE_HIPRI = "hipri"
/** APN type for FOTA  */
const val APN_TYPE_FOTA = "fota"
/** APN type for IMS  */
const val APN_TYPE_IMS = "ims"
/** APN type for CBS  */
const val APN_TYPE_CBS = "cbs"
/** APN type for IA Initial Attach APN  */
const val APN_TYPE_IA = "ia"
/** APN type for Emergency PDN. This is not an IA apn, but is used
 * for access to carrier services in an emergency call situation.  */
const val APN_TYPE_EMERGENCY = "emergency"
/** APN type for Mission Critical Services  */
const val APN_TYPE_MCX = "mcx"
/** APN type for XCAP  */
const val APN_TYPE_XCAP = "xcap"
val APN_TYPES = arrayOf(
    APN_TYPE_DEFAULT,
    APN_TYPE_MMS,
    APN_TYPE_SUPL,
    APN_TYPE_DUN,
    APN_TYPE_HIPRI,
    APN_TYPE_FOTA,
    APN_TYPE_IMS,
    APN_TYPE_CBS,
    APN_TYPE_IA,
    APN_TYPE_EMERGENCY,
    APN_TYPE_MCX,
    APN_TYPE_XCAP
)

/**
 * Initialize ApnData according to the arguments.
 * @param arguments The data passed in when the user calls PageProvider.
@@ -123,6 +172,108 @@ fun getApnDataInit(arguments: Bundle, context: Context, uriInit: Uri, subId: Int
    return apnDataInit
}

/**
 * Validates the apn data and save it to the database if it's valid.
 *
 *
 *
 * A dialog with error message will be displayed if the APN data is invalid.
 *
 * @return true if there is no error
 */
fun validateAndSaveApnData(apnDataInit: ApnData, apnData: ApnData, context: Context): Boolean {
    // Nothing to do if it's a read only APN
    if (apnData.customizedConfig.readOnlyApn) {
        return true
    }
    val errorMsg = validateApnData(apnData, context)
    if (errorMsg != null) {
        //TODO: showError(this)
        return false
    }
    if (apnData.newApn || (apnData != apnDataInit)) {
        Log.d(TAG, "validateAndSaveApnData: apnData ${apnData.name}")
        // TODO: updateApnDataToDatabase
    }
    return true
}

/**
 * Validates whether the apn data is valid.
 *
 * @return An error message if the apn data is invalid, otherwise return null.
 */
fun validateApnData(apnData: ApnData, context: Context): String? {
    var errorMsg: String? = null
    val name = apnData.name
    val apn = apnData.apn
    if (name == "") {
        errorMsg = context.resources.getString(R.string.error_name_empty)
    } else if (apn == "") {
        errorMsg = context.resources.getString(R.string.error_apn_empty)
    }
    if (errorMsg == null) {
        // if carrier does not allow editing certain apn types, make sure type does not include
        // those
        if (!ArrayUtils.isEmpty(apnData.customizedConfig.readOnlyApnTypes)
            && apnTypesMatch(apnData.customizedConfig.readOnlyApnTypes, getUserEnteredApnType(apnData.apnType, apnData.customizedConfig.readOnlyApnTypes))
        ) {
            val stringBuilder = StringBuilder()
            for (type in apnData.customizedConfig.readOnlyApnTypes) {
                stringBuilder.append(type).append(", ")
                Log.d(TAG, "validateApnData: appending type: $type")
            }
            // remove last ", "
            if (stringBuilder.length >= 2) {
                stringBuilder.delete(stringBuilder.length - 2, stringBuilder.length)
            }
            errorMsg = String.format(
                context.resources.getString(R.string.error_adding_apn_type),
                stringBuilder
            )
        }
    }
    return errorMsg
}

private fun getUserEnteredApnType(apnType: String, readOnlyApnTypes: List<String>): String {
    // if user has not specified a type, map it to "ALL APN TYPES THAT ARE NOT READ-ONLY"
    // but if user enter empty type, map it just for default
    var userEnteredApnType = apnType
    if (userEnteredApnType != "") userEnteredApnType =
        userEnteredApnType.trim { it <= ' ' }
    if (TextUtils.isEmpty(userEnteredApnType) || APN_TYPE_ALL == userEnteredApnType) {
        userEnteredApnType = getEditableApnType(readOnlyApnTypes)
    }
    Log.d(
        TAG, "getUserEnteredApnType: changed apn type to editable apn types: "
            + userEnteredApnType
    )
    return userEnteredApnType
}

private fun getEditableApnType(readOnlyApnTypes: List<String>): String {
    val editableApnTypes = StringBuilder()
    var first = true
    for (apnType in APN_TYPES) {
        // add APN type if it is not read-only and is not wild-cardable
        if (!readOnlyApnTypes.contains(apnType)
            && apnType != APN_TYPE_IA
            && apnType != APN_TYPE_EMERGENCY
            && apnType != APN_TYPE_MCX
            && apnType != APN_TYPE_IMS
        ) {
            if (first) {
                first = false
            } else {
                editableApnTypes.append(",")
            }
            editableApnTypes.append(apnType)
        }
    }
    return editableApnTypes.toString()
}

/**
 * Initialize CustomizedConfig information through subId.
 * @param subId subId information obtained from arguments.
@@ -299,11 +450,11 @@ fun hasAllApns(apnTypes: Array<String?>): Boolean {
        return false
    }
    val apnList: List<*> = Arrays.asList(*apnTypes)
    if (apnList.contains(ApnEditor.APN_TYPE_ALL)) {
    if (apnList.contains(APN_TYPE_ALL)) {
        Log.d(TAG, "hasAllApns: true because apnList.contains(APN_TYPE_ALL)")
        return true
    }
    for (apn in ApnEditor.APN_TYPES) {
    for (apn in APN_TYPES) {
        if (!apnList.contains(apn)) {
            return false
        }
+24 −28
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.settings.network.apn

import android.content.Context
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.test.assertIsDisplayed
@@ -58,8 +57,7 @@ class ApnEditPageProviderTest {
        context.resources.getStringArray(R.array.apn_protocol_entries).toList()
    private val networkType = context.resources.getString(R.string.network_type)
    private val passwordTitle = context.resources.getString(R.string.apn_password)
    private val apnData = mutableStateOf(
        ApnData(
    private val apnInit = ApnData(
        name = apnName,
        mmsc = mmsc,
        mmsProxy = mmsProxy,
@@ -67,6 +65,8 @@ class ApnEditPageProviderTest {
        apnRoaming = apnProtocolOptions.indexOf(apnRoaming),
        apnEnable = true
    )
    private val apnData = mutableStateOf(
        apnInit
    )

    @Test
@@ -77,7 +77,7 @@ class ApnEditPageProviderTest {
    @Test
    fun title_displayed() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
@@ -87,7 +87,7 @@ class ApnEditPageProviderTest {
    @Test
    fun name_displayed() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
@@ -97,7 +97,7 @@ class ApnEditPageProviderTest {
    @Test
    fun mmsc_displayed() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
@@ -109,7 +109,7 @@ class ApnEditPageProviderTest {
    @Test
    fun mms_proxy_displayed() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
@@ -121,7 +121,7 @@ class ApnEditPageProviderTest {
    @Test
    fun apn_type_displayed() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
@@ -133,7 +133,7 @@ class ApnEditPageProviderTest {
    @Test
    fun apn_roaming_displayed() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
@@ -145,7 +145,7 @@ class ApnEditPageProviderTest {
    @Test
    fun carrier_enabled_displayed() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
@@ -157,7 +157,7 @@ class ApnEditPageProviderTest {
    @Test
    fun carrier_enabled_isChecked() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
@@ -169,7 +169,7 @@ class ApnEditPageProviderTest {
    @Test
    fun carrier_enabled_checkChanged() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
@@ -182,7 +182,7 @@ class ApnEditPageProviderTest {
    @Test
    fun network_type_displayed() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
@@ -193,12 +193,10 @@ class ApnEditPageProviderTest {

    @Test
    fun network_type_changed() {
        var apnDataa: MutableState<ApnData> = apnData
        composeTestRule.setContent {
            apnDataa = remember {
            ApnPage(apnInit, remember {
                apnData
            }
            ApnPage(apnDataa)
            })
        }
        composeTestRule.onRoot().onChild().onChildAt(0)
            .performScrollToNode(hasText(networkType, true))
@@ -211,12 +209,10 @@ class ApnEditPageProviderTest {

    @Test
    fun network_type_changed_back2Default() {
        var apnDataa: MutableState<ApnData> = apnData
        composeTestRule.setContent {
            apnDataa = remember {
            ApnPage(apnInit, remember {
                apnData
            }
            ApnPage(apnDataa)
            })
        }
        composeTestRule.onRoot().onChild().onChildAt(0)
            .performScrollToNode(hasText(networkType, true))
@@ -234,7 +230,7 @@ class ApnEditPageProviderTest {
    @Test
    fun password_displayed() {
        composeTestRule.setContent {
            ApnPage(remember {
            ApnPage(apnInit, remember {
                apnData
            })
        }
+1 −1

File changed.

Contains only whitespace changes.