1 /*
<lambda>null2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.settings.network.apn
18
19 import android.content.ContentValues
20 import android.content.Context
21 import android.database.Cursor
22 import android.net.Uri
23 import android.provider.Telephony
24 import android.telephony.TelephonyManager
25 import android.util.Log
26 import com.android.settings.R
27 import com.android.settings.network.telephony.telephonyManager
28 import com.android.settingslib.utils.ThreadUtils
29 import java.util.Locale
30
31 val Projection = arrayOf(
32 Telephony.Carriers._ID, // 0
33 Telephony.Carriers.NAME, // 1
34 Telephony.Carriers.APN, // 2
35 Telephony.Carriers.PROXY, // 3
36 Telephony.Carriers.PORT, // 4
37 Telephony.Carriers.USER, // 5
38 Telephony.Carriers.SERVER, // 6
39 Telephony.Carriers.PASSWORD, // 7
40 Telephony.Carriers.MMSC, // 8
41 Telephony.Carriers.MMSPROXY, // 9
42 Telephony.Carriers.MMSPORT, // 10
43 Telephony.Carriers.AUTH_TYPE, // 11
44 Telephony.Carriers.TYPE, // 12
45 Telephony.Carriers.PROTOCOL, // 13
46 Telephony.Carriers.CARRIER_ENABLED, // 14
47 Telephony.Carriers.NETWORK_TYPE_BITMASK, // 15
48 Telephony.Carriers.ROAMING_PROTOCOL, // 16
49 Telephony.Carriers.EDITED_STATUS, // 17
50 Telephony.Carriers.USER_EDITABLE, // 18
51 )
52
53 private const val TAG = "ApnRepository"
54
55 /**
56 * Query apn related information based on uri.
57 * @param uri URI data used for query.
58 *
59 * @return Stored apn related information.
60 */
61 fun getApnDataFromUri(uri: Uri, context: Context): ApnData {
62 var apnData = ApnData()
63 val contentResolver = context.contentResolver
64
65 contentResolver.query(
66 uri,
67 Projection,
68 null /* selection */,
69 null /* selectionArgs */,
70 null /* sortOrder */
71 ).use { cursor ->
72 if (cursor != null && cursor.moveToFirst()) {
73 apnData = ApnData(
74 id = cursor.getInt(Telephony.Carriers._ID),
75 name = cursor.getString(Telephony.Carriers.NAME),
76 apn = cursor.getString(Telephony.Carriers.APN),
77 proxy = cursor.getString(Telephony.Carriers.PROXY),
78 port = cursor.getString(Telephony.Carriers.PORT),
79 userName = cursor.getString(Telephony.Carriers.USER),
80 passWord = cursor.getString(Telephony.Carriers.PASSWORD),
81 server = cursor.getString(Telephony.Carriers.SERVER),
82 mmsc = cursor.getString(Telephony.Carriers.MMSC),
83 mmsProxy = cursor.getString(Telephony.Carriers.MMSPROXY),
84 mmsPort = cursor.getString(Telephony.Carriers.MMSPORT),
85 authType = cursor.getInt(Telephony.Carriers.AUTH_TYPE),
86 apnType = cursor.getString(Telephony.Carriers.TYPE),
87 apnProtocol = context.convertProtocol2Options(
88 cursor.getString(Telephony.Carriers.PROTOCOL)
89 ),
90 apnRoaming = context.convertProtocol2Options(
91 cursor.getString(Telephony.Carriers.ROAMING_PROTOCOL)
92 ),
93 carrierEnabled = cursor.getInt(Telephony.Carriers.CARRIER_ENABLED) == 1,
94 networkType = cursor.getLong(Telephony.Carriers.NETWORK_TYPE_BITMASK),
95 edited = cursor.getInt(Telephony.Carriers.EDITED_STATUS),
96 userEditable = cursor.getInt(Telephony.Carriers.USER_EDITABLE),
97 )
98 }
99 }
100 if (apnData.name == "") {
101 Log.d(TAG, "Can't get apnData from Uri $uri")
102 }
103 return apnData
104 }
105
getStringnull106 private fun Cursor.getString(columnName: String) = getString(getColumnIndexOrThrow(columnName))
107 private fun Cursor.getInt(columnName: String) = getInt(getColumnIndexOrThrow(columnName))
108 private fun Cursor.getLong(columnName: String) = getLong(getColumnIndexOrThrow(columnName))
109
110 /**
111 * Returns The UI choice index corresponding to the given raw value of the protocol preference
112 * (e.g., "IPV4V6").
113 * If unknown, return -1.
114 */
115 private fun Context.convertProtocol2Options(protocol: String): Int {
116 var normalizedProtocol = protocol.uppercase(Locale.getDefault())
117 if (normalizedProtocol == "IPV4") normalizedProtocol = "IP"
118 return resources.getStringArray(R.array.apn_protocol_values).indexOf(normalizedProtocol)
119 }
120
Contextnull121 fun Context.convertOptions2Protocol(protocolIndex: Int): String =
122 resources.getStringArray(R.array.apn_protocol_values).getOrElse(protocolIndex) { "" }
123
updateApnDataToDatabasenull124 fun updateApnDataToDatabase(
125 newApn: Boolean,
126 values: ContentValues,
127 context: Context,
128 uriInit: Uri
129 ) {
130 ThreadUtils.postOnBackgroundThread {
131 if (newApn) {
132 Log.d(TAG, "Adding an new APN to the database $uriInit $values")
133 val newUri = context.contentResolver.insert(uriInit, values)
134 if (newUri == null) {
135 Log.e(TAG, "Can't add a new apn to database $uriInit")
136 }
137 } else {
138 Log.d(TAG, "Updating an existing APN to the database $uriInit $values")
139 context.contentResolver.update(
140 uriInit, values, null /* where */, null /* selection Args */
141 )
142 }
143 }
144 }
145
146 /** Not allowing add duplicated items, if the values of the following keys are all identical. */
147 private val NonDuplicatedKeys = setOf(
148 Telephony.Carriers.APN,
149 Telephony.Carriers.PROXY,
150 Telephony.Carriers.PORT,
151 Telephony.Carriers.MMSC,
152 Telephony.Carriers.MMSPROXY,
153 Telephony.Carriers.MMSPORT,
154 Telephony.Carriers.PROTOCOL,
155 Telephony.Carriers.ROAMING_PROTOCOL,
156 )
157
isItemExistnull158 fun isItemExist(apnData: ApnData, context: Context): String? {
159 val selectionMap = apnData.getContentValueMap(context).filterKeys { it in NonDuplicatedKeys }
160 .mapKeys { "${it.key} = ?" }
161 .toMutableMap()
162 if (apnData.id != -1) selectionMap += "${Telephony.Carriers._ID} != ?" to apnData.id
163 val list = selectionMap.entries.toList()
164 val selection = list.joinToString(" AND ") { it.key }
165 val selectionArgs: Array<String> = list.map { it.value.toString() }.toTypedArray()
166 context.contentResolver.query(
167 Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, apnData.subId.toString()),
168 /* projection = */ emptyArray(),
169 selection,
170 selectionArgs,
171 /* sortOrder = */ null,
172 )?.use { cursor ->
173 if (cursor.count > 0) {
174 return context.resources.getString(R.string.error_duplicate_apn_entry)
175 }
176 }
177 return null
178 }
179
Contextnull180 fun Context.getApnIdMap(subId: Int): Map<String, Any> {
181 val telephonyManager = telephonyManager(subId)
182 val carrierId = telephonyManager.simSpecificCarrierId
183 return if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
184 mapOf(Telephony.Carriers.CARRIER_ID to carrierId)
185 } else {
186 mapOf(Telephony.Carriers.NUMERIC to telephonyManager.simOperator)
187 }.also { Log.d(TAG, "[$subId] New APN item with id: $it") }
188 }
189