• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.internal.telephony;
18 
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 
22 import android.content.Context;
23 import android.os.Build;
24 import android.text.TextUtils;
25 import android.database.Cursor;
26 import android.database.SQLException;
27 import android.telephony.PhoneNumberUtils;
28 import android.telephony.TelephonyManager;
29 import android.telephony.Rlog;
30 
31 import com.android.internal.telephony.HbpcdLookup.MccIdd;
32 import 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  */
41 public 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;
NumberEntry(String number)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      */
formatNumber(Context context, String number, String activeMcc, int networkType)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      */
getAllIDDs(Context context, String mcc)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      */
checkNANP(NumberEntry numberEntry, ArrayList<String> allIDDs)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 
isNANP(String number)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      */
checkInternationalNumberPlan(Context context, NumberEntry numberEntry, ArrayList<String> allIDDs,String homeIDD)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      */
getCountryCode(Context context, String number)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      */
getAllCountryCodes(Context context)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 
inExceptionListForNpCcAreaLocal(NumberEntry numberEntry)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 
getNumberPlanType(int state)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      */
filterDestAddr(Phone phone, String destAddr)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      */
getNetworkType(Phone phone)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 
isInternationalRoaming(Phone phone)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 
needToConvert(Phone phone)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 
compareGid1(Phone phone, String serviceGid1)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