SmsNumberUtils.java revision fc240dcd9b7f40b78913f18663809d683c6dbe65
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.telephony; 18 19import java.util.ArrayList; 20import java.util.HashMap; 21 22import android.content.Context; 23import android.os.Build; 24import android.text.TextUtils; 25import android.database.Cursor; 26import android.database.SQLException; 27import android.telephony.PhoneNumberUtils; 28import android.telephony.TelephonyManager; 29import android.telephony.Rlog; 30 31import com.android.internal.telephony.HbpcdLookup.MccIdd; 32import com.android.internal.telephony.HbpcdLookup.MccLookup; 33 34 35 /** 36 * This class implements handle the MO SMS target address before sending. 37 * This is special for VZW requirement. Follow the specifications of assisted dialing 38 * of MO SMS while traveling on VZW CDMA, international CDMA or GSM markets. 39 * {@hide} 40 */ 41public class SmsNumberUtils { 42 private static final String TAG = "SmsNumberUtils"; 43 private static final boolean DBG = Build.IS_DEBUGGABLE; 44 45 private static final String PLUS_SIGN = "+"; 46 47 private static final int NANP_SHORT_LENGTH = 7; 48 private static final int NANP_MEDIUM_LENGTH = 10; 49 private static final int NANP_LONG_LENGTH = 11; 50 51 private static final int NANP_CC = 1; 52 private static final String NANP_NDD = "1"; 53 private static final String NANP_IDD = "011"; 54 55 private static final int MIN_COUNTRY_AREA_LOCAL_LENGTH = 10; 56 57 private static final int GSM_UMTS_NETWORK = 0; 58 private static final int CDMA_HOME_NETWORK = 1; 59 private static final int CDMA_ROAMING_NETWORK = 2; 60 61 private static final int NP_NONE = 0; 62 private static final int NP_NANP_BEGIN = 1; 63 64 /* <Phone Number>, <NXX>-<XXXX> N[2-9] */ 65 private static final int NP_NANP_LOCAL = NP_NANP_BEGIN; 66 67 /* <Area_code>-<Phone Number>, <NXX>-<NXX>-<XXXX> N[2-9] */ 68 private static final int NP_NANP_AREA_LOCAL = NP_NANP_BEGIN + 1; 69 70 /* <1>-<Area_code>-<Phone Number>, 1-<NXX>-<NXX>-<XXXX> N[2-9] */ 71 private static final int NP_NANP_NDD_AREA_LOCAL = NP_NANP_BEGIN + 2; 72 73 /* <+><U.S.Country_code><Area_code><Phone Number>, +1-<NXX>-<NXX>-<XXXX> N[2-9] */ 74 private static final int NP_NANP_NBPCD_CC_AREA_LOCAL = NP_NANP_BEGIN + 3; 75 76 /* <Local_IDD><Country_code><Area_code><Phone Number>, 001-1-<NXX>-<NXX>-<XXXX> N[2-9] */ 77 private static final int NP_NANP_LOCALIDD_CC_AREA_LOCAL = NP_NANP_BEGIN + 4; 78 79 /* <+><Home_IDD><Country_code><Area_code><Phone Number>, +011-1-<NXX>-<NXX>-<XXXX> N[2-9] */ 80 private static final int NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL = NP_NANP_BEGIN + 5; 81 82 private static final int NP_INTERNATIONAL_BEGIN = 100; 83 /* <+>-<Home_IDD>-<Country_code>-<Area_code>-<Phone Number>, +011-86-25-86281234 */ 84 private static final int NP_NBPCD_HOMEIDD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN; 85 86 /* <Home_IDD>-<Country_code>-<Area_code>-<Phone Number>, 011-86-25-86281234 */ 87 private static final int NP_HOMEIDD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 1; 88 89 /* <NBPCD>-<Country_code>-<Area_code>-<Phone Number>, +1-86-25-86281234 */ 90 private static final int NP_NBPCD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 2; 91 92 /* <Local_IDD>-<Country_code>-<Area_code>-<Phone Number>, 00-86-25-86281234 */ 93 private static final int NP_LOCALIDD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 3; 94 95 /* <Country_code>-<Area_code>-<Phone Number>, 86-25-86281234*/ 96 private static final int NP_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 4; 97 98 private static int[] ALL_COUNTRY_CODES = null; 99 private static int MAX_COUNTRY_CODES_LENGTH; 100 private static HashMap<String, ArrayList<String>> IDDS_MAPS = 101 new HashMap<String, ArrayList<String>>(); 102 103 private static class NumberEntry { 104 public String number; 105 public String IDD; 106 public int countryCode; 107 public NumberEntry(String number) { 108 this.number = number; 109 } 110 } 111 112 /* Breaks the given number down and formats it according to the rules 113 * for different number plans and different network. 114 * 115 * @param number destination number which need to be format 116 * @param activeMcc current network's mcc 117 * @param networkType current network type 118 * 119 * @return the number after formatting. 120 */ 121 private static String formatNumber(Context context, String number, 122 String activeMcc, 123 int networkType) { 124 if (number == null ) { 125 throw new IllegalArgumentException("number is null"); 126 } 127 128 if (activeMcc == null || activeMcc.trim().length() == 0) { 129 throw new IllegalArgumentException("activeMcc is null or empty!"); 130 } 131 132 String networkPortionNumber = PhoneNumberUtils.extractNetworkPortion(number); 133 if (networkPortionNumber == null || networkPortionNumber.length() == 0) { 134 throw new IllegalArgumentException("Number is invalid!"); 135 } 136 137 NumberEntry numberEntry = new NumberEntry(networkPortionNumber); 138 ArrayList<String> allIDDs = getAllIDDs(context, activeMcc); 139 140 // First check whether the number is a NANP number. 141 int nanpState = checkNANP(numberEntry, allIDDs); 142 if (DBG) Rlog.d(TAG, "NANP type: " + getNumberPlanType(nanpState)); 143 144 if ((nanpState == NP_NANP_LOCAL) 145 || (nanpState == NP_NANP_AREA_LOCAL) 146 || (nanpState == NP_NANP_NDD_AREA_LOCAL)) { 147 return networkPortionNumber; 148 } else if (nanpState == NP_NANP_NBPCD_CC_AREA_LOCAL) { 149 if (networkType == CDMA_HOME_NETWORK 150 || networkType == CDMA_ROAMING_NETWORK) { 151 // Remove "+" 152 return networkPortionNumber.substring(1); 153 } else { 154 return networkPortionNumber; 155 } 156 } else if (nanpState == NP_NANP_LOCALIDD_CC_AREA_LOCAL) { 157 if (networkType == CDMA_HOME_NETWORK) { 158 return networkPortionNumber; 159 } else if (networkType == GSM_UMTS_NETWORK) { 160 // Remove the local IDD and replace with "+" 161 int iddLength = numberEntry.IDD != null ? numberEntry.IDD.length() : 0; 162 return PLUS_SIGN + networkPortionNumber.substring(iddLength); 163 } else if (networkType == CDMA_ROAMING_NETWORK) { 164 // Remove the local IDD 165 int iddLength = numberEntry.IDD != null ? numberEntry.IDD.length() : 0; 166 return networkPortionNumber.substring(iddLength); 167 } 168 } 169 170 int internationalState = checkInternationalNumberPlan(context, numberEntry, allIDDs, 171 NANP_IDD); 172 if (DBG) Rlog.d(TAG, "International type: " + getNumberPlanType(internationalState)); 173 String returnNumber = null; 174 175 switch (internationalState) { 176 case NP_NBPCD_HOMEIDD_CC_AREA_LOCAL: 177 if (networkType == GSM_UMTS_NETWORK) { 178 // Remove "+" 179 returnNumber = networkPortionNumber.substring(1); 180 } 181 break; 182 183 case NP_NBPCD_CC_AREA_LOCAL: 184 // Replace "+" with "011" 185 returnNumber = NANP_IDD + networkPortionNumber.substring(1); 186 break; 187 188 case NP_LOCALIDD_CC_AREA_LOCAL: 189 if (networkType == GSM_UMTS_NETWORK || networkType == CDMA_ROAMING_NETWORK) { 190 int iddLength = numberEntry.IDD != null ? numberEntry.IDD.length() : 0; 191 // Replace <Local IDD> to <Home IDD>("011") 192 returnNumber = NANP_IDD + networkPortionNumber.substring(iddLength); 193 } 194 break; 195 196 case NP_CC_AREA_LOCAL: 197 int countryCode = numberEntry.countryCode; 198 199 if (!inExceptionListForNpCcAreaLocal(numberEntry) 200 && networkPortionNumber.length() >= 11 && countryCode != NANP_CC) { 201 // Add "011" 202 returnNumber = NANP_IDD + networkPortionNumber; 203 } 204 break; 205 206 case NP_HOMEIDD_CC_AREA_LOCAL: 207 returnNumber = networkPortionNumber; 208 break; 209 210 default: 211 // Replace "+" with 011 in CDMA network if the number's country 212 // code is not in the HbpcdLookup database. 213 if (networkPortionNumber.startsWith(PLUS_SIGN) 214 && (networkType == CDMA_HOME_NETWORK || networkType == CDMA_ROAMING_NETWORK)) { 215 if (networkPortionNumber.startsWith(PLUS_SIGN + NANP_IDD)) { 216 // Only remove "+" 217 returnNumber = networkPortionNumber.substring(1); 218 } else { 219 // Replace "+" with "011" 220 returnNumber = NANP_IDD + networkPortionNumber.substring(1); 221 } 222 } 223 } 224 225 if (returnNumber == null) { 226 returnNumber = networkPortionNumber; 227 } 228 return returnNumber; 229 } 230 231 /* Query International direct dialing from HbpcdLookup.db 232 * for specified country code 233 * 234 * @param mcc current network's country code 235 * 236 * @return the IDD array list. 237 */ 238 private static ArrayList<String> getAllIDDs(Context context, String mcc) { 239 ArrayList<String> allIDDs = IDDS_MAPS.get(mcc); 240 if (allIDDs != null) { 241 return allIDDs; 242 } else { 243 allIDDs = new ArrayList<String>(); 244 } 245 246 String projection[] = {MccIdd.IDD, MccIdd.MCC}; 247 String where = null; 248 249 // if mcc is null : return all rows 250 // if mcc is empty-string : return those rows whose mcc is emptry-string 251 String[] selectionArgs = null; 252 if (mcc != null) { 253 where = MccIdd.MCC + "=?"; 254 selectionArgs = new String[] {mcc}; 255 } 256 257 Cursor cursor = null; 258 try { 259 cursor = context.getContentResolver().query(MccIdd.CONTENT_URI, projection, 260 where, selectionArgs, null); 261 if (cursor.getCount() > 0) { 262 while (cursor.moveToNext()) { 263 String idd = cursor.getString(0); 264 if (!allIDDs.contains(idd)) { 265 allIDDs.add(idd); 266 } 267 } 268 } 269 } catch (SQLException e) { 270 Rlog.e(TAG, "Can't access HbpcdLookup database", e); 271 } finally { 272 if (cursor != null) { 273 cursor.close(); 274 } 275 } 276 277 IDDS_MAPS.put(mcc, allIDDs); 278 279 if (DBG) Rlog.d(TAG, "MCC = " + mcc + ", all IDDs = " + allIDDs); 280 return allIDDs; 281 } 282 283 284 /* Verify if the the destination number is a NANP number 285 * 286 * @param numberEntry including number and IDD array 287 * @param allIDDs the IDD array list of the current network's country code 288 * 289 * @return the number plan type related NANP 290 */ 291 private static int checkNANP(NumberEntry numberEntry, ArrayList<String> allIDDs) { 292 boolean isNANP = false; 293 String number = numberEntry.number; 294 295 if (number.length() == NANP_SHORT_LENGTH) { 296 // 7 digits - Seven digit phone numbers 297 char firstChar = number.charAt(0); 298 if (firstChar >= '2' && firstChar <= '9') { 299 isNANP = true; 300 for (int i=1; i< NANP_SHORT_LENGTH; i++ ) { 301 char c= number.charAt(i); 302 if (!PhoneNumberUtils.isISODigit(c)) { 303 isNANP = false; 304 break; 305 } 306 } 307 } 308 if (isNANP) { 309 return NP_NANP_LOCAL; 310 } 311 } else if (number.length() == NANP_MEDIUM_LENGTH) { 312 // 10 digits - Three digit area code followed by seven digit phone numbers/ 313 if (isNANP(number)) { 314 return NP_NANP_AREA_LOCAL; 315 } 316 } else if (number.length() == NANP_LONG_LENGTH) { 317 // 11 digits - One digit U.S. NDD(National Direct Dial) prefix '1', 318 // followed by three digit area code and seven digit phone numbers 319 if (isNANP(number)) { 320 return NP_NANP_NDD_AREA_LOCAL; 321 } 322 } else if (number.startsWith(PLUS_SIGN)) { 323 number = number.substring(1); 324 if (number.length() == NANP_LONG_LENGTH) { 325 // '+' and 11 digits -'+', followed by NANP CC prefix '1' followed by 326 // three digit area code and seven digit phone numbers 327 if (isNANP(number)) { 328 return NP_NANP_NBPCD_CC_AREA_LOCAL; 329 } 330 } else if (number.startsWith(NANP_IDD) && number.length() == NANP_LONG_LENGTH + 3) { 331 // '+' and 14 digits -'+', followed by NANP IDD "011" followed by NANP CC 332 // prefix '1' followed by three digit area code and seven digit phone numbers 333 number = number.substring(3); 334 if (isNANP(number)) { 335 return NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL; 336 } 337 } 338 } else { 339 // Check whether it's NP_NANP_LOCALIDD_CC_AREA_LOCAL 340 for (String idd : allIDDs) { 341 if (number.startsWith(idd)) { 342 String number2 = number.substring(idd.length()); 343 if(number2 !=null && number2.startsWith(String.valueOf(NANP_CC))){ 344 if (isNANP(number2)) { 345 numberEntry.IDD = idd; 346 return NP_NANP_LOCALIDD_CC_AREA_LOCAL; 347 } 348 } 349 } 350 } 351 } 352 353 return NP_NONE; 354 } 355 356 private static boolean isNANP(String number) { 357 if (number.length() == NANP_MEDIUM_LENGTH 358 || (number.length() == NANP_LONG_LENGTH && number.startsWith(NANP_NDD))) { 359 if (number.length() == NANP_LONG_LENGTH) { 360 number = number.substring(1); 361 } 362 return (PhoneNumberUtils.isNanp(number)); 363 } 364 return false; 365 } 366 367 /* Verify if the the destination number is an internal number 368 * 369 * @param numberEntry including number and IDD array 370 * @param allIDDs the IDD array list of the current network's country code 371 * 372 * @return the number plan type related international number 373 */ 374 private static int checkInternationalNumberPlan(Context context, NumberEntry numberEntry, 375 ArrayList<String> allIDDs,String homeIDD) { 376 String number = numberEntry.number; 377 int countryCode = -1; 378 379 if (number.startsWith(PLUS_SIGN)) { 380 // +xxxxxxxxxx 381 String numberNoNBPCD = number.substring(1); 382 if (numberNoNBPCD.startsWith(homeIDD)) { 383 // +011xxxxxxxx 384 String numberCountryAreaLocal = numberNoNBPCD.substring(homeIDD.length()); 385 if ((countryCode = getCountryCode(context, numberCountryAreaLocal)) > 0) { 386 numberEntry.countryCode = countryCode; 387 return NP_NBPCD_HOMEIDD_CC_AREA_LOCAL; 388 } 389 } else if ((countryCode = getCountryCode(context, numberNoNBPCD)) > 0) { 390 numberEntry.countryCode = countryCode; 391 return NP_NBPCD_CC_AREA_LOCAL; 392 } 393 394 } else if (number.startsWith(homeIDD)) { 395 // 011xxxxxxxxx 396 String numberCountryAreaLocal = number.substring(homeIDD.length()); 397 if ((countryCode = getCountryCode(context, numberCountryAreaLocal)) > 0) { 398 numberEntry.countryCode = countryCode; 399 return NP_HOMEIDD_CC_AREA_LOCAL; 400 } 401 } else { 402 for (String exitCode : allIDDs) { 403 if (number.startsWith(exitCode)) { 404 String numberNoIDD = number.substring(exitCode.length()); 405 if ((countryCode = getCountryCode(context, numberNoIDD)) > 0) { 406 numberEntry.countryCode = countryCode; 407 numberEntry.IDD = exitCode; 408 return NP_LOCALIDD_CC_AREA_LOCAL; 409 } 410 } 411 } 412 413 if (!number.startsWith("0") && (countryCode = getCountryCode(context, number)) > 0) { 414 numberEntry.countryCode = countryCode; 415 return NP_CC_AREA_LOCAL; 416 } 417 } 418 return NP_NONE; 419 } 420 421 /** 422 * Returns the country code from the given number. 423 */ 424 private static int getCountryCode(Context context, String number) { 425 int countryCode = -1; 426 if (number.length() >= MIN_COUNTRY_AREA_LOCAL_LENGTH) { 427 // Check Country code 428 int[] allCCs = getAllCountryCodes(context); 429 if (allCCs == null) { 430 return countryCode; 431 } 432 433 int[] ccArray = new int[MAX_COUNTRY_CODES_LENGTH]; 434 for (int i = 0; i < MAX_COUNTRY_CODES_LENGTH; i ++) { 435 ccArray[i] = Integer.parseInt(number.substring(0, i+1)); 436 } 437 438 for (int i = 0; i < allCCs.length; i ++) { 439 int tempCC = allCCs[i]; 440 for (int j = 0; j < MAX_COUNTRY_CODES_LENGTH; j ++) { 441 if (tempCC == ccArray[j]) { 442 if (DBG) Rlog.d(TAG, "Country code = " + tempCC); 443 return tempCC; 444 } 445 } 446 } 447 } 448 449 return countryCode; 450 } 451 452 /** 453 * Gets all country Codes information with given MCC. 454 */ 455 private static int[] getAllCountryCodes(Context context) { 456 if (ALL_COUNTRY_CODES != null) { 457 return ALL_COUNTRY_CODES; 458 } 459 460 Cursor cursor = null; 461 try { 462 String projection[] = {MccLookup.COUNTRY_CODE}; 463 cursor = context.getContentResolver().query(MccLookup.CONTENT_URI, 464 projection, null, null, null); 465 466 if (cursor.getCount() > 0) { 467 ALL_COUNTRY_CODES = new int[cursor.getCount()]; 468 int i = 0; 469 while (cursor.moveToNext()) { 470 int countryCode = cursor.getInt(0); 471 ALL_COUNTRY_CODES[i++] = countryCode; 472 int length = String.valueOf(countryCode).trim().length(); 473 if (length > MAX_COUNTRY_CODES_LENGTH) { 474 MAX_COUNTRY_CODES_LENGTH = length; 475 } 476 } 477 } 478 } catch (SQLException e) { 479 Rlog.e(TAG, "Can't access HbpcdLookup database", e); 480 } finally { 481 if (cursor != null) { 482 cursor.close(); 483 } 484 } 485 return ALL_COUNTRY_CODES; 486 } 487 488 private static boolean inExceptionListForNpCcAreaLocal(NumberEntry numberEntry) { 489 int countryCode = numberEntry.countryCode; 490 boolean result = (numberEntry.number.length() == 12 491 && (countryCode == 7 || countryCode == 20 492 || countryCode == 65 || countryCode == 90)); 493 return result; 494 } 495 496 private static String getNumberPlanType(int state) { 497 String numberPlanType = "Number Plan type (" + state + "): "; 498 499 if (state == NP_NANP_LOCAL) { 500 numberPlanType = "NP_NANP_LOCAL"; 501 } else if (state == NP_NANP_AREA_LOCAL) { 502 numberPlanType = "NP_NANP_AREA_LOCAL"; 503 } else if (state == NP_NANP_NDD_AREA_LOCAL) { 504 numberPlanType = "NP_NANP_NDD_AREA_LOCAL"; 505 } else if (state == NP_NANP_NBPCD_CC_AREA_LOCAL) { 506 numberPlanType = "NP_NANP_NBPCD_CC_AREA_LOCAL"; 507 } else if (state == NP_NANP_LOCALIDD_CC_AREA_LOCAL) { 508 numberPlanType = "NP_NANP_LOCALIDD_CC_AREA_LOCAL"; 509 } else if (state == NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL) { 510 numberPlanType = "NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL"; 511 } else if (state == NP_NBPCD_HOMEIDD_CC_AREA_LOCAL) { 512 numberPlanType = "NP_NBPCD_HOMEIDD_CC_AREA_LOCAL"; 513 } else if (state == NP_HOMEIDD_CC_AREA_LOCAL) { 514 numberPlanType = "NP_HOMEIDD_CC_AREA_LOCAL"; 515 } else if (state == NP_NBPCD_CC_AREA_LOCAL) { 516 numberPlanType = "NP_NBPCD_CC_AREA_LOCAL"; 517 } else if (state == NP_LOCALIDD_CC_AREA_LOCAL) { 518 numberPlanType = "NP_LOCALIDD_CC_AREA_LOCAL"; 519 } else if (state == NP_CC_AREA_LOCAL) { 520 numberPlanType = "NP_CC_AREA_LOCAL"; 521 } else { 522 numberPlanType = "Unknown type"; 523 } 524 return numberPlanType; 525 } 526 527 /** 528 * Filter the destination number if using VZW sim card. 529 */ 530 public static String filterDestAddr(Phone phone, String destAddr) { 531 if (DBG) Rlog.d(TAG, "enter filterDestAddr. destAddr=\"" + destAddr + "\"" ); 532 533 if (destAddr == null || !PhoneNumberUtils.isGlobalPhoneNumber(destAddr)) { 534 Rlog.w(TAG, "destAddr" + destAddr + " is not a global phone number! Nothing changed."); 535 return destAddr; 536 } 537 538 final String networkOperator = TelephonyManager.from(phone.getContext()). 539 getNetworkOperator(phone.getSubId()); 540 String result = null; 541 542 if (needToConvert(phone)) { 543 final int networkType = getNetworkType(phone); 544 if (networkType != -1 && !TextUtils.isEmpty(networkOperator)) { 545 String networkMcc = networkOperator.substring(0, 3); 546 if (networkMcc != null && networkMcc.trim().length() > 0) { 547 result = formatNumber(phone.getContext(), destAddr, networkMcc, networkType); 548 } 549 } 550 } 551 552 if (DBG) { 553 Rlog.d(TAG, "destAddr is " + ((result != null)?"formatted.":"not formatted.")); 554 Rlog.d(TAG, "leave filterDestAddr, new destAddr=\"" + (result != null ? result : destAddr) + "\"" ); 555 } 556 return result != null ? result : destAddr; 557 } 558 559 /** 560 * Returns the current network type 561 */ 562 private static int getNetworkType(Phone phone) { 563 int networkType = -1; 564 int phoneType = phone.getPhoneType(); 565 566 if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { 567 networkType = GSM_UMTS_NETWORK; 568 } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { 569 if (isInternationalRoaming(phone)) { 570 networkType = CDMA_ROAMING_NETWORK; 571 } else { 572 networkType = CDMA_HOME_NETWORK; 573 } 574 } else { 575 if (DBG) Rlog.w(TAG, "warning! unknown mPhoneType value=" + phoneType); 576 } 577 578 return networkType; 579 } 580 581 private static boolean isInternationalRoaming(Phone phone) { 582 String operatorIsoCountry = TelephonyManager.from(phone.getContext()). 583 getNetworkCountryIsoForPhone(phone.getPhoneId()); 584 String simIsoCountry = TelephonyManager.from(phone.getContext()).getSimCountryIsoForPhone( 585 phone.getPhoneId()); 586 boolean internationalRoaming = !TextUtils.isEmpty(operatorIsoCountry) 587 && !TextUtils.isEmpty(simIsoCountry) 588 && !simIsoCountry.equals(operatorIsoCountry); 589 if (internationalRoaming) { 590 if ("us".equals(simIsoCountry)) { 591 internationalRoaming = !"vi".equals(operatorIsoCountry); 592 } else if ("vi".equals(simIsoCountry)) { 593 internationalRoaming = !"us".equals(operatorIsoCountry); 594 } 595 } 596 return internationalRoaming; 597 } 598 599 private static boolean needToConvert(Phone phone) { 600 boolean bNeedToConvert = false; 601 String[] listArray = phone.getContext().getResources() 602 .getStringArray(com.android.internal.R.array 603 .config_sms_convert_destination_number_support); 604 if (listArray != null && listArray.length > 0) { 605 for (int i=0; i<listArray.length; i++) { 606 if (!TextUtils.isEmpty(listArray[i])) { 607 String[] needToConvertArray = listArray[i].split(";"); 608 if (needToConvertArray != null && needToConvertArray.length > 0) { 609 if (needToConvertArray.length == 1) { 610 bNeedToConvert = "true".equalsIgnoreCase(needToConvertArray[0]); 611 } else if (needToConvertArray.length == 2 && 612 !TextUtils.isEmpty(needToConvertArray[1]) && 613 compareGid1(phone, needToConvertArray[1])) { 614 bNeedToConvert = "true".equalsIgnoreCase(needToConvertArray[0]); 615 break; 616 } 617 } 618 } 619 } 620 } 621 return bNeedToConvert; 622 } 623 624 private static boolean compareGid1(Phone phone, String serviceGid1) { 625 String gid1 = phone.getGroupIdLevel1(); 626 boolean ret = true; 627 628 if (TextUtils.isEmpty(serviceGid1)) { 629 if (DBG) Rlog.d(TAG, "compareGid1 serviceGid is empty, return " + ret); 630 return ret; 631 } 632 633 int gid_length = serviceGid1.length(); 634 // Check if gid1 match service GID1 635 if (!((gid1 != null) && (gid1.length() >= gid_length) && 636 gid1.substring(0, gid_length).equalsIgnoreCase(serviceGid1))) { 637 if (DBG) Rlog.d(TAG, " gid1 " + gid1 + " serviceGid1 " + serviceGid1); 638 ret = false; 639 } 640 if (DBG) Rlog.d(TAG, "compareGid1 is " + (ret?"Same":"Different")); 641 return ret; 642 } 643} 644