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