1/* 2** 3** Copyright (C) 2014, 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/* 19 * This class is used to create, load tables for HBPCD 20 * HBPCD means 'Handset Based Plus Code Dialing', for CDMA network, most of network 21 * couldn't handle international dialing number with '+', it need to be converted 22 * to a IDD (International Direct Dialing) number, and some CDMA network won't 23 * broadcast operator numeric, we need CDMA system ID and timezone etc. information 24 * to get right MCC part of numeric, MNC part of numeric has no way to get in this 25 * case, but for HBPCD, the MCC is enough. 26 * 27 * Table TABLE_MCC_LOOKUP_TABLE 28 * This table has country name, country code, time zones for each MCC 29 * 30 * Table TABLE_MCC_IDD 31 * This table has the IDDs for each MCC, some countries have multiple IDDs. 32 * 33 * Table TABLE_MCC_SID_RANGE 34 * This table are SIDs assigned to each MCC 35 * 36 * Table TABLE_MCC_SID_CONFLICT 37 * This table shows those SIDs are assigned to more than 1 MCC entry, 38 * if the SID is here, it means the SID couldn't be matched to a single MCC, 39 * it need to check the time zone and SID in TABLE_MCC_LOOKUP_TABLE to get 40 * right MCC. 41 * 42 * Table TABLE_ARBITRARY_MCC_SID_MATCH 43 * The SID listed in this table technically have operators in multiple MCC, 44 * but conveniently only have *active* operators in a single MCC allowing a 45 * unique SID->MCC lookup. Lookup by Timezone however would be complicatedi 46 * as there will be multiple matches, and those matched entries have same 47 * time zone, which can not tell which MCC is right. Conventionaly it is known 48 * that SID is used only by the *active* operators in that MCC. 49 * 50 * Table TABLE_NANP_AREA_CODE 51 * This table has NANP(North America Number Planning) area code, this is used 52 * to check if a dialing number is a NANP number. 53 */ 54 55package com.android.providers.telephony; 56 57import android.content.ContentValues; 58import android.content.Context; 59import android.content.res.Resources; 60import android.content.res.XmlResourceParser; 61import android.database.Cursor; 62import android.database.SQLException; 63import android.database.sqlite.SQLiteDatabase; 64import android.database.sqlite.SQLiteOpenHelper; 65import android.database.sqlite.SQLiteQueryBuilder; 66import android.util.Log; 67import android.util.Xml; 68import com.android.internal.util.XmlUtils; 69 70import org.xmlpull.v1.XmlPullParser; 71import org.xmlpull.v1.XmlPullParserException; 72 73import java.io.IOException; 74 75import com.android.internal.telephony.HbpcdLookup; 76import com.android.internal.telephony.HbpcdLookup.MccIdd; 77import com.android.internal.telephony.HbpcdLookup.MccLookup; 78import com.android.internal.telephony.HbpcdLookup.MccSidConflicts; 79import com.android.internal.telephony.HbpcdLookup.MccSidRange; 80import com.android.internal.telephony.HbpcdLookup.ArbitraryMccSidMatch; 81import com.android.internal.telephony.HbpcdLookup.NanpAreaCode; 82 83public class HbpcdLookupDatabaseHelper extends SQLiteOpenHelper { 84 private static final String TAG = "HbpcdLockupDatabaseHelper"; 85 private static final boolean DBG = true; 86 87 private static final String DATABASE_NAME = "HbpcdLookup.db"; 88 private static final int DATABASE_VERSION = 1; 89 90 // Context to access resources with 91 private Context mContext; 92 93 /** 94 * DatabaseHelper helper class for loading apns into a database. 95 * 96 * @param context of the user. 97 */ 98 public HbpcdLookupDatabaseHelper(Context context) { 99 super(context, DATABASE_NAME, null, DATABASE_VERSION); 100 101 mContext = context; 102 } 103 104 @Override 105 public void onCreate(SQLiteDatabase db) { 106 //set up the database schema 107 // 1 MCC may has more IDDs 108 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_MCC_IDD + 109 "(_id INTEGER PRIMARY KEY," + 110 "MCC INTEGER," + 111 "IDD TEXT);"); 112 113 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_MCC_LOOKUP_TABLE + 114 "(_id INTEGER PRIMARY KEY," + 115 "MCC INTEGER," + 116 "Country_Code TEXT," + 117 "Country_Name TEXT," + 118 "NDD TEXT," + 119 "NANPS BOOLEAN," + 120 "GMT_Offset_Low REAL," + 121 "GMT_Offset_High REAL," + 122 "GMT_DST_Low REAL," + 123 "GMT_DST_High REAL);"); 124 125 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_MCC_SID_CONFLICT + 126 "(_id INTEGER PRIMARY KEY," + 127 "MCC INTEGER," + 128 "SID_Conflict INTEGER);"); 129 130 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_MCC_SID_RANGE + 131 "(_id INTEGER PRIMARY KEY," + 132 "MCC INTEGER," + 133 "SID_Range_Low INTEGER," + 134 "SID_Range_High INTEGER);"); 135 136 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_NANP_AREA_CODE + 137 "(_id INTEGER PRIMARY KEY," + 138 "AREA_CODE INTEGER UNIQUE);"); 139 140 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_ARBITRARY_MCC_SID_MATCH + 141 "(_id INTEGER PRIMARY KEY," + 142 "MCC INTEGER," + 143 "SID INTEGER UNIQUE);"); 144 145 initDatabase(db); 146 } 147 148 @Override 149 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 150 // do nothing 151 } 152 153 private void initDatabase (SQLiteDatabase db) { 154 // Read internal data from xml 155 Resources r = mContext.getResources(); 156 XmlResourceParser parser = r.getXml(R.xml.hbpcd_lookup_tables); 157 158 if (parser == null) { 159 Log.e (TAG, "error to load the HBPCD resource"); 160 } else { 161 try { 162 db.beginTransaction(); 163 XmlUtils.beginDocument(parser, "hbpcd_info"); 164 165 int eventType = parser.getEventType(); 166 String tagName = parser.getName(); 167 168 while (eventType != XmlPullParser.END_DOCUMENT) { 169 if (eventType == XmlPullParser.START_TAG 170 && tagName.equalsIgnoreCase("table")) { 171 String tableName = parser.getAttributeValue(null, "name"); 172 loadTable(db, parser, tableName); 173 } 174 parser.next(); 175 eventType = parser.getEventType(); 176 tagName = parser.getName(); 177 } 178 db.setTransactionSuccessful(); 179 } catch (XmlPullParserException e) { 180 Log.e (TAG, "Got XmlPullParserException when load hbpcd info"); 181 } catch (IOException e) { 182 Log.e (TAG, "Got IOException when load hbpcd info"); 183 } catch (SQLException e) { 184 Log.e (TAG, "Got SQLException when load hbpcd info"); 185 } finally { 186 db.endTransaction(); 187 parser.close(); 188 } 189 } 190 } 191 192 private void loadTable(SQLiteDatabase db, XmlPullParser parser, String tableName) 193 throws XmlPullParserException, IOException { 194 int eventType = parser.getEventType(); 195 String tagName = parser.getName(); 196 while (!(eventType == XmlPullParser.END_TAG 197 && tagName.equalsIgnoreCase("table"))) { 198 ContentValues row = null; 199 if (tableName.equalsIgnoreCase(HbpcdLookupProvider.TABLE_MCC_IDD)) { 200 row = getTableMccIddRow(parser); 201 } else if (tableName.equalsIgnoreCase(HbpcdLookupProvider.TABLE_MCC_LOOKUP_TABLE)) { 202 row = getTableMccLookupTableRow(parser); 203 } else if (tableName.equalsIgnoreCase(HbpcdLookupProvider.TABLE_MCC_SID_CONFLICT)) { 204 row = getTableMccSidConflictRow(parser); 205 } else if (tableName.equalsIgnoreCase(HbpcdLookupProvider.TABLE_MCC_SID_RANGE)) { 206 row = getTableMccSidRangeRow(parser); 207 } else if (tableName.equalsIgnoreCase(HbpcdLookupProvider.TABLE_NANP_AREA_CODE)) { 208 row = getTableNanpAreaCodeRow(parser); 209 } else if (tableName.equalsIgnoreCase( 210 HbpcdLookupProvider.TABLE_ARBITRARY_MCC_SID_MATCH)) { 211 row = getTableArbitraryMccSidMatch(parser); 212 } else { 213 Log.e(TAG, "unrecognized table name" + tableName); 214 break; 215 } 216 if (row != null) { 217 db.insert(tableName, null, row); 218 } 219 parser.next(); 220 eventType = parser.getEventType(); 221 tagName = parser.getName(); 222 } 223 } 224 225 private ContentValues getTableMccIddRow(XmlPullParser parser) 226 throws XmlPullParserException, IOException { 227 int eventType = parser.getEventType(); 228 String tagName = parser.getName(); 229 ContentValues row = new ContentValues(); 230 231 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 232 if (eventType == XmlPullParser.START_TAG) { 233 if (tagName.equalsIgnoreCase(MccIdd.MCC)) { 234 row.put(MccIdd.MCC, Integer.parseInt(parser.nextText())); 235 } else if (tagName.equalsIgnoreCase(MccIdd.IDD)) { 236 row.put(MccIdd.IDD, parser.nextText()); 237 } 238 } 239 parser.next(); 240 eventType = parser.getEventType(); 241 tagName = parser.getName(); 242 } 243 return row; 244 } 245 246 private ContentValues getTableMccLookupTableRow(XmlPullParser parser) 247 throws XmlPullParserException, IOException { 248 int eventType = parser.getEventType(); 249 String tagName = parser.getName(); 250 ContentValues row = new ContentValues(); 251 252 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 253 if (eventType == XmlPullParser.START_TAG) { 254 if (tagName.equalsIgnoreCase(MccLookup.MCC)) { 255 row.put(MccLookup.MCC, Integer.parseInt(parser.nextText())); 256 } else if (tagName.equalsIgnoreCase(MccLookup.COUNTRY_CODE)) { 257 row.put(MccLookup.COUNTRY_CODE, Integer.parseInt(parser.nextText())); 258 } else if (tagName.equalsIgnoreCase(MccLookup.COUNTRY_NAME)) { 259 row.put(MccLookup.COUNTRY_NAME, parser.nextText()); 260 } else if (tagName.equalsIgnoreCase(MccLookup.NDD)) { 261 row.put(MccLookup.NDD, parser.nextText()); 262 } else if (tagName.equalsIgnoreCase(MccLookup.NANPS)) { 263 row.put(MccLookup.NANPS, Boolean.parseBoolean(parser.nextText())); 264 } else if (tagName.equalsIgnoreCase(MccLookup.GMT_OFFSET_LOW)) { 265 row.put(MccLookup.GMT_OFFSET_LOW, Float.parseFloat(parser.nextText())); 266 } else if (tagName.equalsIgnoreCase(MccLookup.GMT_OFFSET_HIGH)) { 267 row.put(MccLookup.GMT_OFFSET_HIGH, Float.parseFloat(parser.nextText())); 268 } else if (tagName.equalsIgnoreCase(MccLookup.GMT_DST_LOW)) { 269 row.put(MccLookup.GMT_DST_LOW, Float.parseFloat(parser.nextText())); 270 } else if (tagName.equalsIgnoreCase(MccLookup.GMT_DST_HIGH)) { 271 row.put(MccLookup.GMT_DST_HIGH, Float.parseFloat(parser.nextText())); 272 } 273 } 274 parser.next(); 275 eventType = parser.getEventType(); 276 tagName = parser.getName(); 277 } 278 return row; 279 } 280 281 private ContentValues getTableMccSidConflictRow(XmlPullParser parser) 282 throws XmlPullParserException, IOException { 283 int eventType = parser.getEventType(); 284 String tagName = parser.getName(); 285 ContentValues row = new ContentValues(); 286 287 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 288 if (eventType == XmlPullParser.START_TAG) { 289 if (tagName.equalsIgnoreCase(MccSidConflicts.MCC)) { 290 row.put(MccSidConflicts.MCC, Integer.parseInt(parser.nextText())); 291 } else if (tagName.equalsIgnoreCase(MccSidConflicts.SID_CONFLICT)) { 292 row.put(MccSidConflicts.SID_CONFLICT, Integer.parseInt(parser.nextText())); 293 } 294 } 295 parser.next(); 296 eventType = parser.getEventType(); 297 tagName = parser.getName(); 298 } 299 return row; 300 } 301 302 private ContentValues getTableMccSidRangeRow(XmlPullParser parser) 303 throws XmlPullParserException, IOException { 304 int eventType = parser.getEventType(); 305 String tagName = parser.getName(); 306 ContentValues row = new ContentValues(); 307 308 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 309 if (eventType == XmlPullParser.START_TAG) { 310 if (tagName.equalsIgnoreCase(MccSidRange.MCC)) { 311 row.put(MccSidRange.MCC, Integer.parseInt(parser.nextText())); 312 } else if (tagName.equalsIgnoreCase(MccSidRange.RANGE_LOW)) { 313 row.put(MccSidRange.RANGE_LOW, Integer.parseInt(parser.nextText())); 314 } else if (tagName.equalsIgnoreCase(MccSidRange.RANGE_HIGH)) { 315 row.put(MccSidRange.RANGE_HIGH, Integer.parseInt(parser.nextText())); 316 } 317 } 318 parser.next(); 319 eventType = parser.getEventType(); 320 tagName = parser.getName(); 321 } 322 return row; 323 } 324 325 private ContentValues getTableNanpAreaCodeRow(XmlPullParser parser) 326 throws XmlPullParserException, IOException { 327 int eventType = parser.getEventType(); 328 String tagName = parser.getName(); 329 ContentValues row = new ContentValues(); 330 331 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 332 if (eventType == XmlPullParser.START_TAG) { 333 if (tagName.equalsIgnoreCase(NanpAreaCode.AREA_CODE)) { 334 row.put(NanpAreaCode.AREA_CODE, Integer.parseInt(parser.nextText())); 335 } 336 } 337 parser.next(); 338 eventType = parser.getEventType(); 339 tagName = parser.getName(); 340 } 341 return row; 342 } 343 344 private ContentValues getTableArbitraryMccSidMatch(XmlPullParser parser) 345 throws XmlPullParserException, IOException { 346 int eventType = parser.getEventType(); 347 String tagName = parser.getName(); 348 ContentValues row = new ContentValues(); 349 350 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 351 if (eventType == XmlPullParser.START_TAG) { 352 if (tagName.equalsIgnoreCase(ArbitraryMccSidMatch.MCC)) { 353 row.put(ArbitraryMccSidMatch.MCC, Integer.parseInt(parser.nextText())); 354 } else if (tagName.equalsIgnoreCase(ArbitraryMccSidMatch.SID)) { 355 row.put(ArbitraryMccSidMatch.SID, Integer.parseInt(parser.nextText())); 356 } 357 } 358 parser.next(); 359 eventType = parser.getEventType(); 360 tagName = parser.getName(); 361 } 362 return row; 363 } 364} 365