Add ApnDataInit.

Fix: 298906796
Test: Unit Test
Change-Id: Ibf9e12e4f9c4ee033ad6dc2ca1f2267bf1f21912
This commit is contained in:
Charlotte Lu
2023-10-08 14:23:37 +08:00
parent 4188a571aa
commit 93fb316f01
6 changed files with 445 additions and 25 deletions

View File

@@ -50,6 +50,7 @@ const val SUB_ID = "subId"
const val MVNO_TYPE = "mvnoType" const val MVNO_TYPE = "mvnoType"
const val MVNO_MATCH_DATA = "mvnoMatchData" const val MVNO_MATCH_DATA = "mvnoMatchData"
const val EDIT_URL = "editUrl" const val EDIT_URL = "editUrl"
const val INSERT_URL = "insertUrl"
object ApnEditPageProvider : SettingsPageProvider { object ApnEditPageProvider : SettingsPageProvider {
@@ -66,7 +67,10 @@ object ApnEditPageProvider : SettingsPageProvider {
@Composable @Composable
override fun Page(arguments: Bundle?) { override fun Page(arguments: Bundle?) {
val apnDataInit = ApnData() val uriString = arguments!!.getString(URI)
val uriInit = Uri.parse(String(Base64.getDecoder().decode(uriString)))
val subId = arguments.getInt(SUB_ID)
val apnDataInit = getApnDataInit(arguments, LocalContext.current, uriInit, subId)
val apnDataCur = remember { val apnDataCur = remember {
mutableStateOf(apnDataInit) mutableStateOf(apnDataInit)
} }

View File

@@ -0,0 +1,182 @@
/*
* 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.apn
import android.content.Context
import android.net.Uri
import android.provider.Telephony
import android.util.Log
import com.android.settings.R
import java.util.Locale
const val NAME_INDEX = 1
const val APN_INDEX = 2
const val PROXY_INDEX = 3
const val PORT_INDEX = 4
const val USER_INDEX = 5
const val SERVER_INDEX = 6
const val PASSWORD_INDEX = 7
const val MMSC_INDEX = 8
const val MCC_INDEX = 9
const val MNC_INDEX = 10
const val MMSPROXY_INDEX = 12
const val MMSPORT_INDEX = 13
const val AUTH_TYPE_INDEX = 14
const val TYPE_INDEX = 15
const val PROTOCOL_INDEX = 16
const val CARRIER_ENABLED_INDEX = 17
const val NETWORK_TYPE_INDEX = 18
const val ROAMING_PROTOCOL_INDEX = 19
const val MVNO_TYPE_INDEX = 20
const val MVNO_MATCH_DATA_INDEX = 21
const val EDITED_INDEX = 22
const val USER_EDITABLE_INDEX = 23
const val CARRIER_ID_INDEX = 24
val sProjection = arrayOf(
Telephony.Carriers._ID, // 0
Telephony.Carriers.NAME, // 1
Telephony.Carriers.APN, // 2
Telephony.Carriers.PROXY, // 3
Telephony.Carriers.PORT, // 4
Telephony.Carriers.USER, // 5
Telephony.Carriers.SERVER, // 6
Telephony.Carriers.PASSWORD, // 7
Telephony.Carriers.MMSC, // 8
Telephony.Carriers.MCC, // 9
Telephony.Carriers.MNC, // 10
Telephony.Carriers.NUMERIC, // 11
Telephony.Carriers.MMSPROXY, // 12
Telephony.Carriers.MMSPORT, // 13
Telephony.Carriers.AUTH_TYPE, // 14
Telephony.Carriers.TYPE, // 15
Telephony.Carriers.PROTOCOL, // 16
Telephony.Carriers.CARRIER_ENABLED, // 17
Telephony.Carriers.NETWORK_TYPE_BITMASK, // 18
Telephony.Carriers.ROAMING_PROTOCOL, // 19
Telephony.Carriers.MVNO_TYPE, // 20
Telephony.Carriers.MVNO_MATCH_DATA, // 21
Telephony.Carriers.EDITED_STATUS, // 22
Telephony.Carriers.USER_EDITABLE, // 23
Telephony.Carriers.CARRIER_ID // 24
)
const val TAG = "ApnRepository"
/**
* Query apn related information based on uri.
* @param uri URI data used for query.
*
* @return Stored apn related information.
*/
fun getApnDataFromUri(uri: Uri, context: Context): ApnData {
var apnData = ApnData()
val contentResolver = context.contentResolver
val apnProtocolOptions = context.resources.getStringArray(R.array.apn_protocol_entries).toList()
val mvnoTypeOptions = context.resources.getStringArray(R.array.mvno_type_entries).toList()
contentResolver.query(
uri,
sProjection,
null /* selection */,
null /* selectionArgs */,
null /* sortOrder */
).use { cursor ->
if (cursor != null && cursor.moveToFirst()) {
val name = cursor.getString(NAME_INDEX)
val apn = cursor.getString(APN_INDEX)
val proxy = cursor.getString(PROXY_INDEX)
val port = cursor.getString(PORT_INDEX)
val userName = cursor.getString(USER_INDEX)
val server = cursor.getString(SERVER_INDEX)
val passWord = cursor.getString(PASSWORD_INDEX)
val mmsc = cursor.getString(MMSC_INDEX)
val mcc = cursor.getString(MCC_INDEX)
val mnc = cursor.getString(MNC_INDEX)
val mmsProxy = cursor.getString(MMSPROXY_INDEX)
val mmsPort = cursor.getString(MMSPORT_INDEX)
val authType = cursor.getInt(AUTH_TYPE_INDEX)
val apnType = cursor.getString(TYPE_INDEX)
val apnProtocol = convertProtocol2Options(cursor.getString(PROTOCOL_INDEX), context)
val apnRoaming =
convertProtocol2Options(cursor.getString(ROAMING_PROTOCOL_INDEX), context)
val apnEnable = cursor.getInt(CARRIER_ENABLED_INDEX) == 1
val networkType = cursor.getLong(NETWORK_TYPE_INDEX)
val mvnoType = cursor.getString(MVNO_TYPE_INDEX)
val mvnoValue = cursor.getString(MVNO_MATCH_DATA_INDEX)
val edited = cursor.getInt(EDITED_INDEX)
val userEditable = cursor.getInt(USER_EDITABLE_INDEX)
val carrierId = cursor.getInt(CARRIER_ID_INDEX)
apnData = apnData.copy(
name = name,
apn = apn,
proxy = proxy,
port = port,
userName = userName,
passWord = passWord,
server = server,
mmsc = mmsc,
mmsProxy = mmsProxy,
mmsPort = mmsPort,
mcc = mcc,
mnc = mnc,
authType = authType,
apnType = apnType,
apnProtocol = apnProtocolOptions.indexOf(apnProtocol),
apnRoaming = apnProtocolOptions.indexOf(apnRoaming),
apnEnable = apnEnable,
networkType = networkType,
mvnoType = mvnoTypeOptions.indexOf(mvnoType),
mvnoValue = mvnoValue,
edited = edited,
userEditable = userEditable,
carrierId = carrierId
)
}
}
if (apnData.name == "") {
Log.d(TAG, "Can't get apnData from Uri $uri")
}
return apnData
}
/**
* Returns The UI choice (e.g., "IPv4/IPv6") corresponding to the given
* raw value of the protocol preference (e.g., "IPV4V6"). If unknown,
* return null.
*
* @return UI choice
*/
private fun convertProtocol2Options(raw: String, context: Context): String {
val apnProtocolOptions = context.resources.getStringArray(R.array.apn_protocol_entries).toList()
val apnProtocolValues = context.resources.getStringArray(R.array.apn_protocol_values).toList()
var uRaw = raw.uppercase(Locale.getDefault())
uRaw = if (uRaw == "IPV4") "IP" else uRaw
val protocolIndex = apnProtocolValues.indexOf(uRaw)
return if (protocolIndex == -1) {
""
} else {
try {
apnProtocolOptions[protocolIndex]
} catch (e: ArrayIndexOutOfBoundsException) {
""
}
}
}

View File

@@ -16,8 +16,16 @@
package com.android.settings.network.apn package com.android.settings.network.apn
import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.provider.Telephony import android.provider.Telephony
import android.telephony.CarrierConfigManager
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import android.text.TextUtils
import android.util.Log
import com.android.internal.util.ArrayUtils
import com.android.settings.R
data class ApnData( data class ApnData(
val name: String = "", val name: String = "",
@@ -42,26 +50,147 @@ data class ApnData(
var mvnoValue: String = "", var mvnoValue: String = "",
val edited: Int = Telephony.Carriers.USER_EDITED, val edited: Int = Telephony.Carriers.USER_EDITED,
val userEditable: Int = 1, val userEditable: Int = 1,
val carrierId: Int = TelephonyManager.UNKNOWN_CARRIER_ID val carrierId: Int = TelephonyManager.UNKNOWN_CARRIER_ID,
) { val nameEnabled: Boolean = true,
var nameEnabled = true val apnEnabled: Boolean = true,
var apnEnabled = true val proxyEnabled: Boolean = true,
var proxyEnabled = true val portEnabled: Boolean = true,
var portEnabled = true val userNameEnabled: Boolean = true,
var userNameEnabled = true val passWordEnabled: Boolean = true,
var passWordEnabled = true val serverEnabled: Boolean = true,
var serverEnabled = true val mmscEnabled: Boolean = true,
var mmscEnabled = true val mmsProxyEnabled: Boolean = true,
var mmsProxyEnabled = true val mmsPortEnabled: Boolean = true,
var mmsPortEnabled = true val mccEnabled: Boolean = true,
var mccEnabled = true val mncEnabled: Boolean = true,
var mncEnabled = true val authTypeEnabled: Boolean = true,
var authTypeEnabled = true val apnTypeEnabled: Boolean = true,
var apnTypeEnabled = true val apnProtocolEnabled: Boolean = true,
var apnProtocolEnabled = true val apnRoamingEnabled: Boolean = true,
var apnRoamingEnabled = true val apnEnableEnabled: Boolean = true,
var apnEnableEnabled = true val networkTypeEnabled: Boolean = true,
var networkTypeEnabled = true val mvnoTypeEnabled: Boolean = true,
var mvnoTypeEnabled = true val mvnoValueEnabled: Boolean = false,
var mvnoValueEnabled = false val newApn: Boolean = false,
)
data class CustomizedConfig(
val newApn: Boolean = false,
val readOnlyApn: Boolean = false,
val isAddApnAllowed: Boolean = true,
val readOnlyApnTypes: List<String> = emptyList(),
val readOnlyApnFields: List<String> = emptyList(),
val defaultApnTypes: List<String> = emptyList(),
val defaultApnProtocol: String = "",
val defaultApnRoamingProtocol: String = "",
)
/**
* Initialize ApnData according to the arguments.
* @param arguments The data passed in when the user calls PageProvider.
* @param uriInit The decoded user incoming uri data in Page.
* @param subId The subId obtained in arguments.
*
* @return Initialized CustomizedConfig information.
*/
fun getApnDataInit(arguments: Bundle, context: Context, uriInit: Uri, subId: Int): ApnData {
val uriType = arguments.getString(URI_TYPE)!!
val mvnoType = arguments.getString(MVNO_TYPE)
val mvnoValue = arguments.getString(MVNO_MATCH_DATA)
val mvnoTypeOptions = context.resources.getStringArray(R.array.mvno_type_entries).toList()
val configManager =
context.getSystemService(Context.CARRIER_CONFIG_SERVICE) as CarrierConfigManager
getCarrierCustomizedConfig(configManager, subId)
if (!uriInit.isPathPrefixMatch(Telephony.Carriers.CONTENT_URI)) {
Log.e(TAG, "Insert request not for carrier table. Uri: $uriInit")
return ApnData() //TODO: finish
}
var apnDataInit = when (uriType) {
EDIT_URL -> getApnDataFromUri(uriInit, context)
INSERT_URL -> ApnData(
mvnoType = mvnoTypeOptions.indexOf(mvnoType!!),
mvnoValue = mvnoValue!!
)
else -> ApnData() //TODO: finish
}
if (uriType == INSERT_URL) {
apnDataInit = apnDataInit.copy(newApn = true)
}
// TODO: mvnoDescription
apnDataInit = apnDataInit.copy(
apnEnableEnabled =
context.resources.getBoolean(R.bool.config_allow_edit_carrier_enabled)
)
// TODO: mIsCarrierIdApn & disableInit(apnDataInit)
return apnDataInit
} }
/**
* Initialize CustomizedConfig information through subId.
* @param subId subId information obtained from arguments.
*
* @return Initialized CustomizedConfig information.
*/
fun getCarrierCustomizedConfig(configManager: CarrierConfigManager, subId: Int): CustomizedConfig {
val b = configManager.getConfigForSubId(
subId,
CarrierConfigManager.KEY_READ_ONLY_APN_TYPES_STRING_ARRAY,
CarrierConfigManager.KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY,
CarrierConfigManager.KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY,
CarrierConfigManager.Apn.KEY_SETTINGS_DEFAULT_PROTOCOL_STRING,
CarrierConfigManager.Apn.KEY_SETTINGS_DEFAULT_ROAMING_PROTOCOL_STRING,
CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL
)
val customizedConfig = CustomizedConfig(
readOnlyApnTypes = b.getStringArray(
CarrierConfigManager.KEY_READ_ONLY_APN_TYPES_STRING_ARRAY
)?.toList() ?: emptyList(), readOnlyApnFields = b.getStringArray(
CarrierConfigManager.KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY
)?.toList() ?: emptyList(), defaultApnTypes = b.getStringArray(
CarrierConfigManager.KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY
)?.toList() ?: emptyList(), defaultApnProtocol = b.getString(
CarrierConfigManager.Apn.KEY_SETTINGS_DEFAULT_PROTOCOL_STRING
) ?: "", defaultApnRoamingProtocol = b.getString(
CarrierConfigManager.Apn.KEY_SETTINGS_DEFAULT_ROAMING_PROTOCOL_STRING
) ?: "", isAddApnAllowed = b.getBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL)
)
if (!ArrayUtils.isEmpty(customizedConfig.readOnlyApnTypes)) {
Log.d(
TAG,
"getCarrierCustomizedConfig: read only APN type: " + customizedConfig.readOnlyApnTypes.joinToString(
", "
)
)
}
if (!ArrayUtils.isEmpty(customizedConfig.defaultApnTypes)) {
Log.d(
TAG,
"getCarrierCustomizedConfig: default apn types: " + customizedConfig.defaultApnTypes.joinToString(
", "
)
)
}
if (!TextUtils.isEmpty(customizedConfig.defaultApnProtocol)) {
Log.d(
TAG,
"getCarrierCustomizedConfig: default apn protocol: ${customizedConfig.defaultApnProtocol}"
)
}
if (!TextUtils.isEmpty(customizedConfig.defaultApnRoamingProtocol)) {
Log.d(
TAG,
"getCarrierCustomizedConfig: default apn roaming protocol: ${customizedConfig.defaultApnRoamingProtocol}"
)
}
if (!customizedConfig.isAddApnAllowed) {
Log.d(TAG, "getCarrierCustomizedConfig: not allow to add new APN")
}
return customizedConfig
}

View File

@@ -256,9 +256,9 @@ class ApnEditPageProviderTest {
.performScrollToNode(hasText(passwordTitle, true)) .performScrollToNode(hasText(passwordTitle, true))
composeTestRule.onNodeWithText(passwordTitle, true).assertIsDisplayed() composeTestRule.onNodeWithText(passwordTitle, true).assertIsDisplayed()
} }
private companion object { private companion object {
const val NETWORK_TYPE_UNSPECIFIED = "Unspecified" const val NETWORK_TYPE_UNSPECIFIED = "Unspecified"
const val NETWORK_TYPE_LTE = "LTE" const val NETWORK_TYPE_LTE = "LTE"
} }
} }

View File

@@ -0,0 +1,55 @@
/*
* 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.apn
import android.content.ContentResolver
import android.content.Context
import android.database.MatrixCursor
import android.net.Uri
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class ApnRepositoryTest {
private val context: Context = ApplicationProvider.getApplicationContext()
private val mContentResolver = mock<ContentResolver> {}
private val uri = mock<Uri> {}
@Test
fun getApnDataFromUri() {
// mock out resources and the feature provider
val cursor = MatrixCursor(sProjection)
cursor.addRow(
arrayOf<Any?>(
0, "name", "apn", "proxy", "port",
"userName", "server", "passWord", "mmsc", "mcc", "mnc", "numeric",
"mmsProxy", "mmsPort", 0, "apnType", "apnProtocol", 0,
0, "apnRoaming", "mvnoType", "mvnoValue", 0, 1, 0
)
)
val context = Mockito.spy(context)
whenever(context.contentResolver).thenReturn(mContentResolver)
whenever(mContentResolver.query(uri, sProjection, null, null, null)).thenReturn(cursor)
assert(getApnDataFromUri(uri, context).name == "name")
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.apn
import android.os.PersistableBundle
import android.telephony.CarrierConfigManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
@RunWith(AndroidJUnit4::class)
class ApnStatusTest {
private val subId = 1
private val configManager = mock<CarrierConfigManager> {
val p = PersistableBundle()
p.putBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL, true)
on {
getConfigForSubId(
subId,
CarrierConfigManager.KEY_READ_ONLY_APN_TYPES_STRING_ARRAY,
CarrierConfigManager.KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY,
CarrierConfigManager.KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY,
CarrierConfigManager.Apn.KEY_SETTINGS_DEFAULT_PROTOCOL_STRING,
CarrierConfigManager.Apn.KEY_SETTINGS_DEFAULT_ROAMING_PROTOCOL_STRING,
CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL
)
} doReturn p
}
@Test
fun getCarrierCustomizedConfig_test() {
assert(getCarrierCustomizedConfig(configManager, subId).isAddApnAllowed)
}
}