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