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 private static final int IDLE_CONNECTION_TIMEOUT_MS = 30000; 90 91 // Context to access resources with 92 private Context mContext; 93 94 /** 95 * DatabaseHelper helper class for loading apns into a database. 96 * 97 * @param context of the user. 98 */ 99 public HbpcdLookupDatabaseHelper(Context context) { 100 super(context, DATABASE_NAME, null, DATABASE_VERSION); 101 102 mContext = context; 103 // Memory optimization - close idle connections after 30s of inactivity 104 setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS); 105 } 106 107 @Override 108 public void onCreate(SQLiteDatabase db) { 109 //set up the database schema 110 // 1 MCC may has more IDDs 111 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_MCC_IDD + 112 "(_id INTEGER PRIMARY KEY," + 113 "MCC INTEGER," + 114 "IDD TEXT);"); 115 116 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_MCC_LOOKUP_TABLE + 117 "(_id INTEGER PRIMARY KEY," + 118 "MCC INTEGER," + 119 "Country_Code TEXT," + 120 "Country_Name TEXT," + 121 "NDD TEXT," + 122 "NANPS BOOLEAN," + 123 "GMT_Offset_Low REAL," + 124 "GMT_Offset_High REAL," + 125 "GMT_DST_Low REAL," + 126 "GMT_DST_High REAL);"); 127 128 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_MCC_SID_CONFLICT + 129 "(_id INTEGER PRIMARY KEY," + 130 "MCC INTEGER," + 131 "SID_Conflict INTEGER);"); 132 133 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_MCC_SID_RANGE + 134 "(_id INTEGER PRIMARY KEY," + 135 "MCC INTEGER," + 136 "SID_Range_Low INTEGER," + 137 "SID_Range_High INTEGER);"); 138 139 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_NANP_AREA_CODE + 140 "(_id INTEGER PRIMARY KEY," + 141 "AREA_CODE INTEGER UNIQUE);"); 142 143 db.execSQL("CREATE TABLE " + HbpcdLookupProvider.TABLE_ARBITRARY_MCC_SID_MATCH + 144 "(_id INTEGER PRIMARY KEY," + 145 "MCC INTEGER," + 146 "SID INTEGER UNIQUE);"); 147 148 initDatabase(db); 149 } 150 151 @Override 152 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 153 // do nothing 154 } 155 156 private void initDatabase (SQLiteDatabase db) { 157 // Read internal data from xml 158 Resources r = mContext.getResources(); 159 XmlResourceParser parser = r.getXml(R.xml.hbpcd_lookup_tables); 160 161 if (parser == null) { 162 Log.e (TAG, "error to load the HBPCD resource"); 163 } else { 164 try { 165 db.beginTransaction(); 166 XmlUtils.beginDocument(parser, "hbpcd_info"); 167 168 int eventType = parser.getEventType(); 169 String tagName = parser.getName(); 170 171 while (eventType != XmlPullParser.END_DOCUMENT) { 172 if (eventType == XmlPullParser.START_TAG 173 && tagName.equalsIgnoreCase("table")) { 174 String tableName = parser.getAttributeValue(null, "name"); 175 loadTable(db, parser, tableName); 176 } 177 parser.next(); 178 eventType = parser.getEventType(); 179 tagName = parser.getName(); 180 } 181 db.setTransactionSuccessful(); 182 } catch (XmlPullParserException e) { 183 Log.e (TAG, "Got XmlPullParserException when load hbpcd info"); 184 } catch (IOException e) { 185 Log.e (TAG, "Got IOException when load hbpcd info"); 186 } catch (SQLException e) { 187 Log.e (TAG, "Got SQLException when load hbpcd info"); 188 } finally { 189 db.endTransaction(); 190 parser.close(); 191 } 192 } 193 } 194 195 private void loadTable(SQLiteDatabase db, XmlPullParser parser, String tableName) 196 throws XmlPullParserException, IOException { 197 int eventType = parser.getEventType(); 198 String tagName = parser.getName(); 199 while (!(eventType == XmlPullParser.END_TAG 200 && tagName.equalsIgnoreCase("table"))) { 201 ContentValues row = null; 202 if (tableName.equalsIgnoreCase(HbpcdLookupProvider.TABLE_MCC_IDD)) { 203 row = getTableMccIddRow(parser); 204 } else if (tableName.equalsIgnoreCase(HbpcdLookupProvider.TABLE_MCC_LOOKUP_TABLE)) { 205 row = getTableMccLookupTableRow(parser); 206 } else if (tableName.equalsIgnoreCase(HbpcdLookupProvider.TABLE_MCC_SID_CONFLICT)) { 207 row = getTableMccSidConflictRow(parser); 208 } else if (tableName.equalsIgnoreCase(HbpcdLookupProvider.TABLE_MCC_SID_RANGE)) { 209 row = getTableMccSidRangeRow(parser); 210 } else if (tableName.equalsIgnoreCase(HbpcdLookupProvider.TABLE_NANP_AREA_CODE)) { 211 row = getTableNanpAreaCodeRow(parser); 212 } else if (tableName.equalsIgnoreCase( 213 HbpcdLookupProvider.TABLE_ARBITRARY_MCC_SID_MATCH)) { 214 row = getTableArbitraryMccSidMatch(parser); 215 } else { 216 Log.e(TAG, "unrecognized table name" + tableName); 217 break; 218 } 219 if (row != null) { 220 db.insert(tableName, null, row); 221 } 222 parser.next(); 223 eventType = parser.getEventType(); 224 tagName = parser.getName(); 225 } 226 } 227 228 private ContentValues getTableMccIddRow(XmlPullParser parser) 229 throws XmlPullParserException, IOException { 230 int eventType = parser.getEventType(); 231 String tagName = parser.getName(); 232 ContentValues row = new ContentValues(); 233 234 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 235 if (eventType == XmlPullParser.START_TAG) { 236 if (tagName.equalsIgnoreCase(MccIdd.MCC)) { 237 row.put(MccIdd.MCC, Integer.parseInt(parser.nextText())); 238 } else if (tagName.equalsIgnoreCase(MccIdd.IDD)) { 239 row.put(MccIdd.IDD, parser.nextText()); 240 } 241 } 242 parser.next(); 243 eventType = parser.getEventType(); 244 tagName = parser.getName(); 245 } 246 return row; 247 } 248 249 private ContentValues getTableMccLookupTableRow(XmlPullParser parser) 250 throws XmlPullParserException, IOException { 251 int eventType = parser.getEventType(); 252 String tagName = parser.getName(); 253 ContentValues row = new ContentValues(); 254 255 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 256 if (eventType == XmlPullParser.START_TAG) { 257 if (tagName.equalsIgnoreCase(MccLookup.MCC)) { 258 row.put(MccLookup.MCC, Integer.parseInt(parser.nextText())); 259 } else if (tagName.equalsIgnoreCase(MccLookup.COUNTRY_CODE)) { 260 row.put(MccLookup.COUNTRY_CODE, Integer.parseInt(parser.nextText())); 261 } else if (tagName.equalsIgnoreCase(MccLookup.COUNTRY_NAME)) { 262 row.put(MccLookup.COUNTRY_NAME, parser.nextText()); 263 } else if (tagName.equalsIgnoreCase(MccLookup.NDD)) { 264 row.put(MccLookup.NDD, parser.nextText()); 265 } else if (tagName.equalsIgnoreCase(MccLookup.NANPS)) { 266 row.put(MccLookup.NANPS, Boolean.parseBoolean(parser.nextText())); 267 } else if (tagName.equalsIgnoreCase(MccLookup.GMT_OFFSET_LOW)) { 268 row.put(MccLookup.GMT_OFFSET_LOW, Float.parseFloat(parser.nextText())); 269 } else if (tagName.equalsIgnoreCase(MccLookup.GMT_OFFSET_HIGH)) { 270 row.put(MccLookup.GMT_OFFSET_HIGH, Float.parseFloat(parser.nextText())); 271 } else if (tagName.equalsIgnoreCase(MccLookup.GMT_DST_LOW)) { 272 row.put(MccLookup.GMT_DST_LOW, Float.parseFloat(parser.nextText())); 273 } else if (tagName.equalsIgnoreCase(MccLookup.GMT_DST_HIGH)) { 274 row.put(MccLookup.GMT_DST_HIGH, Float.parseFloat(parser.nextText())); 275 } 276 } 277 parser.next(); 278 eventType = parser.getEventType(); 279 tagName = parser.getName(); 280 } 281 return row; 282 } 283 284 private ContentValues getTableMccSidConflictRow(XmlPullParser parser) 285 throws XmlPullParserException, IOException { 286 int eventType = parser.getEventType(); 287 String tagName = parser.getName(); 288 ContentValues row = new ContentValues(); 289 290 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 291 if (eventType == XmlPullParser.START_TAG) { 292 if (tagName.equalsIgnoreCase(MccSidConflicts.MCC)) { 293 row.put(MccSidConflicts.MCC, Integer.parseInt(parser.nextText())); 294 } else if (tagName.equalsIgnoreCase(MccSidConflicts.SID_CONFLICT)) { 295 row.put(MccSidConflicts.SID_CONFLICT, Integer.parseInt(parser.nextText())); 296 } 297 } 298 parser.next(); 299 eventType = parser.getEventType(); 300 tagName = parser.getName(); 301 } 302 return row; 303 } 304 305 private ContentValues getTableMccSidRangeRow(XmlPullParser parser) 306 throws XmlPullParserException, IOException { 307 int eventType = parser.getEventType(); 308 String tagName = parser.getName(); 309 ContentValues row = new ContentValues(); 310 311 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 312 if (eventType == XmlPullParser.START_TAG) { 313 if (tagName.equalsIgnoreCase(MccSidRange.MCC)) { 314 row.put(MccSidRange.MCC, Integer.parseInt(parser.nextText())); 315 } else if (tagName.equalsIgnoreCase(MccSidRange.RANGE_LOW)) { 316 row.put(MccSidRange.RANGE_LOW, Integer.parseInt(parser.nextText())); 317 } else if (tagName.equalsIgnoreCase(MccSidRange.RANGE_HIGH)) { 318 row.put(MccSidRange.RANGE_HIGH, Integer.parseInt(parser.nextText())); 319 } 320 } 321 parser.next(); 322 eventType = parser.getEventType(); 323 tagName = parser.getName(); 324 } 325 return row; 326 } 327 328 private ContentValues getTableNanpAreaCodeRow(XmlPullParser parser) 329 throws XmlPullParserException, IOException { 330 int eventType = parser.getEventType(); 331 String tagName = parser.getName(); 332 ContentValues row = new ContentValues(); 333 334 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 335 if (eventType == XmlPullParser.START_TAG) { 336 if (tagName.equalsIgnoreCase(NanpAreaCode.AREA_CODE)) { 337 row.put(NanpAreaCode.AREA_CODE, Integer.parseInt(parser.nextText())); 338 } 339 } 340 parser.next(); 341 eventType = parser.getEventType(); 342 tagName = parser.getName(); 343 } 344 return row; 345 } 346 347 private ContentValues getTableArbitraryMccSidMatch(XmlPullParser parser) 348 throws XmlPullParserException, IOException { 349 int eventType = parser.getEventType(); 350 String tagName = parser.getName(); 351 ContentValues row = new ContentValues(); 352 353 while (!(eventType == XmlPullParser.END_TAG && tagName.equalsIgnoreCase("row"))) { 354 if (eventType == XmlPullParser.START_TAG) { 355 if (tagName.equalsIgnoreCase(ArbitraryMccSidMatch.MCC)) { 356 row.put(ArbitraryMccSidMatch.MCC, Integer.parseInt(parser.nextText())); 357 } else if (tagName.equalsIgnoreCase(ArbitraryMccSidMatch.SID)) { 358 row.put(ArbitraryMccSidMatch.SID, Integer.parseInt(parser.nextText())); 359 } 360 } 361 parser.next(); 362 eventType = parser.getEventType(); 363 tagName = parser.getName(); 364 } 365 return row; 366 } 367} 368