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