TelephonyProvider.java revision 410a1228ec7aef66826f4aebf21cd26dc75ae82b
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.res.Resources; 27import android.content.res.XmlResourceParser; 28import android.database.Cursor; 29import android.database.sqlite.SQLiteDatabase; 30import android.database.sqlite.SQLiteOpenHelper; 31import android.database.sqlite.SQLiteQueryBuilder; 32import android.net.Uri; 33import android.os.Environment; 34import android.os.FileUtils; 35import android.provider.Telephony; 36import android.telephony.TelephonyManager; 37import android.util.Log; 38import android.util.Xml; 39 40import com.android.internal.telephony.BaseCommands; 41import com.android.internal.telephony.Phone; 42import com.android.internal.telephony.PhoneConstants; 43import com.android.internal.util.XmlUtils; 44 45import org.xmlpull.v1.XmlPullParser; 46import org.xmlpull.v1.XmlPullParserException; 47 48import java.io.File; 49import java.io.FileNotFoundException; 50import java.io.FileReader; 51import java.io.IOException; 52 53 54public class TelephonyProvider extends ContentProvider 55{ 56 private static final String DATABASE_NAME = "telephony.db"; 57 private static final boolean DBG = true; 58 59 private static final int DATABASE_VERSION = 7 << 16; 60 private static final int URL_TELEPHONY = 1; 61 private static final int URL_CURRENT = 2; 62 private static final int URL_ID = 3; 63 private static final int URL_RESTOREAPN = 4; 64 private static final int URL_PREFERAPN = 5; 65 private static final int URL_PREFERAPN_NO_UPDATE = 6; 66 67 private static final String TAG = "TelephonyProvider"; 68 private static final String CARRIERS_TABLE = "carriers"; 69 70 private static final String PREF_FILE = "preferred-apn"; 71 private static final String COLUMN_APN_ID = "apn_id"; 72 private static final String APN_CONFIG_CHECKSUM = "apn_conf_checksum"; 73 74 private static final String PARTNER_APNS_PATH = "etc/apns-conf.xml"; 75 76 private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH); 77 78 private static final ContentValues s_currentNullMap; 79 private static final ContentValues s_currentSetMap; 80 81 static { 82 s_urlMatcher.addURI("telephony", "carriers", URL_TELEPHONY); 83 s_urlMatcher.addURI("telephony", "carriers/current", URL_CURRENT); 84 s_urlMatcher.addURI("telephony", "carriers/#", URL_ID); 85 s_urlMatcher.addURI("telephony", "carriers/restore", URL_RESTOREAPN); 86 s_urlMatcher.addURI("telephony", "carriers/preferapn", URL_PREFERAPN); 87 s_urlMatcher.addURI("telephony", "carriers/preferapn_no_update", URL_PREFERAPN_NO_UPDATE); 88 89 s_currentNullMap = new ContentValues(1); 90 s_currentNullMap.put("current", (Long) null); 91 92 s_currentSetMap = new ContentValues(1); 93 s_currentSetMap.put("current", "1"); 94 } 95 96 private static class DatabaseHelper extends SQLiteOpenHelper { 97 // Context to access resources with 98 private Context mContext; 99 100 /** 101 * DatabaseHelper helper class for loading apns into a database. 102 * 103 * @param context of the user. 104 */ 105 public DatabaseHelper(Context context) { 106 super(context, DATABASE_NAME, null, getVersion(context)); 107 mContext = context; 108 } 109 110 private static int getVersion(Context context) { 111 // Get the database version, combining a static schema version and the XML version 112 Resources r = context.getResources(); 113 XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns); 114 try { 115 XmlUtils.beginDocument(parser, "apns"); 116 int publicversion = Integer.parseInt(parser.getAttributeValue(null, "version")); 117 return DATABASE_VERSION | publicversion; 118 } catch (Exception e) { 119 Log.e(TAG, "Can't get version of APN database", e); 120 return DATABASE_VERSION; 121 } finally { 122 parser.close(); 123 } 124 } 125 126 @Override 127 public void onCreate(SQLiteDatabase db) { 128 // Set up the database schema 129 db.execSQL("CREATE TABLE " + CARRIERS_TABLE + 130 "(_id INTEGER PRIMARY KEY," + 131 "name TEXT," + 132 "numeric TEXT," + 133 "mcc TEXT," + 134 "mnc TEXT," + 135 "apn TEXT," + 136 "user TEXT," + 137 "server TEXT," + 138 "password TEXT," + 139 "proxy TEXT," + 140 "port TEXT," + 141 "mmsproxy TEXT," + 142 "mmsport TEXT," + 143 "mmsc TEXT," + 144 "authtype INTEGER," + 145 "type TEXT," + 146 "current INTEGER," + 147 "protocol TEXT," + 148 "roaming_protocol TEXT," + 149 "carrier_enabled BOOLEAN," + 150 "bearer INTEGER);"); 151 152 initDatabase(db); 153 } 154 155 private void initDatabase(SQLiteDatabase db) { 156 // Read internal APNS data 157 Resources r = mContext.getResources(); 158 XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns); 159 int publicversion = -1; 160 try { 161 XmlUtils.beginDocument(parser, "apns"); 162 publicversion = Integer.parseInt(parser.getAttributeValue(null, "version")); 163 loadApns(db, parser); 164 } catch (Exception e) { 165 Log.e(TAG, "Got exception while loading APN database.", e); 166 } finally { 167 parser.close(); 168 } 169 170 // Read external APNS data (partner-provided) 171 XmlPullParser confparser = null; 172 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 173 File confFile = new File(Environment.getRootDirectory(), PARTNER_APNS_PATH); 174 FileReader confreader = null; 175 try { 176 confreader = new FileReader(confFile); 177 confparser = Xml.newPullParser(); 178 confparser.setInput(confreader); 179 XmlUtils.beginDocument(confparser, "apns"); 180 181 // Sanity check. Force internal version and confidential versions to agree 182 int confversion = Integer.parseInt(confparser.getAttributeValue(null, "version")); 183 if (publicversion != confversion) { 184 throw new IllegalStateException("Internal APNS file version doesn't match " 185 + confFile.getAbsolutePath()); 186 } 187 188 loadApns(db, confparser); 189 } catch (FileNotFoundException e) { 190 // It's ok if the file isn't found. It means there isn't a confidential file 191 // Log.e(TAG, "File not found: '" + confFile.getAbsolutePath() + "'"); 192 } catch (Exception e) { 193 Log.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e); 194 } finally { 195 try { if (confreader != null) confreader.close(); } catch (IOException e) { } 196 } 197 } 198 199 @Override 200 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 201 if (oldVersion < (5 << 16 | 6)) { 202 // 5 << 16 is the Database version and 6 in the xml version. 203 204 // This change adds a new authtype column to the database. 205 // The auth type column can have 4 values: 0 (None), 1 (PAP), 2 (CHAP) 206 // 3 (PAP or CHAP). To avoid breaking compatibility, with already working 207 // APNs, the unset value (-1) will be used. If the value is -1. 208 // the authentication will default to 0 (if no user / password) is specified 209 // or to 3. Currently, there have been no reported problems with 210 // pre-configured APNs and hence it is set to -1 for them. Similarly, 211 // if the user, has added a new APN, we set the authentication type 212 // to -1. 213 214 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 215 " ADD COLUMN authtype INTEGER DEFAULT -1;"); 216 217 oldVersion = 5 << 16 | 6; 218 } 219 if (oldVersion < (6 << 16 | 6)) { 220 // Add protcol fields to the APN. The XML file does not change. 221 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 222 " ADD COLUMN protocol TEXT DEFAULT IP;"); 223 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 224 " ADD COLUMN roaming_protocol TEXT DEFAULT IP;"); 225 oldVersion = 6 << 16 | 6; 226 } 227 if (oldVersion < (7 << 16 | 6)) { 228 // Add protcol fields to the APN. The XML file does not change. 229 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 230 " ADD COLUMN carrier_enabled BOOLEAN DEFAULT 1;"); 231 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 232 " ADD COLUMN bearer INTEGER DEFAULT 0;"); 233 oldVersion = 7 << 16 | 6; 234 } 235 } 236 237 /** 238 * Gets the next row of apn values. 239 * 240 * @param parser the parser 241 * @return the row or null if it's not an apn 242 */ 243 private ContentValues getRow(XmlPullParser parser) { 244 if (!"apn".equals(parser.getName())) { 245 return null; 246 } 247 248 ContentValues map = new ContentValues(); 249 250 String mcc = parser.getAttributeValue(null, "mcc"); 251 String mnc = parser.getAttributeValue(null, "mnc"); 252 String numeric = mcc + mnc; 253 254 map.put(Telephony.Carriers.NUMERIC,numeric); 255 map.put(Telephony.Carriers.MCC, mcc); 256 map.put(Telephony.Carriers.MNC, mnc); 257 map.put(Telephony.Carriers.NAME, parser.getAttributeValue(null, "carrier")); 258 map.put(Telephony.Carriers.APN, parser.getAttributeValue(null, "apn")); 259 map.put(Telephony.Carriers.USER, parser.getAttributeValue(null, "user")); 260 map.put(Telephony.Carriers.SERVER, parser.getAttributeValue(null, "server")); 261 map.put(Telephony.Carriers.PASSWORD, parser.getAttributeValue(null, "password")); 262 263 // do not add NULL to the map so that insert() will set the default value 264 String proxy = parser.getAttributeValue(null, "proxy"); 265 if (proxy != null) { 266 map.put(Telephony.Carriers.PROXY, proxy); 267 } 268 String port = parser.getAttributeValue(null, "port"); 269 if (port != null) { 270 map.put(Telephony.Carriers.PORT, port); 271 } 272 String mmsproxy = parser.getAttributeValue(null, "mmsproxy"); 273 if (mmsproxy != null) { 274 map.put(Telephony.Carriers.MMSPROXY, mmsproxy); 275 } 276 String mmsport = parser.getAttributeValue(null, "mmsport"); 277 if (mmsport != null) { 278 map.put(Telephony.Carriers.MMSPORT, mmsport); 279 } 280 map.put(Telephony.Carriers.MMSC, parser.getAttributeValue(null, "mmsc")); 281 String type = parser.getAttributeValue(null, "type"); 282 if (type != null) { 283 map.put(Telephony.Carriers.TYPE, type); 284 } 285 286 String auth = parser.getAttributeValue(null, "authtype"); 287 if (auth != null) { 288 map.put(Telephony.Carriers.AUTH_TYPE, Integer.parseInt(auth)); 289 } 290 291 String protocol = parser.getAttributeValue(null, "protocol"); 292 if (protocol != null) { 293 map.put(Telephony.Carriers.PROTOCOL, protocol); 294 } 295 296 String roamingProtocol = parser.getAttributeValue(null, "roaming_protocol"); 297 if (roamingProtocol != null) { 298 map.put(Telephony.Carriers.ROAMING_PROTOCOL, roamingProtocol); 299 } 300 301 String carrierEnabled = parser.getAttributeValue(null, "carrier_enabled"); 302 if (carrierEnabled != null) { 303 map.put(Telephony.Carriers.CARRIER_ENABLED, Boolean.parseBoolean(carrierEnabled)); 304 } 305 306 String bearer = parser.getAttributeValue(null, "bearer"); 307 if (bearer != null) { 308 map.put(Telephony.Carriers.BEARER, Integer.parseInt(bearer)); 309 } 310 return map; 311 } 312 313 /* 314 * Loads apns from xml file into the database 315 * 316 * @param db the sqlite database to write to 317 * @param parser the xml parser 318 * 319 */ 320 private void loadApns(SQLiteDatabase db, XmlPullParser parser) { 321 if (parser != null) { 322 try { 323 while (true) { 324 XmlUtils.nextElement(parser); 325 ContentValues row = getRow(parser); 326 if (row != null) { 327 insertAddingDefaults(db, CARRIERS_TABLE, row); 328 } else { 329 break; // do we really want to skip the rest of the file? 330 } 331 } 332 } catch (XmlPullParserException e) { 333 Log.e(TAG, "Got execption while getting perferred time zone.", e); 334 } catch (IOException e) { 335 Log.e(TAG, "Got execption while getting perferred time zone.", e); 336 } 337 } 338 } 339 340 private void insertAddingDefaults(SQLiteDatabase db, String table, ContentValues row) { 341 // Initialize defaults if any 342 if (row.containsKey(Telephony.Carriers.AUTH_TYPE) == false) { 343 row.put(Telephony.Carriers.AUTH_TYPE, -1); 344 } 345 if (row.containsKey(Telephony.Carriers.PROTOCOL) == false) { 346 row.put(Telephony.Carriers.PROTOCOL, "IP"); 347 } 348 if (row.containsKey(Telephony.Carriers.ROAMING_PROTOCOL) == false) { 349 row.put(Telephony.Carriers.ROAMING_PROTOCOL, "IP"); 350 } 351 if (row.containsKey(Telephony.Carriers.CARRIER_ENABLED) == false) { 352 row.put(Telephony.Carriers.CARRIER_ENABLED, true); 353 } 354 if (row.containsKey(Telephony.Carriers.BEARER) == false) { 355 row.put(Telephony.Carriers.BEARER, 0); 356 } 357 db.insert(CARRIERS_TABLE, null, row); 358 } 359 } 360 361 @Override 362 public boolean onCreate() { 363 long oldCheckSum = getAPNConfigCheckSum(); 364 File confFile = new File(Environment.getRootDirectory(), PARTNER_APNS_PATH); 365 long newCheckSum = -1L; 366 367 if (DBG) { 368 Log.w(TAG, "onCreate: confFile=" + confFile.getAbsolutePath() + 369 " oldCheckSum=" + oldCheckSum); 370 } 371 mOpenHelper = new DatabaseHelper(getContext()); 372 373 if (isLteOnCdma()) { 374 // Check to see if apns-conf.xml file changed. If so, generate db again. 375 // 376 // TODO: Generalize so we can handle apns-conf.xml updates 377 // and preserve any modifications the user might make. For 378 // now its safe on LteOnCdma devices because the user cannot 379 // make changes. 380 try { 381 newCheckSum = FileUtils.checksumCrc32(confFile); 382 if (DBG) Log.w(TAG, "onCreate: newCheckSum=" + newCheckSum); 383 if (oldCheckSum != newCheckSum) { 384 Log.w(TAG, "Rebuilding Telephony.db"); 385 restoreDefaultAPN(); 386 setAPNConfigCheckSum(newCheckSum); 387 } 388 } catch (FileNotFoundException e) { 389 Log.e(TAG, "FileNotFoundException: '" + confFile.getAbsolutePath() + "'", e); 390 } catch (IOException e) { 391 Log.e(TAG, "IOException: '" + confFile.getAbsolutePath() + "'", e); 392 } 393 } 394 return true; 395 } 396 397 private boolean isLteOnCdma() { 398 return TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE; 399 } 400 401 private void setPreferredApnId(Long id) { 402 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE); 403 SharedPreferences.Editor editor = sp.edit(); 404 editor.putLong(COLUMN_APN_ID, id != null ? id.longValue() : -1); 405 editor.apply(); 406 } 407 408 private long getPreferredApnId() { 409 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE); 410 return sp.getLong(COLUMN_APN_ID, -1); 411 } 412 413 private long getAPNConfigCheckSum() { 414 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE); 415 return sp.getLong(APN_CONFIG_CHECKSUM, -1); 416 } 417 418 private void setAPNConfigCheckSum(long id) { 419 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE); 420 SharedPreferences.Editor editor = sp.edit(); 421 editor.putLong(APN_CONFIG_CHECKSUM, id); 422 editor.apply(); 423 } 424 425 @Override 426 public Cursor query(Uri url, String[] projectionIn, String selection, 427 String[] selectionArgs, String sort) { 428 429 checkPermission(); 430 431 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 432 qb.setTables("carriers"); 433 434 int match = s_urlMatcher.match(url); 435 switch (match) { 436 // do nothing 437 case URL_TELEPHONY: { 438 break; 439 } 440 441 442 case URL_CURRENT: { 443 qb.appendWhere("current IS NOT NULL"); 444 // do not ignore the selection since MMS may use it. 445 //selection = null; 446 break; 447 } 448 449 case URL_ID: { 450 qb.appendWhere("_id = " + url.getPathSegments().get(1)); 451 break; 452 } 453 454 case URL_PREFERAPN: 455 case URL_PREFERAPN_NO_UPDATE: { 456 qb.appendWhere("_id = " + getPreferredApnId()); 457 break; 458 } 459 460 default: { 461 return null; 462 } 463 } 464 465 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 466 Cursor ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort); 467 ret.setNotificationUri(getContext().getContentResolver(), url); 468 return ret; 469 } 470 471 @Override 472 public String getType(Uri url) 473 { 474 switch (s_urlMatcher.match(url)) { 475 case URL_TELEPHONY: 476 return "vnd.android.cursor.dir/telephony-carrier"; 477 478 case URL_ID: 479 return "vnd.android.cursor.item/telephony-carrier"; 480 481 case URL_PREFERAPN: 482 case URL_PREFERAPN_NO_UPDATE: 483 return "vnd.android.cursor.item/telephony-carrier"; 484 485 default: 486 throw new IllegalArgumentException("Unknown URL " + url); 487 } 488 } 489 490 @Override 491 public Uri insert(Uri url, ContentValues initialValues) 492 { 493 Uri result = null; 494 495 checkPermission(); 496 497 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 498 int match = s_urlMatcher.match(url); 499 boolean notify = false; 500 switch (match) 501 { 502 case URL_TELEPHONY: 503 { 504 ContentValues values; 505 if (initialValues != null) { 506 values = new ContentValues(initialValues); 507 } else { 508 values = new ContentValues(); 509 } 510 511 // TODO Review this. This code should probably not bet here. 512 // It is valid for the database to return a null string. 513 if (!values.containsKey(Telephony.Carriers.NAME)) { 514 values.put(Telephony.Carriers.NAME, ""); 515 } 516 if (!values.containsKey(Telephony.Carriers.APN)) { 517 values.put(Telephony.Carriers.APN, ""); 518 } 519 if (!values.containsKey(Telephony.Carriers.PORT)) { 520 values.put(Telephony.Carriers.PORT, ""); 521 } 522 if (!values.containsKey(Telephony.Carriers.PROXY)) { 523 values.put(Telephony.Carriers.PROXY, ""); 524 } 525 if (!values.containsKey(Telephony.Carriers.USER)) { 526 values.put(Telephony.Carriers.USER, ""); 527 } 528 if (!values.containsKey(Telephony.Carriers.SERVER)) { 529 values.put(Telephony.Carriers.SERVER, ""); 530 } 531 if (!values.containsKey(Telephony.Carriers.PASSWORD)) { 532 values.put(Telephony.Carriers.PASSWORD, ""); 533 } 534 if (!values.containsKey(Telephony.Carriers.MMSPORT)) { 535 values.put(Telephony.Carriers.MMSPORT, ""); 536 } 537 if (!values.containsKey(Telephony.Carriers.MMSPROXY)) { 538 values.put(Telephony.Carriers.MMSPROXY, ""); 539 } 540 if (!values.containsKey(Telephony.Carriers.AUTH_TYPE)) { 541 values.put(Telephony.Carriers.AUTH_TYPE, -1); 542 } 543 if (!values.containsKey(Telephony.Carriers.PROTOCOL)) { 544 values.put(Telephony.Carriers.PROTOCOL, "IP"); 545 } 546 if (!values.containsKey(Telephony.Carriers.ROAMING_PROTOCOL)) { 547 values.put(Telephony.Carriers.ROAMING_PROTOCOL, "IP"); 548 } 549 if (!values.containsKey(Telephony.Carriers.CARRIER_ENABLED)) { 550 values.put(Telephony.Carriers.CARRIER_ENABLED, true); 551 } 552 if (!values.containsKey(Telephony.Carriers.BEARER)) { 553 values.put(Telephony.Carriers.BEARER, 0); 554 } 555 556 long rowID = db.insert(CARRIERS_TABLE, null, values); 557 if (rowID > 0) 558 { 559 result = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, rowID); 560 notify = true; 561 } 562 563 if (false) Log.d(TAG, "inserted " + values.toString() + " rowID = " + rowID); 564 break; 565 } 566 567 case URL_CURRENT: 568 { 569 // null out the previous operator 570 db.update("carriers", s_currentNullMap, "current IS NOT NULL", null); 571 572 String numeric = initialValues.getAsString("numeric"); 573 int updated = db.update("carriers", s_currentSetMap, 574 "numeric = '" + numeric + "'", null); 575 576 if (updated > 0) 577 { 578 if (false) { 579 Log.d(TAG, "Setting numeric '" + numeric + "' to be the current operator"); 580 } 581 } 582 else 583 { 584 Log.e(TAG, "Failed setting numeric '" + numeric + "' to the current operator"); 585 } 586 break; 587 } 588 589 case URL_PREFERAPN: 590 case URL_PREFERAPN_NO_UPDATE: 591 { 592 if (initialValues != null) { 593 if(initialValues.containsKey(COLUMN_APN_ID)) { 594 setPreferredApnId(initialValues.getAsLong(COLUMN_APN_ID)); 595 } 596 } 597 break; 598 } 599 } 600 601 if (notify) { 602 getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null); 603 } 604 605 return result; 606 } 607 608 @Override 609 public int delete(Uri url, String where, String[] whereArgs) 610 { 611 int count = 0; 612 613 checkPermission(); 614 615 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 616 int match = s_urlMatcher.match(url); 617 switch (match) 618 { 619 case URL_TELEPHONY: 620 { 621 count = db.delete(CARRIERS_TABLE, where, whereArgs); 622 break; 623 } 624 625 case URL_CURRENT: 626 { 627 count = db.delete(CARRIERS_TABLE, where, whereArgs); 628 break; 629 } 630 631 case URL_ID: 632 { 633 count = db.delete(CARRIERS_TABLE, Telephony.Carriers._ID + "=?", 634 new String[] { url.getLastPathSegment() }); 635 break; 636 } 637 638 case URL_RESTOREAPN: { 639 count = 1; 640 restoreDefaultAPN(); 641 break; 642 } 643 644 case URL_PREFERAPN: 645 case URL_PREFERAPN_NO_UPDATE: 646 { 647 setPreferredApnId((long)-1); 648 if (match == URL_PREFERAPN) count = 1; 649 break; 650 } 651 652 default: { 653 throw new UnsupportedOperationException("Cannot delete that URL: " + url); 654 } 655 } 656 657 if (count > 0) { 658 getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null); 659 } 660 661 return count; 662 } 663 664 @Override 665 public int update(Uri url, ContentValues values, String where, String[] whereArgs) 666 { 667 int count = 0; 668 669 checkPermission(); 670 671 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 672 int match = s_urlMatcher.match(url); 673 switch (match) 674 { 675 case URL_TELEPHONY: 676 { 677 count = db.update(CARRIERS_TABLE, values, where, whereArgs); 678 break; 679 } 680 681 case URL_CURRENT: 682 { 683 count = db.update(CARRIERS_TABLE, values, where, whereArgs); 684 break; 685 } 686 687 case URL_ID: 688 { 689 if (where != null || whereArgs != null) { 690 throw new UnsupportedOperationException( 691 "Cannot update URL " + url + " with a where clause"); 692 } 693 count = db.update(CARRIERS_TABLE, values, Telephony.Carriers._ID + "=?", 694 new String[] { url.getLastPathSegment() }); 695 break; 696 } 697 698 case URL_PREFERAPN: 699 case URL_PREFERAPN_NO_UPDATE: 700 { 701 if (values != null) { 702 if (values.containsKey(COLUMN_APN_ID)) { 703 setPreferredApnId(values.getAsLong(COLUMN_APN_ID)); 704 if (match == URL_PREFERAPN) count = 1; 705 } 706 } 707 break; 708 } 709 710 default: { 711 throw new UnsupportedOperationException("Cannot update that URL: " + url); 712 } 713 } 714 715 if (count > 0) { 716 getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null); 717 } 718 719 return count; 720 } 721 722 private void checkPermission() { 723 getContext().enforceCallingOrSelfPermission("android.permission.WRITE_APN_SETTINGS", 724 "No permission to write APN settings"); 725 } 726 727 private DatabaseHelper mOpenHelper; 728 729 private void restoreDefaultAPN() { 730 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 731 732 db.delete(CARRIERS_TABLE, null, null); 733 setPreferredApnId((long)-1); 734 mOpenHelper.initDatabase(db); 735 } 736} 737