• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony;
18 
19 import android.content.Context;
20 import android.database.Cursor;
21 import android.database.SQLException;
22 import android.os.Binder;
23 import android.os.Build;
24 import android.os.PersistableBundle;
25 import android.telephony.CarrierConfigManager;
26 import android.telephony.PhoneNumberUtils;
27 import android.telephony.Rlog;
28 import android.telephony.TelephonyManager;
29 import android.text.TextUtils;
30 
31 import com.android.internal.telephony.HbpcdLookup.MccIdd;
32 import com.android.internal.telephony.HbpcdLookup.MccLookup;
33 
34 import java.util.ArrayList;
35 import java.util.HashMap;
36 
37 
38  /**
39  * This class implements handle the MO SMS target address before sending.
40  * This is special for VZW requirement. Follow the specifications of assisted dialing
41  * of MO SMS while traveling on VZW CDMA, international CDMA or GSM markets.
42  * {@hide}
43  */
44 public 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;
NumberEntry(String number)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 different network.
117      *
118      * @param number destination 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 formatting.
123      */
formatNumber(Context context, String number, String activeMcc, int networkType)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      */
getAllIDDs(Context context, String mcc)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      */
checkNANP(NumberEntry numberEntry, ArrayList<String> allIDDs)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 
isNANP(String number)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      */
checkInternationalNumberPlan(Context context, NumberEntry numberEntry, ArrayList<String> allIDDs,String homeIDD)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      */
getCountryCode(Context context, String number)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.parseInt(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      */
getAllCountryCodes(Context context)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 
inExceptionListForNpCcAreaLocal(NumberEntry numberEntry)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 
getNumberPlanType(int state)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_HOMEIDD_CC_AREA_LOCAL";
516         } else if (state == NP_HOMEIDD_CC_AREA_LOCAL) {
517             numberPlanType = "NP_HOMEIDD_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_LOCALIDD_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      */
filterDestAddr(Phone phone, String destAddr)533     public static String filterDestAddr(Phone phone, String destAddr) {
534         if (DBG) Rlog.d(TAG, "enter filterDestAddr. destAddr=\"" + Rlog.pii(TAG, destAddr) + "\"" );
535 
536         if (destAddr == null || !PhoneNumberUtils.isGlobalPhoneNumber(destAddr)) {
537             Rlog.w(TAG, "destAddr" + Rlog.pii(TAG, destAddr) +
538                     " is not a global phone number! Nothing changed.");
539             return destAddr;
540         }
541 
542         final String networkOperator = TelephonyManager.from(phone.getContext()).
543                 getNetworkOperator(phone.getSubId());
544         String result = null;
545 
546         if (needToConvert(phone)) {
547             final int networkType = getNetworkType(phone);
548             if (networkType != -1 && !TextUtils.isEmpty(networkOperator)) {
549                 String networkMcc = networkOperator.substring(0, 3);
550                 if (networkMcc != null && networkMcc.trim().length() > 0) {
551                     result = formatNumber(phone.getContext(), destAddr, networkMcc, networkType);
552                 }
553             }
554         }
555 
556         if (DBG) {
557             Rlog.d(TAG, "destAddr is " + ((result != null)?"formatted.":"not formatted."));
558             Rlog.d(TAG, "leave filterDestAddr, new destAddr=\"" + (result != null ? Rlog.pii(TAG,
559                     result) : Rlog.pii(TAG, destAddr)) + "\"");
560         }
561         return result != null ? result : destAddr;
562     }
563 
564     /**
565      * Returns the current network type
566      */
getNetworkType(Phone phone)567     private static int getNetworkType(Phone phone) {
568         int networkType = -1;
569         int phoneType = phone.getPhoneType();
570 
571         if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
572             networkType = GSM_UMTS_NETWORK;
573         } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
574             if (isInternationalRoaming(phone)) {
575                 networkType = CDMA_ROAMING_NETWORK;
576             } else {
577                 networkType = CDMA_HOME_NETWORK;
578             }
579         } else {
580             if (DBG) Rlog.w(TAG, "warning! unknown mPhoneType value=" + phoneType);
581         }
582 
583         return networkType;
584     }
585 
isInternationalRoaming(Phone phone)586     private static boolean isInternationalRoaming(Phone phone) {
587         String operatorIsoCountry = TelephonyManager.from(phone.getContext()).
588                 getNetworkCountryIsoForPhone(phone.getPhoneId());
589         String simIsoCountry = TelephonyManager.from(phone.getContext()).getSimCountryIsoForPhone(
590                 phone.getPhoneId());
591         boolean internationalRoaming = !TextUtils.isEmpty(operatorIsoCountry)
592                 && !TextUtils.isEmpty(simIsoCountry)
593                 && !simIsoCountry.equals(operatorIsoCountry);
594         if (internationalRoaming) {
595             if ("us".equals(simIsoCountry)) {
596                 internationalRoaming = !"vi".equals(operatorIsoCountry);
597             } else if ("vi".equals(simIsoCountry)) {
598                 internationalRoaming = !"us".equals(operatorIsoCountry);
599             }
600         }
601         return internationalRoaming;
602     }
603 
needToConvert(Phone phone)604     private static boolean needToConvert(Phone phone) {
605         // Calling package may not have READ_PHONE_STATE which is required for getConfig().
606         // Clear the calling identity so that it is called as self.
607         final long identity = Binder.clearCallingIdentity();
608         try {
609             CarrierConfigManager configManager = (CarrierConfigManager)
610                     phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
611             if (configManager != null) {
612                 PersistableBundle bundle = configManager.getConfigForSubId(phone.getSubId());
613                 if (bundle != null) {
614                     return bundle.getBoolean(CarrierConfigManager
615                             .KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL);
616                 }
617             }
618         } finally {
619             Binder.restoreCallingIdentity(identity);
620         }
621         // by default this value is false
622         return false;
623     }
624 
compareGid1(Phone phone, String serviceGid1)625     private static boolean compareGid1(Phone phone, String serviceGid1) {
626         String gid1 = phone.getGroupIdLevel1();
627         boolean ret = true;
628 
629         if (TextUtils.isEmpty(serviceGid1)) {
630             if (DBG) Rlog.d(TAG, "compareGid1 serviceGid is empty, return " + ret);
631             return ret;
632         }
633 
634         int gid_length = serviceGid1.length();
635         // Check if gid1 match service GID1
636         if (!((gid1 != null) && (gid1.length() >= gid_length) &&
637                 gid1.substring(0, gid_length).equalsIgnoreCase(serviceGid1))) {
638             if (DBG) Rlog.d(TAG, " gid1 " + gid1 + " serviceGid1 " + serviceGid1);
639             ret = false;
640         }
641         if (DBG) Rlog.d(TAG, "compareGid1 is " + (ret?"Same":"Different"));
642         return ret;
643     }
644 }
645