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