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.os.PersistableBundle;
25 import android.text.TextUtils;
26 import android.database.Cursor;
27 import android.database.SQLException;
28 import android.telephony.CarrierConfigManager;
29 import android.telephony.PhoneNumberUtils;
30 import android.telephony.TelephonyManager;
31 import android.telephony.Rlog;
32 
33 import com.android.internal.telephony.HbpcdLookup.MccIdd;
34 import 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  */
43 public 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;
NumberEntry(String number)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      */
formatNumber(Context context, String number, String activeMcc, int networkType)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      */
getAllIDDs(Context context, String mcc)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      */
checkNANP(NumberEntry numberEntry, ArrayList<String> allIDDs)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 
isNANP(String number)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      */
checkInternationalNumberPlan(Context context, NumberEntry numberEntry, ArrayList<String> allIDDs,String homeIDD)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      */
getCountryCode(Context context, String number)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      */
getAllCountryCodes(Context context)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 
inExceptionListForNpCcAreaLocal(NumberEntry numberEntry)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 
getNumberPlanType(int state)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      */
filterDestAddr(Phone phone, String destAddr)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      */
getNetworkType(Phone phone)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 
isInternationalRoaming(Phone phone)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 
needToConvert(Phone phone)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 
compareGid1(Phone phone, String serviceGid1)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