Home | History | Annotate | Download | only in telephony
      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 
     18 package com.android.providers.telephony;
     19 
     20 import android.content.ContentProvider;
     21 import android.content.ContentUris;
     22 import android.content.ContentValues;
     23 import android.content.Context;
     24 import android.content.SharedPreferences;
     25 import android.content.UriMatcher;
     26 import android.content.pm.PackageManager;
     27 import android.content.res.Resources;
     28 import android.content.res.XmlResourceParser;
     29 import android.database.Cursor;
     30 import android.database.SQLException;
     31 import android.database.sqlite.SQLiteDatabase;
     32 import android.database.sqlite.SQLiteException;
     33 import android.database.sqlite.SQLiteOpenHelper;
     34 import android.database.sqlite.SQLiteQueryBuilder;
     35 import android.net.Uri;
     36 import android.os.Binder;
     37 import android.os.Environment;
     38 import android.provider.Telephony;
     39 import android.telephony.SubscriptionManager;
     40 import android.telephony.TelephonyManager;
     41 import android.util.Log;
     42 import android.util.Xml;
     43 
     44 import com.android.internal.telephony.BaseCommands;
     45 import com.android.internal.telephony.Phone;
     46 import com.android.internal.telephony.PhoneConstants;
     47 import com.android.internal.util.XmlUtils;
     48 
     49 import org.xmlpull.v1.XmlPullParser;
     50 import org.xmlpull.v1.XmlPullParserException;
     51 
     52 import java.io.File;
     53 import java.io.FileNotFoundException;
     54 import java.io.FileReader;
     55 import java.io.IOException;
     56 import java.lang.NumberFormatException;
     57 
     58 public 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                 try {
    364                     // Try to update the siminfo table. It might not be there.
    365                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE +
    366                             " ADD COLUMN " + SubscriptionManager.MCC + " INTEGER DEFAULT 0;");
    367                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE +
    368                             " ADD COLUMN " + SubscriptionManager.MNC + " INTEGER DEFAULT 0;");
    369                 } catch (SQLiteException e) {
    370                     if (DBG) {
    371                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
    372                                 " The table will get created in onOpen.");
    373                     }
    374                 }
    375                 oldVersion = 12 << 16 | 6;
    376             }
    377             if (DBG) {
    378                 log("dbh.onUpgrade:- db=" + db + " oldV=" + oldVersion + " newV=" + newVersion);
    379             }
    380         }
    381 
    382         /**
    383          * Gets the next row of apn values.
    384          *
    385          * @param parser the parser
    386          * @return the row or null if it's not an apn
    387          */
    388         private ContentValues getRow(XmlPullParser parser) {
    389             if (!"apn".equals(parser.getName())) {
    390                 return null;
    391             }
    392 
    393             ContentValues map = new ContentValues();
    394 
    395             String mcc = parser.getAttributeValue(null, "mcc");
    396             String mnc = parser.getAttributeValue(null, "mnc");
    397             String numeric = mcc + mnc;
    398 
    399             map.put(Telephony.Carriers.NUMERIC,numeric);
    400             map.put(Telephony.Carriers.MCC, mcc);
    401             map.put(Telephony.Carriers.MNC, mnc);
    402             map.put(Telephony.Carriers.NAME, parser.getAttributeValue(null, "carrier"));
    403             map.put(Telephony.Carriers.APN, parser.getAttributeValue(null, "apn"));
    404             map.put(Telephony.Carriers.USER, parser.getAttributeValue(null, "user"));
    405             map.put(Telephony.Carriers.SERVER, parser.getAttributeValue(null, "server"));
    406             map.put(Telephony.Carriers.PASSWORD, parser.getAttributeValue(null, "password"));
    407 
    408             // do not add NULL to the map so that insert() will set the default value
    409             String proxy = parser.getAttributeValue(null, "proxy");
    410             if (proxy != null) {
    411                 map.put(Telephony.Carriers.PROXY, proxy);
    412             }
    413             String port = parser.getAttributeValue(null, "port");
    414             if (port != null) {
    415                 map.put(Telephony.Carriers.PORT, port);
    416             }
    417             String mmsproxy = parser.getAttributeValue(null, "mmsproxy");
    418             if (mmsproxy != null) {
    419                 map.put(Telephony.Carriers.MMSPROXY, mmsproxy);
    420             }
    421             String mmsport = parser.getAttributeValue(null, "mmsport");
    422             if (mmsport != null) {
    423                 map.put(Telephony.Carriers.MMSPORT, mmsport);
    424             }
    425             map.put(Telephony.Carriers.MMSC, parser.getAttributeValue(null, "mmsc"));
    426             String type = parser.getAttributeValue(null, "type");
    427             if (type != null) {
    428                 map.put(Telephony.Carriers.TYPE, type);
    429             }
    430 
    431             String auth = parser.getAttributeValue(null, "authtype");
    432             if (auth != null) {
    433                 map.put(Telephony.Carriers.AUTH_TYPE, Integer.parseInt(auth));
    434             }
    435 
    436             String protocol = parser.getAttributeValue(null, "protocol");
    437             if (protocol != null) {
    438                 map.put(Telephony.Carriers.PROTOCOL, protocol);
    439             }
    440 
    441             String roamingProtocol = parser.getAttributeValue(null, "roaming_protocol");
    442             if (roamingProtocol != null) {
    443                 map.put(Telephony.Carriers.ROAMING_PROTOCOL, roamingProtocol);
    444             }
    445 
    446             String carrierEnabled = parser.getAttributeValue(null, "carrier_enabled");
    447             if (carrierEnabled != null) {
    448                 map.put(Telephony.Carriers.CARRIER_ENABLED, Boolean.parseBoolean(carrierEnabled));
    449             }
    450 
    451             String bearer = parser.getAttributeValue(null, "bearer");
    452             if (bearer != null) {
    453                 map.put(Telephony.Carriers.BEARER, Integer.parseInt(bearer));
    454             }
    455 
    456             String mvno_type = parser.getAttributeValue(null, "mvno_type");
    457             if (mvno_type != null) {
    458                 String mvno_match_data = parser.getAttributeValue(null, "mvno_match_data");
    459                 if (mvno_match_data != null) {
    460                     map.put(Telephony.Carriers.MVNO_TYPE, mvno_type);
    461                     map.put(Telephony.Carriers.MVNO_MATCH_DATA, mvno_match_data);
    462                 }
    463             }
    464 
    465             String profileId = parser.getAttributeValue(null, "profile_id");
    466             if (profileId != null) {
    467                 map.put(Telephony.Carriers.PROFILE_ID, Integer.parseInt(profileId));
    468             }
    469 
    470             String modemCognitive = parser.getAttributeValue(null, "modem_cognitive");
    471             if (modemCognitive != null) {
    472                 map.put(Telephony.Carriers.MODEM_COGNITIVE, Boolean.parseBoolean(modemCognitive));
    473             }
    474 
    475             String maxConns = parser.getAttributeValue(null, "max_conns");
    476             if (maxConns != null) {
    477                 map.put(Telephony.Carriers.MAX_CONNS, Integer.parseInt(maxConns));
    478             }
    479 
    480             String waitTime = parser.getAttributeValue(null, "wait_time");
    481             if (waitTime != null) {
    482                 map.put(Telephony.Carriers.WAIT_TIME, Integer.parseInt(waitTime));
    483             }
    484 
    485             String maxConnsTime = parser.getAttributeValue(null, "max_conns_time");
    486             if (maxConnsTime != null) {
    487                 map.put(Telephony.Carriers.MAX_CONNS_TIME, Integer.parseInt(maxConnsTime));
    488             }
    489 
    490             String mtu = parser.getAttributeValue(null, "mtu");
    491             if (mtu != null) {
    492                 map.put(Telephony.Carriers.MTU, Integer.parseInt(mtu));
    493             }
    494 
    495             return map;
    496         }
    497 
    498         /*
    499          * Loads apns from xml file into the database
    500          *
    501          * @param db the sqlite database to write to
    502          * @param parser the xml parser
    503          *
    504          */
    505         private void loadApns(SQLiteDatabase db, XmlPullParser parser) {
    506             if (parser != null) {
    507                 try {
    508                     db.beginTransaction();
    509                     XmlUtils.nextElement(parser);
    510                     while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
    511                         ContentValues row = getRow(parser);
    512                         if (row == null) {
    513                             throw new XmlPullParserException("Expected 'apn' tag", parser, null);
    514                         }
    515                         insertAddingDefaults(db, CARRIERS_TABLE, row);
    516                         XmlUtils.nextElement(parser);
    517                     }
    518                     db.setTransactionSuccessful();
    519                 } catch (XmlPullParserException e) {
    520                     loge("Got XmlPullParserException while loading apns." + e);
    521                 } catch (IOException e) {
    522                     loge("Got IOException while loading apns." + e);
    523                 } catch (SQLException e) {
    524                     loge("Got SQLException while loading apns." + e);
    525                 } finally {
    526                     db.endTransaction();
    527                 }
    528             }
    529         }
    530 
    531         static public ContentValues setDefaultValue(ContentValues values) {
    532             if (!values.containsKey(Telephony.Carriers.NAME)) {
    533                 values.put(Telephony.Carriers.NAME, "");
    534             }
    535             if (!values.containsKey(Telephony.Carriers.APN)) {
    536                 values.put(Telephony.Carriers.APN, "");
    537             }
    538             if (!values.containsKey(Telephony.Carriers.PORT)) {
    539                 values.put(Telephony.Carriers.PORT, "");
    540             }
    541             if (!values.containsKey(Telephony.Carriers.PROXY)) {
    542                 values.put(Telephony.Carriers.PROXY, "");
    543             }
    544             if (!values.containsKey(Telephony.Carriers.USER)) {
    545                 values.put(Telephony.Carriers.USER, "");
    546             }
    547             if (!values.containsKey(Telephony.Carriers.SERVER)) {
    548                 values.put(Telephony.Carriers.SERVER, "");
    549             }
    550             if (!values.containsKey(Telephony.Carriers.PASSWORD)) {
    551                 values.put(Telephony.Carriers.PASSWORD, "");
    552             }
    553             if (!values.containsKey(Telephony.Carriers.MMSPORT)) {
    554                 values.put(Telephony.Carriers.MMSPORT, "");
    555             }
    556             if (!values.containsKey(Telephony.Carriers.MMSPROXY)) {
    557                 values.put(Telephony.Carriers.MMSPROXY, "");
    558             }
    559             if (!values.containsKey(Telephony.Carriers.AUTH_TYPE)) {
    560                 values.put(Telephony.Carriers.AUTH_TYPE, -1);
    561             }
    562             if (!values.containsKey(Telephony.Carriers.PROTOCOL)) {
    563                 values.put(Telephony.Carriers.PROTOCOL, "IP");
    564             }
    565             if (!values.containsKey(Telephony.Carriers.ROAMING_PROTOCOL)) {
    566                 values.put(Telephony.Carriers.ROAMING_PROTOCOL, "IP");
    567             }
    568             if (!values.containsKey(Telephony.Carriers.CARRIER_ENABLED)) {
    569                 values.put(Telephony.Carriers.CARRIER_ENABLED, true);
    570             }
    571             if (!values.containsKey(Telephony.Carriers.BEARER)) {
    572                 values.put(Telephony.Carriers.BEARER, 0);
    573             }
    574             if (!values.containsKey(Telephony.Carriers.MVNO_TYPE)) {
    575                 values.put(Telephony.Carriers.MVNO_TYPE, "");
    576             }
    577             if (!values.containsKey(Telephony.Carriers.MVNO_MATCH_DATA)) {
    578                 values.put(Telephony.Carriers.MVNO_MATCH_DATA, "");
    579             }
    580 
    581             long subId = SubscriptionManager.getDefaultSubId();
    582             if (!values.containsKey(Telephony.Carriers.SUB_ID)) {
    583                 values.put(Telephony.Carriers.SUB_ID, subId);
    584             }
    585 
    586             if (!values.containsKey(Telephony.Carriers.PROFILE_ID)) {
    587                 values.put(Telephony.Carriers.PROFILE_ID, 0);
    588             }
    589             if (!values.containsKey(Telephony.Carriers.MODEM_COGNITIVE)) {
    590                 values.put(Telephony.Carriers.MODEM_COGNITIVE, false);
    591             }
    592             if (!values.containsKey(Telephony.Carriers.MAX_CONNS)) {
    593                 values.put(Telephony.Carriers.MAX_CONNS, 0);
    594             }
    595             if (!values.containsKey(Telephony.Carriers.WAIT_TIME)) {
    596                 values.put(Telephony.Carriers.WAIT_TIME, 0);
    597             }
    598             if (!values.containsKey(Telephony.Carriers.MAX_CONNS_TIME)) {
    599                 values.put(Telephony.Carriers.MAX_CONNS_TIME, 0);
    600             }
    601 
    602             return values;
    603         }
    604 
    605         private void insertAddingDefaults(SQLiteDatabase db, String table, ContentValues row) {
    606             row = setDefaultValue(row);
    607             db.insert(CARRIERS_TABLE, null, row);
    608         }
    609     }
    610 
    611     @Override
    612     public boolean onCreate() {
    613         if (VDBG) log("onCreate:+");
    614         mOpenHelper = new DatabaseHelper(getContext());
    615         if (VDBG) log("onCreate:- ret true");
    616         return true;
    617     }
    618 
    619     private void setPreferredApnId(Long id, long subId) {
    620         SharedPreferences sp = getContext().getSharedPreferences(
    621                 PREF_FILE + subId, Context.MODE_PRIVATE);
    622         SharedPreferences.Editor editor = sp.edit();
    623         editor.putLong(COLUMN_APN_ID, id != null ? id.longValue() : -1);
    624         editor.apply();
    625     }
    626 
    627     private long getPreferredApnId(long subId) {
    628         SharedPreferences sp = getContext().getSharedPreferences(
    629                 PREF_FILE + subId, Context.MODE_PRIVATE);
    630         return sp.getLong(COLUMN_APN_ID, -1);
    631     }
    632 
    633     @Override
    634     public Cursor query(Uri url, String[] projectionIn, String selection,
    635             String[] selectionArgs, String sort) {
    636         TelephonyManager mTelephonyManager =
    637                 (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
    638         long subId = SubscriptionManager.getDefaultSubId();
    639         String subIdString;
    640         SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
    641         qb.setStrict(true); // a little protection from injection attacks
    642         qb.setTables("carriers");
    643 
    644         int match = s_urlMatcher.match(url);
    645         switch (match) {
    646             case URL_TELEPHONY_USING_SUBID: {
    647                 subIdString = url.getLastPathSegment();
    648                 try {
    649                     subId = Long.parseLong(subIdString);
    650                 } catch (NumberFormatException e) {
    651                     loge("NumberFormatException" + e);
    652                     return null;
    653                 }
    654                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
    655                 qb.appendWhere("numeric = '" + mTelephonyManager.getSimOperator(subId)+"'");
    656                 // FIXME alter the selection to pass subId
    657                 // selection = selection + "and subId = "
    658             }
    659             //intentional fall through from above case
    660             // do nothing
    661             case URL_TELEPHONY: {
    662                 break;
    663             }
    664 
    665             case URL_CURRENT_USING_SUBID: {
    666                 subIdString = url.getLastPathSegment();
    667                 try {
    668                     subId = Long.parseLong(subIdString);
    669                 } catch (NumberFormatException e) {
    670                     loge("NumberFormatException" + e);
    671                     return null;
    672                 }
    673                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
    674                 // FIXME alter the selection to pass subId
    675                 // selection = selection + "and subId = "
    676             }
    677             //intentional fall through from above case
    678             case URL_CURRENT: {
    679                 qb.appendWhere("current IS NOT NULL");
    680                 // do not ignore the selection since MMS may use it.
    681                 //selection = null;
    682                 break;
    683             }
    684 
    685             case URL_ID: {
    686                 qb.appendWhere("_id = " + url.getPathSegments().get(1));
    687                 break;
    688             }
    689 
    690             case URL_PREFERAPN_USING_SUBID:
    691             case URL_PREFERAPN_NO_UPDATE_USING_SUBID: {
    692                 subIdString = url.getLastPathSegment();
    693                 try {
    694                     subId = Long.parseLong(subIdString);
    695                 } catch (NumberFormatException e) {
    696                     loge("NumberFormatException" + e);
    697                     return null;
    698                 }
    699                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
    700             }
    701             //intentional fall through from above case
    702             case URL_PREFERAPN:
    703             case URL_PREFERAPN_NO_UPDATE: {
    704                 qb.appendWhere("_id = " + getPreferredApnId(subId));
    705                 break;
    706             }
    707 
    708             case URL_SIMINFO: {
    709                 qb.setTables(SIMINFO_TABLE);
    710                 break;
    711             }
    712 
    713             default: {
    714                 return null;
    715             }
    716         }
    717 
    718         if (match != URL_SIMINFO) {
    719             if (projectionIn != null) {
    720                 for (String column : projectionIn) {
    721                     if (Telephony.Carriers.TYPE.equals(column) ||
    722                             Telephony.Carriers.MMSC.equals(column) ||
    723                             Telephony.Carriers.MMSPROXY.equals(column) ||
    724                             Telephony.Carriers.MMSPORT.equals(column) ||
    725                             Telephony.Carriers.APN.equals(column)) {
    726                         // noop
    727                     } else {
    728                         checkPermission();
    729                         break;
    730                     }
    731                 }
    732             } else {
    733                 // null returns all columns, so need permission check
    734                 checkPermission();
    735             }
    736         }
    737 
    738         SQLiteDatabase db = mOpenHelper.getReadableDatabase();
    739         Cursor ret = null;
    740         try {
    741             ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort);
    742         } catch (SQLException e) {
    743             loge("got exception when querying: " + e);
    744         }
    745         if (ret != null)
    746             ret.setNotificationUri(getContext().getContentResolver(), url);
    747         return ret;
    748     }
    749 
    750     @Override
    751     public String getType(Uri url)
    752     {
    753         switch (s_urlMatcher.match(url)) {
    754         case URL_TELEPHONY:
    755         case URL_TELEPHONY_USING_SUBID:
    756             return "vnd.android.cursor.dir/telephony-carrier";
    757 
    758         case URL_ID:
    759             return "vnd.android.cursor.item/telephony-carrier";
    760 
    761         case URL_PREFERAPN_USING_SUBID:
    762         case URL_PREFERAPN_NO_UPDATE_USING_SUBID:
    763         case URL_PREFERAPN:
    764         case URL_PREFERAPN_NO_UPDATE:
    765             return "vnd.android.cursor.item/telephony-carrier";
    766 
    767         default:
    768             throw new IllegalArgumentException("Unknown URL " + url);
    769         }
    770     }
    771 
    772     @Override
    773     public Uri insert(Uri url, ContentValues initialValues)
    774     {
    775         Uri result = null;
    776         long subId = SubscriptionManager.getDefaultSubId();
    777 
    778         checkPermission();
    779 
    780         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    781         int match = s_urlMatcher.match(url);
    782         boolean notify = false;
    783         switch (match)
    784         {
    785             case URL_TELEPHONY_USING_SUBID:
    786             {
    787                 String subIdString = url.getLastPathSegment();
    788                 try {
    789                     subId = Long.parseLong(subIdString);
    790                 } catch (NumberFormatException e) {
    791                     loge("NumberFormatException" + e);
    792                     return result;
    793                 }
    794                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
    795             }
    796             //intentional fall through from above case
    797 
    798             case URL_TELEPHONY:
    799             {
    800                 ContentValues values;
    801                 if (initialValues != null) {
    802                     values = new ContentValues(initialValues);
    803                 } else {
    804                     values = new ContentValues();
    805                 }
    806 
    807                 values = DatabaseHelper.setDefaultValue(values);
    808 
    809                 long rowID = db.insert(CARRIERS_TABLE, null, values);
    810                 if (rowID > 0)
    811                 {
    812                     result = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, rowID);
    813                     notify = true;
    814                 }
    815 
    816                 if (VDBG) log("inserted " + values.toString() + " rowID = " + rowID);
    817                 break;
    818             }
    819 
    820             case URL_CURRENT_USING_SUBID:
    821             {
    822                 String subIdString = url.getLastPathSegment();
    823                 try {
    824                     subId = Long.parseLong(subIdString);
    825                 } catch (NumberFormatException e) {
    826                     loge("NumberFormatException" + e);
    827                     return result;
    828                 }
    829                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
    830                 // FIXME use subId in the query
    831             }
    832             //intentional fall through from above case
    833 
    834             case URL_CURRENT:
    835             {
    836                 // null out the previous operator
    837                 db.update("carriers", s_currentNullMap, "current IS NOT NULL", null);
    838 
    839                 String numeric = initialValues.getAsString("numeric");
    840                 int updated = db.update("carriers", s_currentSetMap,
    841                         "numeric = '" + numeric + "'", null);
    842 
    843                 if (updated > 0)
    844                 {
    845                     if (VDBG) log("Setting numeric '" + numeric + "' to be the current operator");
    846                 }
    847                 else
    848                 {
    849                     loge("Failed setting numeric '" + numeric + "' to the current operator");
    850                 }
    851                 break;
    852             }
    853 
    854             case URL_PREFERAPN_USING_SUBID:
    855             case URL_PREFERAPN_NO_UPDATE_USING_SUBID:
    856             {
    857                 String subIdString = url.getLastPathSegment();
    858                 try {
    859                     subId = Long.parseLong(subIdString);
    860                 } catch (NumberFormatException e) {
    861                     loge("NumberFormatException" + e);
    862                     return result;
    863                 }
    864                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
    865             }
    866             //intentional fall through from above case
    867 
    868             case URL_PREFERAPN:
    869             case URL_PREFERAPN_NO_UPDATE:
    870             {
    871                 if (initialValues != null) {
    872                     if(initialValues.containsKey(COLUMN_APN_ID)) {
    873                         setPreferredApnId(initialValues.getAsLong(COLUMN_APN_ID), subId);
    874                     }
    875                 }
    876                 break;
    877             }
    878 
    879             case URL_SIMINFO: {
    880                long id = db.insert(SIMINFO_TABLE, null, initialValues);
    881                result = ContentUris.withAppendedId(SubscriptionManager.CONTENT_URI, id);
    882                break;
    883             }
    884         }
    885 
    886         if (notify) {
    887             getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null);
    888         }
    889 
    890         return result;
    891     }
    892 
    893     @Override
    894     public int delete(Uri url, String where, String[] whereArgs)
    895     {
    896         int count = 0;
    897         long subId = SubscriptionManager.getDefaultSubId();
    898 
    899         checkPermission();
    900 
    901         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    902         int match = s_urlMatcher.match(url);
    903         switch (match)
    904         {
    905             case URL_TELEPHONY_USING_SUBID:
    906             {
    907                  String subIdString = url.getLastPathSegment();
    908                  try {
    909                      subId = Long.parseLong(subIdString);
    910                  } catch (NumberFormatException e) {
    911                      loge("NumberFormatException" + e);
    912                      throw new IllegalArgumentException("Invalid subId " + url);
    913                  }
    914                  if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
    915                 // FIXME use subId in query
    916             }
    917             //intentional fall through from above case
    918 
    919             case URL_TELEPHONY:
    920             {
    921                 count = db.delete(CARRIERS_TABLE, where, whereArgs);
    922                 break;
    923             }
    924 
    925             case URL_CURRENT_USING_SUBID: {
    926                 String subIdString = url.getLastPathSegment();
    927                 try {
    928                     subId = Long.parseLong(subIdString);
    929                 } catch (NumberFormatException e) {
    930                     loge("NumberFormatException" + e);
    931                     throw new IllegalArgumentException("Invalid subId " + url);
    932                 }
    933                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
    934                 // FIXME use subId in query
    935             }
    936             //intentional fall through from above case
    937 
    938             case URL_CURRENT:
    939             {
    940                 count = db.delete(CARRIERS_TABLE, where, whereArgs);
    941                 break;
    942             }
    943 
    944             case URL_ID:
    945             {
    946                 count = db.delete(CARRIERS_TABLE, Telephony.Carriers._ID + "=?",
    947                         new String[] { url.getLastPathSegment() });
    948                 break;
    949             }
    950 
    951             case URL_RESTOREAPN_USING_SUBID: {
    952                 String subIdString = url.getLastPathSegment();
    953                 try {
    954                     subId = Long.parseLong(subIdString);
    955                 } catch (NumberFormatException e) {
    956                     loge("NumberFormatException" + e);
    957                     throw new IllegalArgumentException("Invalid subId " + url);
    958                 }
    959                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
    960                 // FIXME use subId in query
    961             }
    962             case URL_RESTOREAPN: {
    963                 count = 1;
    964                 restoreDefaultAPN(subId);
    965                 break;
    966             }
    967 
    968             case URL_PREFERAPN_USING_SUBID:
    969             case URL_PREFERAPN_NO_UPDATE_USING_SUBID: {
    970                 String subIdString = url.getLastPathSegment();
    971                 try {
    972                     subId = Long.parseLong(subIdString);
    973                 } catch (NumberFormatException e) {
    974                     loge("NumberFormatException" + e);
    975                     throw new IllegalArgumentException("Invalid subId " + url);
    976                 }
    977                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
    978             }
    979             //intentional fall through from above case
    980 
    981             case URL_PREFERAPN:
    982             case URL_PREFERAPN_NO_UPDATE:
    983             {
    984                 setPreferredApnId((long)-1, subId);
    985                 if ((match == URL_PREFERAPN) || (match == URL_PREFERAPN_USING_SUBID)) count = 1;
    986                 break;
    987             }
    988 
    989             case URL_SIMINFO: {
    990                 count = db.delete(SIMINFO_TABLE, where, whereArgs);
    991                 break;
    992             }
    993 
    994             default: {
    995                 throw new UnsupportedOperationException("Cannot delete that URL: " + url);
    996             }
    997         }
    998 
    999         if (count > 0) {
   1000             getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null);
   1001         }
   1002 
   1003         return count;
   1004     }
   1005 
   1006     @Override
   1007     public int update(Uri url, ContentValues values, String where, String[] whereArgs)
   1008     {
   1009         int count = 0;
   1010         int uriType = URL_UNKNOWN;
   1011         long subId = SubscriptionManager.getDefaultSubId();
   1012 
   1013         checkPermission();
   1014 
   1015         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
   1016         int match = s_urlMatcher.match(url);
   1017         switch (match)
   1018         {
   1019             case URL_TELEPHONY_USING_SUBID:
   1020             {
   1021                  String subIdString = url.getLastPathSegment();
   1022                  try {
   1023                      subId = Long.parseLong(subIdString);
   1024                  } catch (NumberFormatException e) {
   1025                      loge("NumberFormatException" + e);
   1026                      throw new IllegalArgumentException("Invalid subId " + url);
   1027                  }
   1028                  if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
   1029                 //FIXME use subId in the query
   1030             }
   1031             //intentional fall through from above case
   1032 
   1033             case URL_TELEPHONY:
   1034             {
   1035                 count = db.update(CARRIERS_TABLE, values, where, whereArgs);
   1036                 break;
   1037             }
   1038 
   1039             case URL_CURRENT_USING_SUBID:
   1040             {
   1041                 String subIdString = url.getLastPathSegment();
   1042                 try {
   1043                     subId = Long.parseLong(subIdString);
   1044                 } catch (NumberFormatException e) {
   1045                     loge("NumberFormatException" + e);
   1046                     throw new IllegalArgumentException("Invalid subId " + url);
   1047                 }
   1048                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
   1049                 //FIXME use subId in the query
   1050             }
   1051             //intentional fall through from above case
   1052 
   1053             case URL_CURRENT:
   1054             {
   1055                 count = db.update(CARRIERS_TABLE, values, where, whereArgs);
   1056                 break;
   1057             }
   1058 
   1059             case URL_ID:
   1060             {
   1061                 if (where != null || whereArgs != null) {
   1062                     throw new UnsupportedOperationException(
   1063                             "Cannot update URL " + url + " with a where clause");
   1064                 }
   1065                 count = db.update(CARRIERS_TABLE, values, Telephony.Carriers._ID + "=?",
   1066                         new String[] { url.getLastPathSegment() });
   1067                 break;
   1068             }
   1069 
   1070             case URL_PREFERAPN_USING_SUBID:
   1071             case URL_PREFERAPN_NO_UPDATE_USING_SUBID:
   1072             {
   1073                 String subIdString = url.getLastPathSegment();
   1074                 try {
   1075                     subId = Long.parseLong(subIdString);
   1076                 } catch (NumberFormatException e) {
   1077                     loge("NumberFormatException" + e);
   1078                     throw new IllegalArgumentException("Invalid subId " + url);
   1079                 }
   1080                 if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
   1081             }
   1082 
   1083             case URL_PREFERAPN:
   1084             case URL_PREFERAPN_NO_UPDATE:
   1085             {
   1086                 if (values != null) {
   1087                     if (values.containsKey(COLUMN_APN_ID)) {
   1088                         setPreferredApnId(values.getAsLong(COLUMN_APN_ID), subId);
   1089                         if ((match == URL_PREFERAPN) ||
   1090                                 (match == URL_PREFERAPN_USING_SUBID)) {
   1091                             count = 1;
   1092                         }
   1093                     }
   1094                 }
   1095                 break;
   1096             }
   1097 
   1098             case URL_SIMINFO: {
   1099                 count = db.update(SIMINFO_TABLE, values, where, whereArgs);
   1100                 uriType = URL_SIMINFO;
   1101                 break;
   1102             }
   1103 
   1104             default: {
   1105                 throw new UnsupportedOperationException("Cannot update that URL: " + url);
   1106             }
   1107         }
   1108 
   1109         if (count > 0) {
   1110             switch (uriType) {
   1111                 case URL_SIMINFO:
   1112                     getContext().getContentResolver().notifyChange(
   1113                             SubscriptionManager.CONTENT_URI, null);
   1114                     break;
   1115                 default:
   1116                     getContext().getContentResolver().notifyChange(
   1117                             Telephony.Carriers.CONTENT_URI, null);
   1118             }
   1119         }
   1120 
   1121         return count;
   1122     }
   1123 
   1124     private void checkPermission() {
   1125         int status = getContext().checkCallingOrSelfPermission(
   1126                 "android.permission.WRITE_APN_SETTINGS");
   1127         if (status == PackageManager.PERMISSION_GRANTED) {
   1128             return;
   1129         }
   1130 
   1131         PackageManager packageManager = getContext().getPackageManager();
   1132         String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid());
   1133 
   1134         TelephonyManager telephonyManager =
   1135                 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
   1136         for (String pkg : packages) {
   1137             if (telephonyManager.checkCarrierPrivilegesForPackage(pkg) ==
   1138                     TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
   1139                 return;
   1140             }
   1141         }
   1142         throw new SecurityException("No permission to write APN settings");
   1143     }
   1144 
   1145     private DatabaseHelper mOpenHelper;
   1146 
   1147     private void restoreDefaultAPN(long subId) {
   1148         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
   1149 
   1150         try {
   1151             db.delete(CARRIERS_TABLE, null, null);
   1152         } catch (SQLException e) {
   1153             loge("got exception when deleting to restore: " + e);
   1154         }
   1155         setPreferredApnId((long)-1, subId);
   1156         mOpenHelper.initDatabase(db);
   1157     }
   1158 
   1159     /**
   1160      * Log with debug
   1161      *
   1162      * @param s is string log
   1163      */
   1164     private static void log(String s) {
   1165         Log.d(TAG, s);
   1166     }
   1167 
   1168     private static void loge(String s) {
   1169         Log.e(TAG, s);
   1170     }
   1171 }
   1172