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