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