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.SubscriptionManager
25 import android.telephony.TelephonyManager
26 import android.util.Log
27 import com.android.settings.R
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 apnEnable = 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 subInfo = getSystemService(SubscriptionManager::class.java)!!
182 .getActiveSubscriptionInfo(subId)
183 val carrierId = subInfo.carrierId
184 return if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
185 mapOf(Telephony.Carriers.CARRIER_ID to carrierId)
186 } else {
187 mapOf(Telephony.Carriers.NUMERIC to subInfo.mccString + subInfo.mncString)
188 }.also { Log.d(TAG, "[$subId] New APN item with id: $it") }
189 }
190