TelephonyProvider.java revision 7c6edbe10dbbf1744b2b631ae23a5648f307fa14
1/* //device/content/providers/telephony/TelephonyProvider.java 2** 3** Copyright 2006, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18package com.android.providers.telephony; 19 20import android.content.ContentProvider; 21import android.content.ContentUris; 22import android.content.ContentValues; 23import android.content.Context; 24import android.content.SharedPreferences; 25import android.content.UriMatcher; 26import android.content.pm.PackageManager; 27import android.content.res.Resources; 28import android.content.res.XmlResourceParser; 29import android.database.Cursor; 30import android.database.SQLException; 31import android.database.sqlite.SQLiteDatabase; 32import android.database.sqlite.SQLiteException; 33import android.database.sqlite.SQLiteOpenHelper; 34import android.database.sqlite.SQLiteQueryBuilder; 35import android.net.Uri; 36import android.os.Binder; 37import android.os.Environment; 38import android.provider.Telephony; 39import android.telephony.SubscriptionManager; 40import android.telephony.TelephonyManager; 41import android.util.Log; 42import android.util.Xml; 43 44import com.android.internal.telephony.BaseCommands; 45import com.android.internal.telephony.Phone; 46import com.android.internal.telephony.PhoneConstants; 47import com.android.internal.util.XmlUtils; 48 49import org.xmlpull.v1.XmlPullParser; 50import org.xmlpull.v1.XmlPullParserException; 51 52import java.io.File; 53import java.io.FileNotFoundException; 54import java.io.FileReader; 55import java.io.IOException; 56import java.lang.NumberFormatException; 57 58public class TelephonyProvider extends ContentProvider 59{ 60 private static final String DATABASE_NAME = "telephony.db"; 61 private static final boolean DBG = true; 62 private static final boolean VDBG = false; 63 64 private static final int DATABASE_VERSION = 12 << 16; 65 private static final int URL_UNKNOWN = 0; 66 private static final int URL_TELEPHONY = 1; 67 private static final int URL_CURRENT = 2; 68 private static final int URL_ID = 3; 69 private static final int URL_RESTOREAPN = 4; 70 private static final int URL_PREFERAPN = 5; 71 private static final int URL_PREFERAPN_NO_UPDATE = 6; 72 private static final int URL_SIMINFO = 7; 73 private static final int URL_TELEPHONY_USING_SUBID = 8; 74 private static final int URL_CURRENT_USING_SUBID = 9; 75 private static final int URL_RESTOREAPN_USING_SUBID = 10; 76 private static final int URL_PREFERAPN_USING_SUBID = 11; 77 private static final int URL_PREFERAPN_NO_UPDATE_USING_SUBID = 12; 78 private static final int URL_SIMINFO_USING_SUBID = 13; 79 80 private static final String TAG = "TelephonyProvider"; 81 private static final String CARRIERS_TABLE = "carriers"; 82 private static final String SIMINFO_TABLE = "siminfo"; 83 84 private static final String PREF_FILE = "preferred-apn"; 85 private static final String COLUMN_APN_ID = "apn_id"; 86 87 private static final String PARTNER_APNS_PATH = "etc/apns-conf.xml"; 88 89 private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH); 90 91 private static final ContentValues s_currentNullMap; 92 private static final ContentValues s_currentSetMap; 93 94 static { 95 s_urlMatcher.addURI("telephony", "carriers", URL_TELEPHONY); 96 s_urlMatcher.addURI("telephony", "carriers/current", URL_CURRENT); 97 s_urlMatcher.addURI("telephony", "carriers/#", URL_ID); 98 s_urlMatcher.addURI("telephony", "carriers/restore", URL_RESTOREAPN); 99 s_urlMatcher.addURI("telephony", "carriers/preferapn", URL_PREFERAPN); 100 s_urlMatcher.addURI("telephony", "carriers/preferapn_no_update", URL_PREFERAPN_NO_UPDATE); 101 102 s_urlMatcher.addURI("telephony", "siminfo", URL_SIMINFO); 103 104 s_urlMatcher.addURI("telephony", "carriers/subId/*", URL_TELEPHONY_USING_SUBID); 105 s_urlMatcher.addURI("telephony", "carriers/current/subId/*", URL_CURRENT_USING_SUBID); 106 s_urlMatcher.addURI("telephony", "carriers/restore/subId/*", URL_RESTOREAPN_USING_SUBID); 107 s_urlMatcher.addURI("telephony", "carriers/preferapn/subId/*", URL_PREFERAPN_USING_SUBID); 108 s_urlMatcher.addURI("telephony", "carriers/preferapn_no_update/subId/*", 109 URL_PREFERAPN_NO_UPDATE_USING_SUBID); 110 111 112 s_currentNullMap = new ContentValues(1); 113 s_currentNullMap.put("current", (Long) null); 114 115 s_currentSetMap = new ContentValues(1); 116 s_currentSetMap.put("current", "1"); 117 } 118 119 private static class DatabaseHelper extends SQLiteOpenHelper { 120 // Context to access resources with 121 private Context mContext; 122 123 /** 124 * DatabaseHelper helper class for loading apns into a database. 125 * 126 * @param context of the user. 127 */ 128 public DatabaseHelper(Context context) { 129 super(context, DATABASE_NAME, null, getVersion(context)); 130 mContext = context; 131 } 132 133 private static int getVersion(Context context) { 134 if (VDBG) log("getVersion:+"); 135 // Get the database version, combining a static schema version and the XML version 136 Resources r = context.getResources(); 137 XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns); 138 try { 139 XmlUtils.beginDocument(parser, "apns"); 140 int publicversion = Integer.parseInt(parser.getAttributeValue(null, "version")); 141 int version = DATABASE_VERSION | publicversion; 142 if (VDBG) log("getVersion:- version=0x" + Integer.toHexString(version)); 143 return version; 144 } catch (Exception e) { 145 loge("Can't get version of APN database" + e + " return version=" + 146 Integer.toHexString(DATABASE_VERSION)); 147 return DATABASE_VERSION; 148 } finally { 149 parser.close(); 150 } 151 } 152 153 @Override 154 public void onCreate(SQLiteDatabase db) { 155 if (DBG) log("dbh.onCreate:+ db=" + db); 156 createSimInfoTable(db); 157 createCarriersTable(db); 158 initDatabase(db); 159 if (DBG) log("dbh.onCreate:- db=" + db); 160 } 161 162 @Override 163 public void onOpen(SQLiteDatabase db) { 164 if (VDBG) log("dbh.onOpen:+ db=" + db); 165 try { 166 // Try to access the table and create it if "no such table" 167 db.query(SIMINFO_TABLE, null, null, null, null, null, null); 168 if (DBG) log("dbh.onOpen: ok, queried table=" + SIMINFO_TABLE); 169 } catch (SQLiteException e) { 170 loge("Exception " + SIMINFO_TABLE + "e=" + e); 171 if (e.getMessage().startsWith("no such table")) { 172 createSimInfoTable(db); 173 } 174 } 175 try { 176 db.query(CARRIERS_TABLE, null, null, null, null, null, null); 177 if (DBG) log("dbh.onOpen: ok, queried table=" + CARRIERS_TABLE); 178 } catch (SQLiteException e) { 179 loge("Exception " + CARRIERS_TABLE + " e=" + e); 180 if (e.getMessage().startsWith("no such table")) { 181 createCarriersTable(db); 182 } 183 } 184 if (VDBG) log("dbh.onOpen:- db=" + db); 185 } 186 187 private void createSimInfoTable(SQLiteDatabase db) { 188 if (DBG) log("dbh.createSimInfoTable:+"); 189 db.execSQL("CREATE TABLE " + SIMINFO_TABLE + "(" 190 + "_id INTEGER PRIMARY KEY AUTOINCREMENT," 191 + SubscriptionManager.ICC_ID + " TEXT NOT NULL," 192 + SubscriptionManager.SIM_ID + " INTEGER DEFAULT " + SubscriptionManager.SIM_NOT_INSERTED + "," 193 + SubscriptionManager.DISPLAY_NAME + " TEXT," 194 + SubscriptionManager.NAME_SOURCE + " INTEGER DEFAULT " + SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE + "," 195 + SubscriptionManager.COLOR + " INTEGER DEFAULT " + SubscriptionManager.COLOR_DEFAULT + "," 196 + SubscriptionManager.NUMBER + " TEXT," 197 + SubscriptionManager.DISPLAY_NUMBER_FORMAT + " INTEGER NOT NULL DEFAULT " + SubscriptionManager.DISLPAY_NUMBER_DEFAULT + "," 198 + SubscriptionManager.DATA_ROAMING + " INTEGER DEFAULT " + SubscriptionManager.DATA_ROAMING_DEFAULT + "," 199 + SubscriptionManager.MCC + " INTEGER DEFAULT 0," 200 + SubscriptionManager.MNC + " INTEGER DEFAULT 0" 201 + ");"); 202 if (DBG) log("dbh.createSimInfoTable:-"); 203 } 204 205 private void createCarriersTable(SQLiteDatabase db) { 206 // Set up the database schema 207 if (DBG) log("dbh.createCarriersTable:+"); 208 db.execSQL("CREATE TABLE " + CARRIERS_TABLE + 209 "(_id INTEGER PRIMARY KEY," + 210 "name TEXT," + 211 "numeric TEXT," + 212 "mcc TEXT," + 213 "mnc TEXT," + 214 "apn TEXT," + 215 "user TEXT," + 216 "server TEXT," + 217 "password TEXT," + 218 "proxy TEXT," + 219 "port TEXT," + 220 "mmsproxy TEXT," + 221 "mmsport TEXT," + 222 "mmsc TEXT," + 223 "authtype INTEGER," + 224 "type TEXT," + 225 "current INTEGER," + 226 "protocol TEXT," + 227 "roaming_protocol TEXT," + 228 "carrier_enabled BOOLEAN," + 229 "bearer INTEGER," + 230 "mvno_type TEXT," + 231 "mvno_match_data TEXT," + 232 "sub_id LONG DEFAULT -1," + 233 "profile_id INTEGER default 0," + 234 "modem_cognitive BOOLEAN default 0," + 235 "max_conns INTEGER default 0," + 236 "wait_time INTEGER default 0," + 237 "max_conns_time INTEGER default 0," + 238 "mtu INTEGER);"); 239 /* FIXME Currenlty sub_id is column is not used for query purpose. 240 This would be modified to more appropriate default value later. */ 241 if (DBG) log("dbh.createCarriersTable:-"); 242 } 243 private void initDatabase(SQLiteDatabase db) { 244 if (VDBG) log("dbh.initDatabase:+ db=" + db); 245 // Read internal APNS data 246 Resources r = mContext.getResources(); 247 XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns); 248 int publicversion = -1; 249 try { 250 XmlUtils.beginDocument(parser, "apns"); 251 publicversion = Integer.parseInt(parser.getAttributeValue(null, "version")); 252 loadApns(db, parser); 253 } catch (Exception e) { 254 loge("Got exception while loading APN database." + e); 255 } finally { 256 parser.close(); 257 } 258 259 // Read external APNS data (partner-provided) 260 XmlPullParser confparser = null; 261 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 262 File confFile = new File(Environment.getRootDirectory(), PARTNER_APNS_PATH); 263 FileReader confreader = null; 264 try { 265 confreader = new FileReader(confFile); 266 confparser = Xml.newPullParser(); 267 confparser.setInput(confreader); 268 XmlUtils.beginDocument(confparser, "apns"); 269 270 // Sanity check. Force internal version and confidential versions to agree 271 int confversion = Integer.parseInt(confparser.getAttributeValue(null, "version")); 272 if (publicversion != confversion) { 273 throw new IllegalStateException("Internal APNS file version doesn't match " 274 + confFile.getAbsolutePath()); 275 } 276 277 loadApns(db, confparser); 278 } catch (FileNotFoundException e) { 279 // It's ok if the file isn't found. It means there isn't a confidential file 280 // Log.e(TAG, "File not found: '" + confFile.getAbsolutePath() + "'"); 281 } catch (Exception e) { 282 loge("Exception while parsing '" + confFile.getAbsolutePath() + "'" + e); 283 } finally { 284 try { if (confreader != null) confreader.close(); } catch (IOException e) { } 285 } 286 if (VDBG) log("dbh.initDatabase:- db=" + db); 287 288 } 289 290 @Override 291 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 292 if (DBG) { 293 log("dbh.onUpgrade:+ db=" + db + " oldV=" + oldVersion + " newV=" + newVersion); 294 } 295 296 if (oldVersion < (5 << 16 | 6)) { 297 // 5 << 16 is the Database version and 6 in the xml version. 298 299 // This change adds a new authtype column to the database. 300 // The auth type column can have 4 values: 0 (None), 1 (PAP), 2 (CHAP) 301 // 3 (PAP or CHAP). To avoid breaking compatibility, with already working 302 // APNs, the unset value (-1) will be used. If the value is -1. 303 // the authentication will default to 0 (if no user / password) is specified 304 // or to 3. Currently, there have been no reported problems with 305 // pre-configured APNs and hence it is set to -1 for them. Similarly, 306 // if the user, has added a new APN, we set the authentication type 307 // to -1. 308 309 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 310 " ADD COLUMN authtype INTEGER DEFAULT -1;"); 311 312 oldVersion = 5 << 16 | 6; 313 } 314 if (oldVersion < (6 << 16 | 6)) { 315 // Add protcol fields to the APN. The XML file does not change. 316 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 317 " ADD COLUMN protocol TEXT DEFAULT IP;"); 318 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 319 " ADD COLUMN roaming_protocol TEXT DEFAULT IP;"); 320 oldVersion = 6 << 16 | 6; 321 } 322 if (oldVersion < (7 << 16 | 6)) { 323 // Add carrier_enabled, bearer fields to the APN. The XML file does not change. 324 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 325 " ADD COLUMN carrier_enabled BOOLEAN DEFAULT 1;"); 326 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 327 " ADD COLUMN bearer INTEGER DEFAULT 0;"); 328 oldVersion = 7 << 16 | 6; 329 } 330 if (oldVersion < (8 << 16 | 6)) { 331 // Add mvno_type, mvno_match_data fields to the APN. 332 // The XML file does not change. 333 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 334 " ADD COLUMN mvno_type TEXT DEFAULT '';"); 335 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 336 " ADD COLUMN mvno_match_data TEXT DEFAULT '';"); 337 oldVersion = 8 << 16 | 6; 338 } 339 if (oldVersion < (9 << 16 | 6)) { 340 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 341 " ADD COLUMN sub_id LONG DEFAULT -1;"); 342 oldVersion = 9 << 16 | 6; 343 } 344 if (oldVersion < (10 << 16 | 6)) { 345 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 346 " ADD COLUMN profile_id INTEGER DEFAULT 0;"); 347 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 348 " ADD COLUMN modem_cognitive BOOLEAN DEFAULT 0;"); 349 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 350 " ADD COLUMN max_conns INTEGER DEFAULT 0;"); 351 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 352 " ADD COLUMN wait_time INTEGER DEFAULT 0;"); 353 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 354 " ADD COLUMN max_conns_time INTEGER DEFAULT 0;"); 355 oldVersion = 10 << 16 | 6; 356 } 357 if (oldVersion < (11 << 16 | 6)) { 358 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 359 " ADD COLUMN mtu INTEGER DEFAULT 0;"); 360 oldVersion = 11 << 16 | 6; 361 } 362 if (oldVersion < (12 << 16 | 6)) { 363 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + 364 " ADD COLUMN " + SubscriptionManager.MCC + " INTEGER DEFAULT 0;"); 365 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + 366 " ADD COLUMN " + SubscriptionManager.MNC + " INTEGER DEFAULT 0;"); 367 oldVersion = 12 << 16 | 6; 368 } 369 if (DBG) { 370 log("dbh.onUpgrade:- db=" + db + " oldV=" + oldVersion + " newV=" + newVersion); 371 } 372 } 373 374 /** 375 * Gets the next row of apn values. 376 * 377 * @param parser the parser 378 * @return the row or null if it's not an apn 379 */ 380 private ContentValues getRow(XmlPullParser parser) { 381 if (!"apn".equals(parser.getName())) { 382 return null; 383 } 384 385 ContentValues map = new ContentValues(); 386 387 String mcc = parser.getAttributeValue(null, "mcc"); 388 String mnc = parser.getAttributeValue(null, "mnc"); 389 String numeric = mcc + mnc; 390 391 map.put(Telephony.Carriers.NUMERIC,numeric); 392 map.put(Telephony.Carriers.MCC, mcc); 393 map.put(Telephony.Carriers.MNC, mnc); 394 map.put(Telephony.Carriers.NAME, parser.getAttributeValue(null, "carrier")); 395 map.put(Telephony.Carriers.APN, parser.getAttributeValue(null, "apn")); 396 map.put(Telephony.Carriers.USER, parser.getAttributeValue(null, "user")); 397 map.put(Telephony.Carriers.SERVER, parser.getAttributeValue(null, "server")); 398 map.put(Telephony.Carriers.PASSWORD, parser.getAttributeValue(null, "password")); 399 400 // do not add NULL to the map so that insert() will set the default value 401 String proxy = parser.getAttributeValue(null, "proxy"); 402 if (proxy != null) { 403 map.put(Telephony.Carriers.PROXY, proxy); 404 } 405 String port = parser.getAttributeValue(null, "port"); 406 if (port != null) { 407 map.put(Telephony.Carriers.PORT, port); 408 } 409 String mmsproxy = parser.getAttributeValue(null, "mmsproxy"); 410 if (mmsproxy != null) { 411 map.put(Telephony.Carriers.MMSPROXY, mmsproxy); 412 } 413 String mmsport = parser.getAttributeValue(null, "mmsport"); 414 if (mmsport != null) { 415 map.put(Telephony.Carriers.MMSPORT, mmsport); 416 } 417 map.put(Telephony.Carriers.MMSC, parser.getAttributeValue(null, "mmsc")); 418 String type = parser.getAttributeValue(null, "type"); 419 if (type != null) { 420 map.put(Telephony.Carriers.TYPE, type); 421 } 422 423 String auth = parser.getAttributeValue(null, "authtype"); 424 if (auth != null) { 425 map.put(Telephony.Carriers.AUTH_TYPE, Integer.parseInt(auth)); 426 } 427 428 String protocol = parser.getAttributeValue(null, "protocol"); 429 if (protocol != null) { 430 map.put(Telephony.Carriers.PROTOCOL, protocol); 431 } 432 433 String roamingProtocol = parser.getAttributeValue(null, "roaming_protocol"); 434 if (roamingProtocol != null) { 435 map.put(Telephony.Carriers.ROAMING_PROTOCOL, roamingProtocol); 436 } 437 438 String carrierEnabled = parser.getAttributeValue(null, "carrier_enabled"); 439 if (carrierEnabled != null) { 440 map.put(Telephony.Carriers.CARRIER_ENABLED, Boolean.parseBoolean(carrierEnabled)); 441 } 442 443 String bearer = parser.getAttributeValue(null, "bearer"); 444 if (bearer != null) { 445 map.put(Telephony.Carriers.BEARER, Integer.parseInt(bearer)); 446 } 447 448 String mvno_type = parser.getAttributeValue(null, "mvno_type"); 449 if (mvno_type != null) { 450 String mvno_match_data = parser.getAttributeValue(null, "mvno_match_data"); 451 if (mvno_match_data != null) { 452 map.put(Telephony.Carriers.MVNO_TYPE, mvno_type); 453 map.put(Telephony.Carriers.MVNO_MATCH_DATA, mvno_match_data); 454 } 455 } 456 457 String profileId = parser.getAttributeValue(null, "profile_id"); 458 if (profileId != null) { 459 map.put(Telephony.Carriers.PROFILE_ID, Integer.parseInt(profileId)); 460 } 461 462 String modemCognitive = parser.getAttributeValue(null, "modem_cognitive"); 463 if (carrierEnabled != null) { 464 map.put(Telephony.Carriers.MODEM_COGNITIVE, Boolean.parseBoolean(modemCognitive)); 465 } 466 467 String maxConns = parser.getAttributeValue(null, "max_conns"); 468 if (maxConns != null) { 469 map.put(Telephony.Carriers.MAX_CONNS, Integer.parseInt(maxConns)); 470 } 471 472 String waitTime = parser.getAttributeValue(null, "wait_time"); 473 if (waitTime != null) { 474 map.put(Telephony.Carriers.WAIT_TIME, Integer.parseInt(waitTime)); 475 } 476 477 String maxConnsTime = parser.getAttributeValue(null, "max_conns_time"); 478 if (maxConnsTime != null) { 479 map.put(Telephony.Carriers.MAX_CONNS_TIME, Integer.parseInt(maxConnsTime)); 480 } 481 482 String mtu = parser.getAttributeValue(null, "mtu"); 483 if (mtu != null) { 484 map.put(Telephony.Carriers.MTU, Integer.parseInt(mtu)); 485 } 486 487 return map; 488 } 489 490 /* 491 * Loads apns from xml file into the database 492 * 493 * @param db the sqlite database to write to 494 * @param parser the xml parser 495 * 496 */ 497 private void loadApns(SQLiteDatabase db, XmlPullParser parser) { 498 if (parser != null) { 499 try { 500 db.beginTransaction(); 501 XmlUtils.nextElement(parser); 502 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { 503 ContentValues row = getRow(parser); 504 if (row == null) { 505 throw new XmlPullParserException("Expected 'apn' tag", parser, null); 506 } 507 insertAddingDefaults(db, CARRIERS_TABLE, row); 508 XmlUtils.nextElement(parser); 509 } 510 db.setTransactionSuccessful(); 511 } catch (XmlPullParserException e) { 512 loge("Got XmlPullParserException while loading apns." + e); 513 } catch (IOException e) { 514 loge("Got IOException while loading apns." + e); 515 } catch (SQLException e) { 516 loge("Got SQLException while loading apns." + e); 517 } finally { 518 db.endTransaction(); 519 } 520 } 521 } 522 523 static public ContentValues setDefaultValue(ContentValues values) { 524 if (!values.containsKey(Telephony.Carriers.NAME)) { 525 values.put(Telephony.Carriers.NAME, ""); 526 } 527 if (!values.containsKey(Telephony.Carriers.APN)) { 528 values.put(Telephony.Carriers.APN, ""); 529 } 530 if (!values.containsKey(Telephony.Carriers.PORT)) { 531 values.put(Telephony.Carriers.PORT, ""); 532 } 533 if (!values.containsKey(Telephony.Carriers.PROXY)) { 534 values.put(Telephony.Carriers.PROXY, ""); 535 } 536 if (!values.containsKey(Telephony.Carriers.USER)) { 537 values.put(Telephony.Carriers.USER, ""); 538 } 539 if (!values.containsKey(Telephony.Carriers.SERVER)) { 540 values.put(Telephony.Carriers.SERVER, ""); 541 } 542 if (!values.containsKey(Telephony.Carriers.PASSWORD)) { 543 values.put(Telephony.Carriers.PASSWORD, ""); 544 } 545 if (!values.containsKey(Telephony.Carriers.MMSPORT)) { 546 values.put(Telephony.Carriers.MMSPORT, ""); 547 } 548 if (!values.containsKey(Telephony.Carriers.MMSPROXY)) { 549 values.put(Telephony.Carriers.MMSPROXY, ""); 550 } 551 if (!values.containsKey(Telephony.Carriers.AUTH_TYPE)) { 552 values.put(Telephony.Carriers.AUTH_TYPE, -1); 553 } 554 if (!values.containsKey(Telephony.Carriers.PROTOCOL)) { 555 values.put(Telephony.Carriers.PROTOCOL, "IP"); 556 } 557 if (!values.containsKey(Telephony.Carriers.ROAMING_PROTOCOL)) { 558 values.put(Telephony.Carriers.ROAMING_PROTOCOL, "IP"); 559 } 560 if (!values.containsKey(Telephony.Carriers.CARRIER_ENABLED)) { 561 values.put(Telephony.Carriers.CARRIER_ENABLED, true); 562 } 563 if (!values.containsKey(Telephony.Carriers.BEARER)) { 564 values.put(Telephony.Carriers.BEARER, 0); 565 } 566 if (!values.containsKey(Telephony.Carriers.MVNO_TYPE)) { 567 values.put(Telephony.Carriers.MVNO_TYPE, ""); 568 } 569 if (!values.containsKey(Telephony.Carriers.MVNO_MATCH_DATA)) { 570 values.put(Telephony.Carriers.MVNO_MATCH_DATA, ""); 571 } 572 573 long subId = SubscriptionManager.getDefaultSubId(); 574 if (!values.containsKey(Telephony.Carriers.SUB_ID)) { 575 values.put(Telephony.Carriers.SUB_ID, subId); 576 } 577 578 if (!values.containsKey(Telephony.Carriers.PROFILE_ID)) { 579 values.put(Telephony.Carriers.PROFILE_ID, 0); 580 } 581 if (!values.containsKey(Telephony.Carriers.MODEM_COGNITIVE)) { 582 values.put(Telephony.Carriers.MODEM_COGNITIVE, false); 583 } 584 if (!values.containsKey(Telephony.Carriers.MAX_CONNS)) { 585 values.put(Telephony.Carriers.MAX_CONNS, 0); 586 } 587 if (!values.containsKey(Telephony.Carriers.WAIT_TIME)) { 588 values.put(Telephony.Carriers.WAIT_TIME, 0); 589 } 590 if (!values.containsKey(Telephony.Carriers.MAX_CONNS_TIME)) { 591 values.put(Telephony.Carriers.MAX_CONNS_TIME, 0); 592 } 593 594 return values; 595 } 596 597 private void insertAddingDefaults(SQLiteDatabase db, String table, ContentValues row) { 598 row = setDefaultValue(row); 599 db.insert(CARRIERS_TABLE, null, row); 600 } 601 } 602 603 @Override 604 public boolean onCreate() { 605 if (VDBG) log("onCreate:+"); 606 mOpenHelper = new DatabaseHelper(getContext()); 607 if (VDBG) log("onCreate:- ret true"); 608 return true; 609 } 610 611 private void setPreferredApnId(Long id, long subId) { 612 SharedPreferences sp = getContext().getSharedPreferences( 613 PREF_FILE + subId, Context.MODE_PRIVATE); 614 SharedPreferences.Editor editor = sp.edit(); 615 editor.putLong(COLUMN_APN_ID, id != null ? id.longValue() : -1); 616 editor.apply(); 617 } 618 619 private long getPreferredApnId(long subId) { 620 SharedPreferences sp = getContext().getSharedPreferences( 621 PREF_FILE + subId, Context.MODE_PRIVATE); 622 return sp.getLong(COLUMN_APN_ID, -1); 623 } 624 625 @Override 626 public Cursor query(Uri url, String[] projectionIn, String selection, 627 String[] selectionArgs, String sort) { 628 TelephonyManager mTelephonyManager = 629 (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE); 630 long subId = SubscriptionManager.getDefaultSubId(); 631 String subIdString; 632 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 633 qb.setStrict(true); // a little protection from injection attacks 634 qb.setTables("carriers"); 635 636 int match = s_urlMatcher.match(url); 637 switch (match) { 638 case URL_TELEPHONY_USING_SUBID: { 639 subIdString = url.getLastPathSegment(); 640 try { 641 subId = Long.parseLong(subIdString); 642 } catch (NumberFormatException e) { 643 loge("NumberFormatException" + e); 644 return null; 645 } 646 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 647 qb.appendWhere("numeric = " + mTelephonyManager.getSimOperator(subId)); 648 // FIXME alter the selection to pass subId 649 // selection = selection + "and subId = " 650 } 651 //intentional fall through from above case 652 // do nothing 653 case URL_TELEPHONY: { 654 break; 655 } 656 657 case URL_CURRENT_USING_SUBID: { 658 subIdString = url.getLastPathSegment(); 659 try { 660 subId = Long.parseLong(subIdString); 661 } catch (NumberFormatException e) { 662 loge("NumberFormatException" + e); 663 return null; 664 } 665 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 666 // FIXME alter the selection to pass subId 667 // selection = selection + "and subId = " 668 } 669 //intentional fall through from above case 670 case URL_CURRENT: { 671 qb.appendWhere("current IS NOT NULL"); 672 // do not ignore the selection since MMS may use it. 673 //selection = null; 674 break; 675 } 676 677 case URL_ID: { 678 qb.appendWhere("_id = " + url.getPathSegments().get(1)); 679 break; 680 } 681 682 case URL_PREFERAPN_USING_SUBID: 683 case URL_PREFERAPN_NO_UPDATE_USING_SUBID: { 684 subIdString = url.getLastPathSegment(); 685 try { 686 subId = Long.parseLong(subIdString); 687 } catch (NumberFormatException e) { 688 loge("NumberFormatException" + e); 689 return null; 690 } 691 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 692 } 693 //intentional fall through from above case 694 case URL_PREFERAPN: 695 case URL_PREFERAPN_NO_UPDATE: { 696 qb.appendWhere("_id = " + getPreferredApnId(subId)); 697 break; 698 } 699 700 case URL_SIMINFO: { 701 qb.setTables(SIMINFO_TABLE); 702 break; 703 } 704 705 default: { 706 return null; 707 } 708 } 709 710 if (match != URL_SIMINFO) { 711 if (projectionIn != null) { 712 for (String column : projectionIn) { 713 if (Telephony.Carriers.TYPE.equals(column) || 714 Telephony.Carriers.MMSC.equals(column) || 715 Telephony.Carriers.MMSPROXY.equals(column) || 716 Telephony.Carriers.MMSPORT.equals(column) || 717 Telephony.Carriers.APN.equals(column)) { 718 // noop 719 } else { 720 checkPermission(); 721 break; 722 } 723 } 724 } else { 725 // null returns all columns, so need permission check 726 checkPermission(); 727 } 728 } 729 730 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 731 Cursor ret = null; 732 try { 733 ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort); 734 } catch (SQLException e) { 735 loge("got exception when querying: " + e); 736 } 737 if (ret != null) 738 ret.setNotificationUri(getContext().getContentResolver(), url); 739 return ret; 740 } 741 742 @Override 743 public String getType(Uri url) 744 { 745 switch (s_urlMatcher.match(url)) { 746 case URL_TELEPHONY: 747 case URL_TELEPHONY_USING_SUBID: 748 return "vnd.android.cursor.dir/telephony-carrier"; 749 750 case URL_ID: 751 return "vnd.android.cursor.item/telephony-carrier"; 752 753 case URL_PREFERAPN_USING_SUBID: 754 case URL_PREFERAPN_NO_UPDATE_USING_SUBID: 755 case URL_PREFERAPN: 756 case URL_PREFERAPN_NO_UPDATE: 757 return "vnd.android.cursor.item/telephony-carrier"; 758 759 default: 760 throw new IllegalArgumentException("Unknown URL " + url); 761 } 762 } 763 764 @Override 765 public Uri insert(Uri url, ContentValues initialValues) 766 { 767 Uri result = null; 768 long subId = SubscriptionManager.getDefaultSubId(); 769 770 checkPermission(); 771 772 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 773 int match = s_urlMatcher.match(url); 774 boolean notify = false; 775 switch (match) 776 { 777 case URL_TELEPHONY_USING_SUBID: 778 { 779 String subIdString = url.getLastPathSegment(); 780 try { 781 subId = Long.parseLong(subIdString); 782 } catch (NumberFormatException e) { 783 loge("NumberFormatException" + e); 784 return result; 785 } 786 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 787 } 788 //intentional fall through from above case 789 790 case URL_TELEPHONY: 791 { 792 ContentValues values; 793 if (initialValues != null) { 794 values = new ContentValues(initialValues); 795 } else { 796 values = new ContentValues(); 797 } 798 799 values = DatabaseHelper.setDefaultValue(values); 800 801 long rowID = db.insert(CARRIERS_TABLE, null, values); 802 if (rowID > 0) 803 { 804 result = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, rowID); 805 notify = true; 806 } 807 808 if (VDBG) log("inserted " + values.toString() + " rowID = " + rowID); 809 break; 810 } 811 812 case URL_CURRENT_USING_SUBID: 813 { 814 String subIdString = url.getLastPathSegment(); 815 try { 816 subId = Long.parseLong(subIdString); 817 } catch (NumberFormatException e) { 818 loge("NumberFormatException" + e); 819 return result; 820 } 821 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 822 // FIXME use subId in the query 823 } 824 //intentional fall through from above case 825 826 case URL_CURRENT: 827 { 828 // null out the previous operator 829 db.update("carriers", s_currentNullMap, "current IS NOT NULL", null); 830 831 String numeric = initialValues.getAsString("numeric"); 832 int updated = db.update("carriers", s_currentSetMap, 833 "numeric = '" + numeric + "'", null); 834 835 if (updated > 0) 836 { 837 if (VDBG) log("Setting numeric '" + numeric + "' to be the current operator"); 838 } 839 else 840 { 841 loge("Failed setting numeric '" + numeric + "' to the current operator"); 842 } 843 break; 844 } 845 846 case URL_PREFERAPN_USING_SUBID: 847 case URL_PREFERAPN_NO_UPDATE_USING_SUBID: 848 { 849 String subIdString = url.getLastPathSegment(); 850 try { 851 subId = Long.parseLong(subIdString); 852 } catch (NumberFormatException e) { 853 loge("NumberFormatException" + e); 854 return result; 855 } 856 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 857 } 858 //intentional fall through from above case 859 860 case URL_PREFERAPN: 861 case URL_PREFERAPN_NO_UPDATE: 862 { 863 if (initialValues != null) { 864 if(initialValues.containsKey(COLUMN_APN_ID)) { 865 setPreferredApnId(initialValues.getAsLong(COLUMN_APN_ID), subId); 866 } 867 } 868 break; 869 } 870 871 case URL_SIMINFO: { 872 long id = db.insert(SIMINFO_TABLE, null, initialValues); 873 result = ContentUris.withAppendedId(SubscriptionManager.CONTENT_URI, id); 874 break; 875 } 876 } 877 878 if (notify) { 879 getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null); 880 } 881 882 return result; 883 } 884 885 @Override 886 public int delete(Uri url, String where, String[] whereArgs) 887 { 888 int count = 0; 889 long subId = SubscriptionManager.getDefaultSubId(); 890 891 checkPermission(); 892 893 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 894 int match = s_urlMatcher.match(url); 895 switch (match) 896 { 897 case URL_TELEPHONY_USING_SUBID: 898 { 899 String subIdString = url.getLastPathSegment(); 900 try { 901 subId = Long.parseLong(subIdString); 902 } catch (NumberFormatException e) { 903 loge("NumberFormatException" + e); 904 throw new IllegalArgumentException("Invalid subId " + url); 905 } 906 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 907 // FIXME use subId in query 908 } 909 //intentional fall through from above case 910 911 case URL_TELEPHONY: 912 { 913 count = db.delete(CARRIERS_TABLE, where, whereArgs); 914 break; 915 } 916 917 case URL_CURRENT_USING_SUBID: { 918 String subIdString = url.getLastPathSegment(); 919 try { 920 subId = Long.parseLong(subIdString); 921 } catch (NumberFormatException e) { 922 loge("NumberFormatException" + e); 923 throw new IllegalArgumentException("Invalid subId " + url); 924 } 925 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 926 // FIXME use subId in query 927 } 928 //intentional fall through from above case 929 930 case URL_CURRENT: 931 { 932 count = db.delete(CARRIERS_TABLE, where, whereArgs); 933 break; 934 } 935 936 case URL_ID: 937 { 938 count = db.delete(CARRIERS_TABLE, Telephony.Carriers._ID + "=?", 939 new String[] { url.getLastPathSegment() }); 940 break; 941 } 942 943 case URL_RESTOREAPN_USING_SUBID: { 944 String subIdString = url.getLastPathSegment(); 945 try { 946 subId = Long.parseLong(subIdString); 947 } catch (NumberFormatException e) { 948 loge("NumberFormatException" + e); 949 throw new IllegalArgumentException("Invalid subId " + url); 950 } 951 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 952 // FIXME use subId in query 953 } 954 case URL_RESTOREAPN: { 955 count = 1; 956 restoreDefaultAPN(subId); 957 break; 958 } 959 960 case URL_PREFERAPN_USING_SUBID: 961 case URL_PREFERAPN_NO_UPDATE_USING_SUBID: { 962 String subIdString = url.getLastPathSegment(); 963 try { 964 subId = Long.parseLong(subIdString); 965 } catch (NumberFormatException e) { 966 loge("NumberFormatException" + e); 967 throw new IllegalArgumentException("Invalid subId " + url); 968 } 969 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 970 } 971 //intentional fall through from above case 972 973 case URL_PREFERAPN: 974 case URL_PREFERAPN_NO_UPDATE: 975 { 976 setPreferredApnId((long)-1, subId); 977 if ((match == URL_PREFERAPN) || (match == URL_PREFERAPN_USING_SUBID)) count = 1; 978 break; 979 } 980 981 case URL_SIMINFO: { 982 count = db.delete(SIMINFO_TABLE, where, whereArgs); 983 break; 984 } 985 986 default: { 987 throw new UnsupportedOperationException("Cannot delete that URL: " + url); 988 } 989 } 990 991 if (count > 0) { 992 getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null); 993 } 994 995 return count; 996 } 997 998 @Override 999 public int update(Uri url, ContentValues values, String where, String[] whereArgs) 1000 { 1001 int count = 0; 1002 int uriType = URL_UNKNOWN; 1003 long subId = SubscriptionManager.getDefaultSubId(); 1004 1005 checkPermission(); 1006 1007 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1008 int match = s_urlMatcher.match(url); 1009 switch (match) 1010 { 1011 case URL_TELEPHONY_USING_SUBID: 1012 { 1013 String subIdString = url.getLastPathSegment(); 1014 try { 1015 subId = Long.parseLong(subIdString); 1016 } catch (NumberFormatException e) { 1017 loge("NumberFormatException" + e); 1018 throw new IllegalArgumentException("Invalid subId " + url); 1019 } 1020 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 1021 //FIXME use subId in the query 1022 } 1023 //intentional fall through from above case 1024 1025 case URL_TELEPHONY: 1026 { 1027 count = db.update(CARRIERS_TABLE, values, where, whereArgs); 1028 break; 1029 } 1030 1031 case URL_CURRENT_USING_SUBID: 1032 { 1033 String subIdString = url.getLastPathSegment(); 1034 try { 1035 subId = Long.parseLong(subIdString); 1036 } catch (NumberFormatException e) { 1037 loge("NumberFormatException" + e); 1038 throw new IllegalArgumentException("Invalid subId " + url); 1039 } 1040 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 1041 //FIXME use subId in the query 1042 } 1043 //intentional fall through from above case 1044 1045 case URL_CURRENT: 1046 { 1047 count = db.update(CARRIERS_TABLE, values, where, whereArgs); 1048 break; 1049 } 1050 1051 case URL_ID: 1052 { 1053 if (where != null || whereArgs != null) { 1054 throw new UnsupportedOperationException( 1055 "Cannot update URL " + url + " with a where clause"); 1056 } 1057 count = db.update(CARRIERS_TABLE, values, Telephony.Carriers._ID + "=?", 1058 new String[] { url.getLastPathSegment() }); 1059 break; 1060 } 1061 1062 case URL_PREFERAPN_USING_SUBID: 1063 case URL_PREFERAPN_NO_UPDATE_USING_SUBID: 1064 { 1065 String subIdString = url.getLastPathSegment(); 1066 try { 1067 subId = Long.parseLong(subIdString); 1068 } catch (NumberFormatException e) { 1069 loge("NumberFormatException" + e); 1070 throw new IllegalArgumentException("Invalid subId " + url); 1071 } 1072 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 1073 } 1074 1075 case URL_PREFERAPN: 1076 case URL_PREFERAPN_NO_UPDATE: 1077 { 1078 if (values != null) { 1079 if (values.containsKey(COLUMN_APN_ID)) { 1080 setPreferredApnId(values.getAsLong(COLUMN_APN_ID), subId); 1081 if ((match == URL_PREFERAPN) || 1082 (match == URL_PREFERAPN_USING_SUBID)) { 1083 count = 1; 1084 } 1085 } 1086 } 1087 break; 1088 } 1089 1090 case URL_SIMINFO: { 1091 count = db.update(SIMINFO_TABLE, values, where, whereArgs); 1092 uriType = URL_SIMINFO; 1093 break; 1094 } 1095 1096 default: { 1097 throw new UnsupportedOperationException("Cannot update that URL: " + url); 1098 } 1099 } 1100 1101 if (count > 0) { 1102 switch (uriType) { 1103 case URL_SIMINFO: 1104 getContext().getContentResolver().notifyChange( 1105 SubscriptionManager.CONTENT_URI, null); 1106 break; 1107 default: 1108 getContext().getContentResolver().notifyChange( 1109 Telephony.Carriers.CONTENT_URI, null); 1110 } 1111 } 1112 1113 return count; 1114 } 1115 1116 private void checkPermission() { 1117 int status = getContext().checkCallingOrSelfPermission( 1118 "android.permission.WRITE_APN_SETTINGS"); 1119 if (status == PackageManager.PERMISSION_GRANTED) { 1120 return; 1121 } 1122 1123 PackageManager packageManager = getContext().getPackageManager(); 1124 String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid()); 1125 1126 TelephonyManager telephonyManager = 1127 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE); 1128 for (String pkg : packages) { 1129 if (telephonyManager.checkCarrierPrivilegesForPackage(pkg) == 1130 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 1131 return; 1132 } 1133 } 1134 throw new SecurityException("No permission to write APN settings"); 1135 } 1136 1137 private DatabaseHelper mOpenHelper; 1138 1139 private void restoreDefaultAPN(long subId) { 1140 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1141 1142 try { 1143 db.delete(CARRIERS_TABLE, null, null); 1144 } catch (SQLException e) { 1145 loge("got exception when deleting to restore: " + e); 1146 } 1147 setPreferredApnId((long)-1, subId); 1148 mOpenHelper.initDatabase(db); 1149 } 1150 1151 /** 1152 * Log with debug 1153 * 1154 * @param s is string log 1155 */ 1156 private static void log(String s) { 1157 Log.d(TAG, s); 1158 } 1159 1160 private static void loge(String s) { 1161 Log.e(TAG, s); 1162 } 1163} 1164