Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2006 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 android.telephony;
     18 
     19 import com.android.i18n.phonenumbers.NumberParseException;
     20 import com.android.i18n.phonenumbers.PhoneNumberUtil;
     21 import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
     22 import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
     23 import com.android.i18n.phonenumbers.ShortNumberUtil;
     24 
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.database.Cursor;
     28 import android.location.CountryDetector;
     29 import android.net.Uri;
     30 import android.os.SystemProperties;
     31 import android.provider.Contacts;
     32 import android.provider.ContactsContract;
     33 import android.telecom.PhoneAccount;
     34 import android.text.Editable;
     35 import android.text.Spannable;
     36 import android.text.SpannableStringBuilder;
     37 import android.text.TextUtils;
     38 import android.text.style.TtsSpan;
     39 import android.util.SparseIntArray;
     40 
     41 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING;
     42 
     43 import java.util.Locale;
     44 import java.util.regex.Matcher;
     45 import java.util.regex.Pattern;
     46 
     47 /**
     48  * Various utilities for dealing with phone number strings.
     49  */
     50 public class PhoneNumberUtils
     51 {
     52     /*
     53      * Special characters
     54      *
     55      * (See "What is a phone number?" doc)
     56      * 'p' --- GSM pause character, same as comma
     57      * 'n' --- GSM wild character
     58      * 'w' --- GSM wait character
     59      */
     60     public static final char PAUSE = ',';
     61     public static final char WAIT = ';';
     62     public static final char WILD = 'N';
     63 
     64     /*
     65      * Calling Line Identification Restriction (CLIR)
     66      */
     67     private static final String CLIR_ON = "*31#";
     68     private static final String CLIR_OFF = "#31#";
     69 
     70     /*
     71      * TOA = TON + NPI
     72      * See TS 24.008 section 10.5.4.7 for details.
     73      * These are the only really useful TOA values
     74      */
     75     public static final int TOA_International = 0x91;
     76     public static final int TOA_Unknown = 0x81;
     77 
     78     static final String LOG_TAG = "PhoneNumberUtils";
     79     private static final boolean DBG = false;
     80 
     81     /*
     82      * global-phone-number = ["+"] 1*( DIGIT / written-sep )
     83      * written-sep         = ("-"/".")
     84      */
     85     private static final Pattern GLOBAL_PHONE_NUMBER_PATTERN =
     86             Pattern.compile("[\\+]?[0-9.-]+");
     87 
     88     /** True if c is ISO-LATIN characters 0-9 */
     89     public static boolean
     90     isISODigit (char c) {
     91         return c >= '0' && c <= '9';
     92     }
     93 
     94     /** True if c is ISO-LATIN characters 0-9, *, # */
     95     public final static boolean
     96     is12Key(char c) {
     97         return (c >= '0' && c <= '9') || c == '*' || c == '#';
     98     }
     99 
    100     /** True if c is ISO-LATIN characters 0-9, *, # , +, WILD  */
    101     public final static boolean
    102     isDialable(char c) {
    103         return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+' || c == WILD;
    104     }
    105 
    106     /** True if c is ISO-LATIN characters 0-9, *, # , + (no WILD)  */
    107     public final static boolean
    108     isReallyDialable(char c) {
    109         return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+';
    110     }
    111 
    112     /** True if c is ISO-LATIN characters 0-9, *, # , +, WILD, WAIT, PAUSE   */
    113     public final static boolean
    114     isNonSeparator(char c) {
    115         return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+'
    116                 || c == WILD || c == WAIT || c == PAUSE;
    117     }
    118 
    119     /** This any anything to the right of this char is part of the
    120      *  post-dial string (eg this is PAUSE or WAIT)
    121      */
    122     public final static boolean
    123     isStartsPostDial (char c) {
    124         return c == PAUSE || c == WAIT;
    125     }
    126 
    127     private static boolean
    128     isPause (char c){
    129         return c == 'p'||c == 'P';
    130     }
    131 
    132     private static boolean
    133     isToneWait (char c){
    134         return c == 'w'||c == 'W';
    135     }
    136 
    137 
    138     /** Returns true if ch is not dialable or alpha char */
    139     private static boolean isSeparator(char ch) {
    140         return !isDialable(ch) && !(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'));
    141     }
    142 
    143     /** Extracts the phone number from an Intent.
    144      *
    145      * @param intent the intent to get the number of
    146      * @param context a context to use for database access
    147      *
    148      * @return the phone number that would be called by the intent, or
    149      *         <code>null</code> if the number cannot be found.
    150      */
    151     public static String getNumberFromIntent(Intent intent, Context context) {
    152         String number = null;
    153 
    154         Uri uri = intent.getData();
    155 
    156         if (uri == null) {
    157             return null;
    158         }
    159 
    160         String scheme = uri.getScheme();
    161 
    162         if (scheme.equals("tel") || scheme.equals("sip")) {
    163             return uri.getSchemeSpecificPart();
    164         }
    165 
    166         if (context == null) {
    167             return null;
    168         }
    169 
    170         String type = intent.resolveType(context);
    171         String phoneColumn = null;
    172 
    173         // Correctly read out the phone entry based on requested provider
    174         final String authority = uri.getAuthority();
    175         if (Contacts.AUTHORITY.equals(authority)) {
    176             phoneColumn = Contacts.People.Phones.NUMBER;
    177         } else if (ContactsContract.AUTHORITY.equals(authority)) {
    178             phoneColumn = ContactsContract.CommonDataKinds.Phone.NUMBER;
    179         }
    180 
    181         Cursor c = null;
    182         try {
    183             c = context.getContentResolver().query(uri, new String[] { phoneColumn },
    184                     null, null, null);
    185             if (c != null) {
    186                 if (c.moveToFirst()) {
    187                     number = c.getString(c.getColumnIndex(phoneColumn));
    188                 }
    189             }
    190         } catch (RuntimeException e) {
    191             Rlog.e(LOG_TAG, "Error getting phone number.", e);
    192         } finally {
    193             if (c != null) {
    194                 c.close();
    195             }
    196         }
    197 
    198         return number;
    199     }
    200 
    201     /** Extracts the network address portion and canonicalizes
    202      *  (filters out separators.)
    203      *  Network address portion is everything up to DTMF control digit
    204      *  separators (pause or wait), but without non-dialable characters.
    205      *
    206      *  Please note that the GSM wild character is allowed in the result.
    207      *  This must be resolved before dialing.
    208      *
    209      *  Returns null if phoneNumber == null
    210      */
    211     public static String
    212     extractNetworkPortion(String phoneNumber) {
    213         if (phoneNumber == null) {
    214             return null;
    215         }
    216 
    217         int len = phoneNumber.length();
    218         StringBuilder ret = new StringBuilder(len);
    219 
    220         for (int i = 0; i < len; i++) {
    221             char c = phoneNumber.charAt(i);
    222             // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
    223             int digit = Character.digit(c, 10);
    224             if (digit != -1) {
    225                 ret.append(digit);
    226             } else if (c == '+') {
    227                 // Allow '+' as first character or after CLIR MMI prefix
    228                 String prefix = ret.toString();
    229                 if (prefix.length() == 0 || prefix.equals(CLIR_ON) || prefix.equals(CLIR_OFF)) {
    230                     ret.append(c);
    231                 }
    232             } else if (isDialable(c)) {
    233                 ret.append(c);
    234             } else if (isStartsPostDial (c)) {
    235                 break;
    236             }
    237         }
    238 
    239         return ret.toString();
    240     }
    241 
    242     /**
    243      * Extracts the network address portion and canonicalize.
    244      *
    245      * This function is equivalent to extractNetworkPortion(), except
    246      * for allowing the PLUS character to occur at arbitrary positions
    247      * in the address portion, not just the first position.
    248      *
    249      * @hide
    250      */
    251     public static String extractNetworkPortionAlt(String phoneNumber) {
    252         if (phoneNumber == null) {
    253             return null;
    254         }
    255 
    256         int len = phoneNumber.length();
    257         StringBuilder ret = new StringBuilder(len);
    258         boolean haveSeenPlus = false;
    259 
    260         for (int i = 0; i < len; i++) {
    261             char c = phoneNumber.charAt(i);
    262             if (c == '+') {
    263                 if (haveSeenPlus) {
    264                     continue;
    265                 }
    266                 haveSeenPlus = true;
    267             }
    268             if (isDialable(c)) {
    269                 ret.append(c);
    270             } else if (isStartsPostDial (c)) {
    271                 break;
    272             }
    273         }
    274 
    275         return ret.toString();
    276     }
    277 
    278     /**
    279      * Strips separators from a phone number string.
    280      * @param phoneNumber phone number to strip.
    281      * @return phone string stripped of separators.
    282      */
    283     public static String stripSeparators(String phoneNumber) {
    284         if (phoneNumber == null) {
    285             return null;
    286         }
    287         int len = phoneNumber.length();
    288         StringBuilder ret = new StringBuilder(len);
    289 
    290         for (int i = 0; i < len; i++) {
    291             char c = phoneNumber.charAt(i);
    292             // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
    293             int digit = Character.digit(c, 10);
    294             if (digit != -1) {
    295                 ret.append(digit);
    296             } else if (isNonSeparator(c)) {
    297                 ret.append(c);
    298             }
    299         }
    300 
    301         return ret.toString();
    302     }
    303 
    304     /**
    305      * Translates keypad letters to actual digits (e.g. 1-800-GOOG-411 will
    306      * become 1-800-4664-411), and then strips all separators (e.g. 1-800-4664-411 will become
    307      * 18004664411).
    308      *
    309      * @see #convertKeypadLettersToDigits(String)
    310      * @see #stripSeparators(String)
    311      *
    312      * @hide
    313      */
    314     public static String convertAndStrip(String phoneNumber) {
    315         return stripSeparators(convertKeypadLettersToDigits(phoneNumber));
    316     }
    317 
    318     /**
    319      * Converts pause and tonewait pause characters
    320      * to Android representation.
    321      * RFC 3601 says pause is 'p' and tonewait is 'w'.
    322      * @hide
    323      */
    324     public static String convertPreDial(String phoneNumber) {
    325         if (phoneNumber == null) {
    326             return null;
    327         }
    328         int len = phoneNumber.length();
    329         StringBuilder ret = new StringBuilder(len);
    330 
    331         for (int i = 0; i < len; i++) {
    332             char c = phoneNumber.charAt(i);
    333 
    334             if (isPause(c)) {
    335                 c = PAUSE;
    336             } else if (isToneWait(c)) {
    337                 c = WAIT;
    338             }
    339             ret.append(c);
    340         }
    341         return ret.toString();
    342     }
    343 
    344     /** or -1 if both are negative */
    345     static private int
    346     minPositive (int a, int b) {
    347         if (a >= 0 && b >= 0) {
    348             return (a < b) ? a : b;
    349         } else if (a >= 0) { /* && b < 0 */
    350             return a;
    351         } else if (b >= 0) { /* && a < 0 */
    352             return b;
    353         } else { /* a < 0 && b < 0 */
    354             return -1;
    355         }
    356     }
    357 
    358     private static void log(String msg) {
    359         Rlog.d(LOG_TAG, msg);
    360     }
    361     /** index of the last character of the network portion
    362      *  (eg anything after is a post-dial string)
    363      */
    364     static private int
    365     indexOfLastNetworkChar(String a) {
    366         int pIndex, wIndex;
    367         int origLength;
    368         int trimIndex;
    369 
    370         origLength = a.length();
    371 
    372         pIndex = a.indexOf(PAUSE);
    373         wIndex = a.indexOf(WAIT);
    374 
    375         trimIndex = minPositive(pIndex, wIndex);
    376 
    377         if (trimIndex < 0) {
    378             return origLength - 1;
    379         } else {
    380             return trimIndex - 1;
    381         }
    382     }
    383 
    384     /**
    385      * Extracts the post-dial sequence of DTMF control digits, pauses, and
    386      * waits. Strips separators. This string may be empty, but will not be null
    387      * unless phoneNumber == null.
    388      *
    389      * Returns null if phoneNumber == null
    390      */
    391 
    392     public static String
    393     extractPostDialPortion(String phoneNumber) {
    394         if (phoneNumber == null) return null;
    395 
    396         int trimIndex;
    397         StringBuilder ret = new StringBuilder();
    398 
    399         trimIndex = indexOfLastNetworkChar (phoneNumber);
    400 
    401         for (int i = trimIndex + 1, s = phoneNumber.length()
    402                 ; i < s; i++
    403         ) {
    404             char c = phoneNumber.charAt(i);
    405             if (isNonSeparator(c)) {
    406                 ret.append(c);
    407             }
    408         }
    409 
    410         return ret.toString();
    411     }
    412 
    413     /**
    414      * Compare phone numbers a and b, return true if they're identical enough for caller ID purposes.
    415      */
    416     public static boolean compare(String a, String b) {
    417         // We've used loose comparation at least Eclair, which may change in the future.
    418 
    419         return compare(a, b, false);
    420     }
    421 
    422     /**
    423      * Compare phone numbers a and b, and return true if they're identical
    424      * enough for caller ID purposes. Checks a resource to determine whether
    425      * to use a strict or loose comparison algorithm.
    426      */
    427     public static boolean compare(Context context, String a, String b) {
    428         boolean useStrict = context.getResources().getBoolean(
    429                com.android.internal.R.bool.config_use_strict_phone_number_comparation);
    430         return compare(a, b, useStrict);
    431     }
    432 
    433     /**
    434      * @hide only for testing.
    435      */
    436     public static boolean compare(String a, String b, boolean useStrictComparation) {
    437         return (useStrictComparation ? compareStrictly(a, b) : compareLoosely(a, b));
    438     }
    439 
    440     /**
    441      * Compare phone numbers a and b, return true if they're identical
    442      * enough for caller ID purposes.
    443      *
    444      * - Compares from right to left
    445      * - requires MIN_MATCH (7) characters to match
    446      * - handles common trunk prefixes and international prefixes
    447      *   (basically, everything except the Russian trunk prefix)
    448      *
    449      * Note that this method does not return false even when the two phone numbers
    450      * are not exactly same; rather; we can call this method "similar()", not "equals()".
    451      *
    452      * @hide
    453      */
    454     public static boolean
    455     compareLoosely(String a, String b) {
    456         int ia, ib;
    457         int matched;
    458         int numNonDialableCharsInA = 0;
    459         int numNonDialableCharsInB = 0;
    460 
    461         if (a == null || b == null) return a == b;
    462 
    463         if (a.length() == 0 || b.length() == 0) {
    464             return false;
    465         }
    466 
    467         ia = indexOfLastNetworkChar (a);
    468         ib = indexOfLastNetworkChar (b);
    469         matched = 0;
    470 
    471         while (ia >= 0 && ib >=0) {
    472             char ca, cb;
    473             boolean skipCmp = false;
    474 
    475             ca = a.charAt(ia);
    476 
    477             if (!isDialable(ca)) {
    478                 ia--;
    479                 skipCmp = true;
    480                 numNonDialableCharsInA++;
    481             }
    482 
    483             cb = b.charAt(ib);
    484 
    485             if (!isDialable(cb)) {
    486                 ib--;
    487                 skipCmp = true;
    488                 numNonDialableCharsInB++;
    489             }
    490 
    491             if (!skipCmp) {
    492                 if (cb != ca && ca != WILD && cb != WILD) {
    493                     break;
    494                 }
    495                 ia--; ib--; matched++;
    496             }
    497         }
    498 
    499         if (matched < MIN_MATCH) {
    500             int effectiveALen = a.length() - numNonDialableCharsInA;
    501             int effectiveBLen = b.length() - numNonDialableCharsInB;
    502 
    503 
    504             // if the number of dialable chars in a and b match, but the matched chars < MIN_MATCH,
    505             // treat them as equal (i.e. 404-04 and 40404)
    506             if (effectiveALen == effectiveBLen && effectiveALen == matched) {
    507                 return true;
    508             }
    509 
    510             return false;
    511         }
    512 
    513         // At least one string has matched completely;
    514         if (matched >= MIN_MATCH && (ia < 0 || ib < 0)) {
    515             return true;
    516         }
    517 
    518         /*
    519          * Now, what remains must be one of the following for a
    520          * match:
    521          *
    522          *  - a '+' on one and a '00' or a '011' on the other
    523          *  - a '0' on one and a (+,00)<country code> on the other
    524          *     (for this, a '0' and a '00' prefix would have succeeded above)
    525          */
    526 
    527         if (matchIntlPrefix(a, ia + 1)
    528             && matchIntlPrefix (b, ib +1)
    529         ) {
    530             return true;
    531         }
    532 
    533         if (matchTrunkPrefix(a, ia + 1)
    534             && matchIntlPrefixAndCC(b, ib +1)
    535         ) {
    536             return true;
    537         }
    538 
    539         if (matchTrunkPrefix(b, ib + 1)
    540             && matchIntlPrefixAndCC(a, ia +1)
    541         ) {
    542             return true;
    543         }
    544 
    545         return false;
    546     }
    547 
    548     /**
    549      * @hide
    550      */
    551     public static boolean
    552     compareStrictly(String a, String b) {
    553         return compareStrictly(a, b, true);
    554     }
    555 
    556     /**
    557      * @hide
    558      */
    559     public static boolean
    560     compareStrictly(String a, String b, boolean acceptInvalidCCCPrefix) {
    561         if (a == null || b == null) {
    562             return a == b;
    563         } else if (a.length() == 0 && b.length() == 0) {
    564             return false;
    565         }
    566 
    567         int forwardIndexA = 0;
    568         int forwardIndexB = 0;
    569 
    570         CountryCallingCodeAndNewIndex cccA =
    571             tryGetCountryCallingCodeAndNewIndex(a, acceptInvalidCCCPrefix);
    572         CountryCallingCodeAndNewIndex cccB =
    573             tryGetCountryCallingCodeAndNewIndex(b, acceptInvalidCCCPrefix);
    574         boolean bothHasCountryCallingCode = false;
    575         boolean okToIgnorePrefix = true;
    576         boolean trunkPrefixIsOmittedA = false;
    577         boolean trunkPrefixIsOmittedB = false;
    578         if (cccA != null && cccB != null) {
    579             if (cccA.countryCallingCode != cccB.countryCallingCode) {
    580                 // Different Country Calling Code. Must be different phone number.
    581                 return false;
    582             }
    583             // When both have ccc, do not ignore trunk prefix. Without this,
    584             // "+81123123" becomes same as "+810123123" (+81 == Japan)
    585             okToIgnorePrefix = false;
    586             bothHasCountryCallingCode = true;
    587             forwardIndexA = cccA.newIndex;
    588             forwardIndexB = cccB.newIndex;
    589         } else if (cccA == null && cccB == null) {
    590             // When both do not have ccc, do not ignore trunk prefix. Without this,
    591             // "123123" becomes same as "0123123"
    592             okToIgnorePrefix = false;
    593         } else {
    594             if (cccA != null) {
    595                 forwardIndexA = cccA.newIndex;
    596             } else {
    597                 int tmp = tryGetTrunkPrefixOmittedIndex(b, 0);
    598                 if (tmp >= 0) {
    599                     forwardIndexA = tmp;
    600                     trunkPrefixIsOmittedA = true;
    601                 }
    602             }
    603             if (cccB != null) {
    604                 forwardIndexB = cccB.newIndex;
    605             } else {
    606                 int tmp = tryGetTrunkPrefixOmittedIndex(b, 0);
    607                 if (tmp >= 0) {
    608                     forwardIndexB = tmp;
    609                     trunkPrefixIsOmittedB = true;
    610                 }
    611             }
    612         }
    613 
    614         int backwardIndexA = a.length() - 1;
    615         int backwardIndexB = b.length() - 1;
    616         while (backwardIndexA >= forwardIndexA && backwardIndexB >= forwardIndexB) {
    617             boolean skip_compare = false;
    618             final char chA = a.charAt(backwardIndexA);
    619             final char chB = b.charAt(backwardIndexB);
    620             if (isSeparator(chA)) {
    621                 backwardIndexA--;
    622                 skip_compare = true;
    623             }
    624             if (isSeparator(chB)) {
    625                 backwardIndexB--;
    626                 skip_compare = true;
    627             }
    628 
    629             if (!skip_compare) {
    630                 if (chA != chB) {
    631                     return false;
    632                 }
    633                 backwardIndexA--;
    634                 backwardIndexB--;
    635             }
    636         }
    637 
    638         if (okToIgnorePrefix) {
    639             if ((trunkPrefixIsOmittedA && forwardIndexA <= backwardIndexA) ||
    640                 !checkPrefixIsIgnorable(a, forwardIndexA, backwardIndexA)) {
    641                 if (acceptInvalidCCCPrefix) {
    642                     // Maybe the code handling the special case for Thailand makes the
    643                     // result garbled, so disable the code and try again.
    644                     // e.g. "16610001234" must equal to "6610001234", but with
    645                     //      Thailand-case handling code, they become equal to each other.
    646                     //
    647                     // Note: we select simplicity rather than adding some complicated
    648                     //       logic here for performance(like "checking whether remaining
    649                     //       numbers are just 66 or not"), assuming inputs are small
    650                     //       enough.
    651                     return compare(a, b, false);
    652                 } else {
    653                     return false;
    654                 }
    655             }
    656             if ((trunkPrefixIsOmittedB && forwardIndexB <= backwardIndexB) ||
    657                 !checkPrefixIsIgnorable(b, forwardIndexA, backwardIndexB)) {
    658                 if (acceptInvalidCCCPrefix) {
    659                     return compare(a, b, false);
    660                 } else {
    661                     return false;
    662                 }
    663             }
    664         } else {
    665             // In the US, 1-650-555-1234 must be equal to 650-555-1234,
    666             // while 090-1234-1234 must not be equal to 90-1234-1234 in Japan.
    667             // This request exists just in US (with 1 trunk (NDD) prefix).
    668             // In addition, "011 11 7005554141" must not equal to "+17005554141",
    669             // while "011 1 7005554141" must equal to "+17005554141"
    670             //
    671             // In this comparison, we ignore the prefix '1' just once, when
    672             // - at least either does not have CCC, or
    673             // - the remaining non-separator number is 1
    674             boolean maybeNamp = !bothHasCountryCallingCode;
    675             while (backwardIndexA >= forwardIndexA) {
    676                 final char chA = a.charAt(backwardIndexA);
    677                 if (isDialable(chA)) {
    678                     if (maybeNamp && tryGetISODigit(chA) == 1) {
    679                         maybeNamp = false;
    680                     } else {
    681                         return false;
    682                     }
    683                 }
    684                 backwardIndexA--;
    685             }
    686             while (backwardIndexB >= forwardIndexB) {
    687                 final char chB = b.charAt(backwardIndexB);
    688                 if (isDialable(chB)) {
    689                     if (maybeNamp && tryGetISODigit(chB) == 1) {
    690                         maybeNamp = false;
    691                     } else {
    692                         return false;
    693                     }
    694                 }
    695                 backwardIndexB--;
    696             }
    697         }
    698 
    699         return true;
    700     }
    701 
    702     /**
    703      * Returns the rightmost MIN_MATCH (5) characters in the network portion
    704      * in *reversed* order
    705      *
    706      * This can be used to do a database lookup against the column
    707      * that stores getStrippedReversed()
    708      *
    709      * Returns null if phoneNumber == null
    710      */
    711     public static String
    712     toCallerIDMinMatch(String phoneNumber) {
    713         String np = extractNetworkPortionAlt(phoneNumber);
    714         return internalGetStrippedReversed(np, MIN_MATCH);
    715     }
    716 
    717     /**
    718      * Returns the network portion reversed.
    719      * This string is intended to go into an index column for a
    720      * database lookup.
    721      *
    722      * Returns null if phoneNumber == null
    723      */
    724     public static String
    725     getStrippedReversed(String phoneNumber) {
    726         String np = extractNetworkPortionAlt(phoneNumber);
    727 
    728         if (np == null) return null;
    729 
    730         return internalGetStrippedReversed(np, np.length());
    731     }
    732 
    733     /**
    734      * Returns the last numDigits of the reversed phone number
    735      * Returns null if np == null
    736      */
    737     private static String
    738     internalGetStrippedReversed(String np, int numDigits) {
    739         if (np == null) return null;
    740 
    741         StringBuilder ret = new StringBuilder(numDigits);
    742         int length = np.length();
    743 
    744         for (int i = length - 1, s = length
    745             ; i >= 0 && (s - i) <= numDigits ; i--
    746         ) {
    747             char c = np.charAt(i);
    748 
    749             ret.append(c);
    750         }
    751 
    752         return ret.toString();
    753     }
    754 
    755     /**
    756      * Basically: makes sure there's a + in front of a
    757      * TOA_International number
    758      *
    759      * Returns null if s == null
    760      */
    761     public static String
    762     stringFromStringAndTOA(String s, int TOA) {
    763         if (s == null) return null;
    764 
    765         if (TOA == TOA_International && s.length() > 0 && s.charAt(0) != '+') {
    766             return "+" + s;
    767         }
    768 
    769         return s;
    770     }
    771 
    772     /**
    773      * Returns the TOA for the given dial string
    774      * Basically, returns TOA_International if there's a + prefix
    775      */
    776 
    777     public static int
    778     toaFromString(String s) {
    779         if (s != null && s.length() > 0 && s.charAt(0) == '+') {
    780             return TOA_International;
    781         }
    782 
    783         return TOA_Unknown;
    784     }
    785 
    786     /**
    787      *  3GPP TS 24.008 10.5.4.7
    788      *  Called Party BCD Number
    789      *
    790      *  See Also TS 51.011 10.5.1 "dialing number/ssc string"
    791      *  and TS 11.11 "10.3.1 EF adn (Abbreviated dialing numbers)"
    792      *
    793      * @param bytes the data buffer
    794      * @param offset should point to the TOA (aka. TON/NPI) octet after the length byte
    795      * @param length is the number of bytes including TOA byte
    796      *                and must be at least 2
    797      *
    798      * @return partial string on invalid decode
    799      *
    800      * FIXME(mkf) support alphanumeric address type
    801      *  currently implemented in SMSMessage.getAddress()
    802      */
    803     public static String
    804     calledPartyBCDToString (byte[] bytes, int offset, int length) {
    805         boolean prependPlus = false;
    806         StringBuilder ret = new StringBuilder(1 + length * 2);
    807 
    808         if (length < 2) {
    809             return "";
    810         }
    811 
    812         //Only TON field should be taken in consideration
    813         if ((bytes[offset] & 0xf0) == (TOA_International & 0xf0)) {
    814             prependPlus = true;
    815         }
    816 
    817         internalCalledPartyBCDFragmentToString(
    818                 ret, bytes, offset + 1, length - 1);
    819 
    820         if (prependPlus && ret.length() == 0) {
    821             // If the only thing there is a prepended plus, return ""
    822             return "";
    823         }
    824 
    825         if (prependPlus) {
    826             // This is an "international number" and should have
    827             // a plus prepended to the dialing number. But there
    828             // can also be GSM MMI codes as defined in TS 22.030 6.5.2
    829             // so we need to handle those also.
    830             //
    831             // http://web.telia.com/~u47904776/gsmkode.htm
    832             // has a nice list of some of these GSM codes.
    833             //
    834             // Examples are:
    835             //   **21*+886988171479#
    836             //   **21*8311234567#
    837             //   *21#
    838             //   #21#
    839             //   *#21#
    840             //   *31#+11234567890
    841             //   #31#+18311234567
    842             //   #31#8311234567
    843             //   18311234567
    844             //   +18311234567#
    845             //   +18311234567
    846             // Odd ball cases that some phones handled
    847             // where there is no dialing number so they
    848             // append the "+"
    849             //   *21#+
    850             //   **21#+
    851             String retString = ret.toString();
    852             Pattern p = Pattern.compile("(^[#*])(.*)([#*])(.*)(#)$");
    853             Matcher m = p.matcher(retString);
    854             if (m.matches()) {
    855                 if ("".equals(m.group(2))) {
    856                     // Started with two [#*] ends with #
    857                     // So no dialing number and we'll just
    858                     // append a +, this handles **21#+
    859                     ret = new StringBuilder();
    860                     ret.append(m.group(1));
    861                     ret.append(m.group(3));
    862                     ret.append(m.group(4));
    863                     ret.append(m.group(5));
    864                     ret.append("+");
    865                 } else {
    866                     // Starts with [#*] and ends with #
    867                     // Assume group 4 is a dialing number
    868                     // such as *21*+1234554#
    869                     ret = new StringBuilder();
    870                     ret.append(m.group(1));
    871                     ret.append(m.group(2));
    872                     ret.append(m.group(3));
    873                     ret.append("+");
    874                     ret.append(m.group(4));
    875                     ret.append(m.group(5));
    876                 }
    877             } else {
    878                 p = Pattern.compile("(^[#*])(.*)([#*])(.*)");
    879                 m = p.matcher(retString);
    880                 if (m.matches()) {
    881                     // Starts with [#*] and only one other [#*]
    882                     // Assume the data after last [#*] is dialing
    883                     // number (i.e. group 4) such as *31#+11234567890.
    884                     // This also includes the odd ball *21#+
    885                     ret = new StringBuilder();
    886                     ret.append(m.group(1));
    887                     ret.append(m.group(2));
    888                     ret.append(m.group(3));
    889                     ret.append("+");
    890                     ret.append(m.group(4));
    891                 } else {
    892                     // Does NOT start with [#*] just prepend '+'
    893                     ret = new StringBuilder();
    894                     ret.append('+');
    895                     ret.append(retString);
    896                 }
    897             }
    898         }
    899 
    900         return ret.toString();
    901     }
    902 
    903     private static void
    904     internalCalledPartyBCDFragmentToString(
    905         StringBuilder sb, byte [] bytes, int offset, int length) {
    906         for (int i = offset ; i < length + offset ; i++) {
    907             byte b;
    908             char c;
    909 
    910             c = bcdToChar((byte)(bytes[i] & 0xf));
    911 
    912             if (c == 0) {
    913                 return;
    914             }
    915             sb.append(c);
    916 
    917             // FIXME(mkf) TS 23.040 9.1.2.3 says
    918             // "if a mobile receives 1111 in a position prior to
    919             // the last semi-octet then processing shall commence with
    920             // the next semi-octet and the intervening
    921             // semi-octet shall be ignored"
    922             // How does this jive with 24.008 10.5.4.7
    923 
    924             b = (byte)((bytes[i] >> 4) & 0xf);
    925 
    926             if (b == 0xf && i + 1 == length + offset) {
    927                 //ignore final 0xf
    928                 break;
    929             }
    930 
    931             c = bcdToChar(b);
    932             if (c == 0) {
    933                 return;
    934             }
    935 
    936             sb.append(c);
    937         }
    938 
    939     }
    940 
    941     /**
    942      * Like calledPartyBCDToString, but field does not start with a
    943      * TOA byte. For example: SIM ADN extension fields
    944      */
    945 
    946     public static String
    947     calledPartyBCDFragmentToString(byte [] bytes, int offset, int length) {
    948         StringBuilder ret = new StringBuilder(length * 2);
    949 
    950         internalCalledPartyBCDFragmentToString(ret, bytes, offset, length);
    951 
    952         return ret.toString();
    953     }
    954 
    955     /** returns 0 on invalid value */
    956     private static char
    957     bcdToChar(byte b) {
    958         if (b < 0xa) {
    959             return (char)('0' + b);
    960         } else switch (b) {
    961             case 0xa: return '*';
    962             case 0xb: return '#';
    963             case 0xc: return PAUSE;
    964             case 0xd: return WILD;
    965 
    966             default: return 0;
    967         }
    968     }
    969 
    970     private static int
    971     charToBCD(char c) {
    972         if (c >= '0' && c <= '9') {
    973             return c - '0';
    974         } else if (c == '*') {
    975             return 0xa;
    976         } else if (c == '#') {
    977             return 0xb;
    978         } else if (c == PAUSE) {
    979             return 0xc;
    980         } else if (c == WILD) {
    981             return 0xd;
    982         } else if (c == WAIT) {
    983             return 0xe;
    984         } else {
    985             throw new RuntimeException ("invalid char for BCD " + c);
    986         }
    987     }
    988 
    989     /**
    990      * Return true iff the network portion of <code>address</code> is,
    991      * as far as we can tell on the device, suitable for use as an SMS
    992      * destination address.
    993      */
    994     public static boolean isWellFormedSmsAddress(String address) {
    995         String networkPortion =
    996                 PhoneNumberUtils.extractNetworkPortion(address);
    997 
    998         return (!(networkPortion.equals("+")
    999                   || TextUtils.isEmpty(networkPortion)))
   1000                && isDialable(networkPortion);
   1001     }
   1002 
   1003     public static boolean isGlobalPhoneNumber(String phoneNumber) {
   1004         if (TextUtils.isEmpty(phoneNumber)) {
   1005             return false;
   1006         }
   1007 
   1008         Matcher match = GLOBAL_PHONE_NUMBER_PATTERN.matcher(phoneNumber);
   1009         return match.matches();
   1010     }
   1011 
   1012     private static boolean isDialable(String address) {
   1013         for (int i = 0, count = address.length(); i < count; i++) {
   1014             if (!isDialable(address.charAt(i))) {
   1015                 return false;
   1016             }
   1017         }
   1018         return true;
   1019     }
   1020 
   1021     private static boolean isNonSeparator(String address) {
   1022         for (int i = 0, count = address.length(); i < count; i++) {
   1023             if (!isNonSeparator(address.charAt(i))) {
   1024                 return false;
   1025             }
   1026         }
   1027         return true;
   1028     }
   1029     /**
   1030      * Note: calls extractNetworkPortion(), so do not use for
   1031      * SIM EF[ADN] style records
   1032      *
   1033      * Returns null if network portion is empty.
   1034      */
   1035     public static byte[]
   1036     networkPortionToCalledPartyBCD(String s) {
   1037         String networkPortion = extractNetworkPortion(s);
   1038         return numberToCalledPartyBCDHelper(networkPortion, false);
   1039     }
   1040 
   1041     /**
   1042      * Same as {@link #networkPortionToCalledPartyBCD}, but includes a
   1043      * one-byte length prefix.
   1044      */
   1045     public static byte[]
   1046     networkPortionToCalledPartyBCDWithLength(String s) {
   1047         String networkPortion = extractNetworkPortion(s);
   1048         return numberToCalledPartyBCDHelper(networkPortion, true);
   1049     }
   1050 
   1051     /**
   1052      * Convert a dialing number to BCD byte array
   1053      *
   1054      * @param number dialing number string
   1055      *        if the dialing number starts with '+', set to international TOA
   1056      * @return BCD byte array
   1057      */
   1058     public static byte[]
   1059     numberToCalledPartyBCD(String number) {
   1060         return numberToCalledPartyBCDHelper(number, false);
   1061     }
   1062 
   1063     /**
   1064      * If includeLength is true, prepend a one-byte length value to
   1065      * the return array.
   1066      */
   1067     private static byte[]
   1068     numberToCalledPartyBCDHelper(String number, boolean includeLength) {
   1069         int numberLenReal = number.length();
   1070         int numberLenEffective = numberLenReal;
   1071         boolean hasPlus = number.indexOf('+') != -1;
   1072         if (hasPlus) numberLenEffective--;
   1073 
   1074         if (numberLenEffective == 0) return null;
   1075 
   1076         int resultLen = (numberLenEffective + 1) / 2;  // Encoded numbers require only 4 bits each.
   1077         int extraBytes = 1;                            // Prepended TOA byte.
   1078         if (includeLength) extraBytes++;               // Optional prepended length byte.
   1079         resultLen += extraBytes;
   1080 
   1081         byte[] result = new byte[resultLen];
   1082 
   1083         int digitCount = 0;
   1084         for (int i = 0; i < numberLenReal; i++) {
   1085             char c = number.charAt(i);
   1086             if (c == '+') continue;
   1087             int shift = ((digitCount & 0x01) == 1) ? 4 : 0;
   1088             result[extraBytes + (digitCount >> 1)] |= (byte)((charToBCD(c) & 0x0F) << shift);
   1089             digitCount++;
   1090         }
   1091 
   1092         // 1-fill any trailing odd nibble/quartet.
   1093         if ((digitCount & 0x01) == 1) result[extraBytes + (digitCount >> 1)] |= 0xF0;
   1094 
   1095         int offset = 0;
   1096         if (includeLength) result[offset++] = (byte)(resultLen - 1);
   1097         result[offset] = (byte)(hasPlus ? TOA_International : TOA_Unknown);
   1098 
   1099         return result;
   1100     }
   1101 
   1102     //================ Number formatting =========================
   1103 
   1104     /** The current locale is unknown, look for a country code or don't format */
   1105     public static final int FORMAT_UNKNOWN = 0;
   1106     /** NANP formatting */
   1107     public static final int FORMAT_NANP = 1;
   1108     /** Japanese formatting */
   1109     public static final int FORMAT_JAPAN = 2;
   1110 
   1111     /** List of country codes for countries that use the NANP */
   1112     private static final String[] NANP_COUNTRIES = new String[] {
   1113         "US", // United States
   1114         "CA", // Canada
   1115         "AS", // American Samoa
   1116         "AI", // Anguilla
   1117         "AG", // Antigua and Barbuda
   1118         "BS", // Bahamas
   1119         "BB", // Barbados
   1120         "BM", // Bermuda
   1121         "VG", // British Virgin Islands
   1122         "KY", // Cayman Islands
   1123         "DM", // Dominica
   1124         "DO", // Dominican Republic
   1125         "GD", // Grenada
   1126         "GU", // Guam
   1127         "JM", // Jamaica
   1128         "PR", // Puerto Rico
   1129         "MS", // Montserrat
   1130         "MP", // Northern Mariana Islands
   1131         "KN", // Saint Kitts and Nevis
   1132         "LC", // Saint Lucia
   1133         "VC", // Saint Vincent and the Grenadines
   1134         "TT", // Trinidad and Tobago
   1135         "TC", // Turks and Caicos Islands
   1136         "VI", // U.S. Virgin Islands
   1137     };
   1138 
   1139     private static final String KOREA_ISO_COUNTRY_CODE = "KR";
   1140 
   1141     /**
   1142      * Breaks the given number down and formats it according to the rules
   1143      * for the country the number is from.
   1144      *
   1145      * @param source The phone number to format
   1146      * @return A locally acceptable formatting of the input, or the raw input if
   1147      *  formatting rules aren't known for the number
   1148      *
   1149      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
   1150      */
   1151     @Deprecated
   1152     public static String formatNumber(String source) {
   1153         SpannableStringBuilder text = new SpannableStringBuilder(source);
   1154         formatNumber(text, getFormatTypeForLocale(Locale.getDefault()));
   1155         return text.toString();
   1156     }
   1157 
   1158     /**
   1159      * Formats the given number with the given formatting type. Currently
   1160      * {@link #FORMAT_NANP} and {@link #FORMAT_JAPAN} are supported as a formating type.
   1161      *
   1162      * @param source the phone number to format
   1163      * @param defaultFormattingType The default formatting rules to apply if the number does
   1164      * not begin with +[country_code]
   1165      * @return The phone number formatted with the given formatting type.
   1166      *
   1167      * @hide
   1168      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
   1169      */
   1170     @Deprecated
   1171     public static String formatNumber(String source, int defaultFormattingType) {
   1172         SpannableStringBuilder text = new SpannableStringBuilder(source);
   1173         formatNumber(text, defaultFormattingType);
   1174         return text.toString();
   1175     }
   1176 
   1177     /**
   1178      * Returns the phone number formatting type for the given locale.
   1179      *
   1180      * @param locale The locale of interest, usually {@link Locale#getDefault()}
   1181      * @return The formatting type for the given locale, or FORMAT_UNKNOWN if the formatting
   1182      * rules are not known for the given locale
   1183      *
   1184      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
   1185      */
   1186     @Deprecated
   1187     public static int getFormatTypeForLocale(Locale locale) {
   1188         String country = locale.getCountry();
   1189 
   1190         return getFormatTypeFromCountryCode(country);
   1191     }
   1192 
   1193     /**
   1194      * Formats a phone number in-place. Currently {@link #FORMAT_JAPAN} and {@link #FORMAT_NANP}
   1195      * is supported as a second argument.
   1196      *
   1197      * @param text The number to be formatted, will be modified with the formatting
   1198      * @param defaultFormattingType The default formatting rules to apply if the number does
   1199      * not begin with +[country_code]
   1200      *
   1201      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
   1202      */
   1203     @Deprecated
   1204     public static void formatNumber(Editable text, int defaultFormattingType) {
   1205         int formatType = defaultFormattingType;
   1206 
   1207         if (text.length() > 2 && text.charAt(0) == '+') {
   1208             if (text.charAt(1) == '1') {
   1209                 formatType = FORMAT_NANP;
   1210             } else if (text.length() >= 3 && text.charAt(1) == '8'
   1211                 && text.charAt(2) == '1') {
   1212                 formatType = FORMAT_JAPAN;
   1213             } else {
   1214                 formatType = FORMAT_UNKNOWN;
   1215             }
   1216         }
   1217 
   1218         switch (formatType) {
   1219             case FORMAT_NANP:
   1220                 formatNanpNumber(text);
   1221                 return;
   1222             case FORMAT_JAPAN:
   1223                 formatJapaneseNumber(text);
   1224                 return;
   1225             case FORMAT_UNKNOWN:
   1226                 removeDashes(text);
   1227                 return;
   1228         }
   1229     }
   1230 
   1231     private static final int NANP_STATE_DIGIT = 1;
   1232     private static final int NANP_STATE_PLUS = 2;
   1233     private static final int NANP_STATE_ONE = 3;
   1234     private static final int NANP_STATE_DASH = 4;
   1235 
   1236     /**
   1237      * Formats a phone number in-place using the NANP formatting rules. Numbers will be formatted
   1238      * as:
   1239      *
   1240      * <p><code>
   1241      * xxxxx
   1242      * xxx-xxxx
   1243      * xxx-xxx-xxxx
   1244      * 1-xxx-xxx-xxxx
   1245      * +1-xxx-xxx-xxxx
   1246      * </code></p>
   1247      *
   1248      * @param text the number to be formatted, will be modified with the formatting
   1249      *
   1250      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
   1251      */
   1252     @Deprecated
   1253     public static void formatNanpNumber(Editable text) {
   1254         int length = text.length();
   1255         if (length > "+1-nnn-nnn-nnnn".length()) {
   1256             // The string is too long to be formatted
   1257             return;
   1258         } else if (length <= 5) {
   1259             // The string is either a shortcode or too short to be formatted
   1260             return;
   1261         }
   1262 
   1263         CharSequence saved = text.subSequence(0, length);
   1264 
   1265         // Strip the dashes first, as we're going to add them back
   1266         removeDashes(text);
   1267         length = text.length();
   1268 
   1269         // When scanning the number we record where dashes need to be added,
   1270         // if they're non-0 at the end of the scan the dashes will be added in
   1271         // the proper places.
   1272         int dashPositions[] = new int[3];
   1273         int numDashes = 0;
   1274 
   1275         int state = NANP_STATE_DIGIT;
   1276         int numDigits = 0;
   1277         for (int i = 0; i < length; i++) {
   1278             char c = text.charAt(i);
   1279             switch (c) {
   1280                 case '1':
   1281                     if (numDigits == 0 || state == NANP_STATE_PLUS) {
   1282                         state = NANP_STATE_ONE;
   1283                         break;
   1284                     }
   1285                     // fall through
   1286                 case '2':
   1287                 case '3':
   1288                 case '4':
   1289                 case '5':
   1290                 case '6':
   1291                 case '7':
   1292                 case '8':
   1293                 case '9':
   1294                 case '0':
   1295                     if (state == NANP_STATE_PLUS) {
   1296                         // Only NANP number supported for now
   1297                         text.replace(0, length, saved);
   1298                         return;
   1299                     } else if (state == NANP_STATE_ONE) {
   1300                         // Found either +1 or 1, follow it up with a dash
   1301                         dashPositions[numDashes++] = i;
   1302                     } else if (state != NANP_STATE_DASH && (numDigits == 3 || numDigits == 6)) {
   1303                         // Found a digit that should be after a dash that isn't
   1304                         dashPositions[numDashes++] = i;
   1305                     }
   1306                     state = NANP_STATE_DIGIT;
   1307                     numDigits++;
   1308                     break;
   1309 
   1310                 case '-':
   1311                     state = NANP_STATE_DASH;
   1312                     break;
   1313 
   1314                 case '+':
   1315                     if (i == 0) {
   1316                         // Plus is only allowed as the first character
   1317                         state = NANP_STATE_PLUS;
   1318                         break;
   1319                     }
   1320                     // Fall through
   1321                 default:
   1322                     // Unknown character, bail on formatting
   1323                     text.replace(0, length, saved);
   1324                     return;
   1325             }
   1326         }
   1327 
   1328         if (numDigits == 7) {
   1329             // With 7 digits we want xxx-xxxx, not xxx-xxx-x
   1330             numDashes--;
   1331         }
   1332 
   1333         // Actually put the dashes in place
   1334         for (int i = 0; i < numDashes; i++) {
   1335             int pos = dashPositions[i];
   1336             text.replace(pos + i, pos + i, "-");
   1337         }
   1338 
   1339         // Remove trailing dashes
   1340         int len = text.length();
   1341         while (len > 0) {
   1342             if (text.charAt(len - 1) == '-') {
   1343                 text.delete(len - 1, len);
   1344                 len--;
   1345             } else {
   1346                 break;
   1347             }
   1348         }
   1349     }
   1350 
   1351     /**
   1352      * Formats a phone number in-place using the Japanese formatting rules.
   1353      * Numbers will be formatted as:
   1354      *
   1355      * <p><code>
   1356      * 03-xxxx-xxxx
   1357      * 090-xxxx-xxxx
   1358      * 0120-xxx-xxx
   1359      * +81-3-xxxx-xxxx
   1360      * +81-90-xxxx-xxxx
   1361      * </code></p>
   1362      *
   1363      * @param text the number to be formatted, will be modified with
   1364      * the formatting
   1365      *
   1366      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
   1367      */
   1368     @Deprecated
   1369     public static void formatJapaneseNumber(Editable text) {
   1370         JapanesePhoneNumberFormatter.format(text);
   1371     }
   1372 
   1373     /**
   1374      * Removes all dashes from the number.
   1375      *
   1376      * @param text the number to clear from dashes
   1377      */
   1378     private static void removeDashes(Editable text) {
   1379         int p = 0;
   1380         while (p < text.length()) {
   1381             if (text.charAt(p) == '-') {
   1382                 text.delete(p, p + 1);
   1383            } else {
   1384                 p++;
   1385            }
   1386         }
   1387     }
   1388 
   1389     /**
   1390      * Formats the specified {@code phoneNumber} to the E.164 representation.
   1391      *
   1392      * @param phoneNumber the phone number to format.
   1393      * @param defaultCountryIso the ISO 3166-1 two letters country code.
   1394      * @return the E.164 representation, or null if the given phone number is not valid.
   1395      */
   1396     public static String formatNumberToE164(String phoneNumber, String defaultCountryIso) {
   1397         return formatNumberInternal(phoneNumber, defaultCountryIso, PhoneNumberFormat.E164);
   1398     }
   1399 
   1400     /**
   1401      * Formats the specified {@code phoneNumber} to the RFC3966 representation.
   1402      *
   1403      * @param phoneNumber the phone number to format.
   1404      * @param defaultCountryIso the ISO 3166-1 two letters country code.
   1405      * @return the RFC3966 representation, or null if the given phone number is not valid.
   1406      */
   1407     public static String formatNumberToRFC3966(String phoneNumber, String defaultCountryIso) {
   1408         return formatNumberInternal(phoneNumber, defaultCountryIso, PhoneNumberFormat.RFC3966);
   1409     }
   1410 
   1411     /**
   1412      * Formats the raw phone number (string) using the specified {@code formatIdentifier}.
   1413      * <p>
   1414      * The given phone number must have an area code and could have a country code.
   1415      * <p>
   1416      * The defaultCountryIso is used to validate the given number and generate the formatted number
   1417      * if the specified number doesn't have a country code.
   1418      *
   1419      * @param rawPhoneNumber The phone number to format.
   1420      * @param defaultCountryIso The ISO 3166-1 two letters country code.
   1421      * @param formatIdentifier The (enum) identifier of the desired format.
   1422      * @return the formatted representation, or null if the specified number is not valid.
   1423      */
   1424     private static String formatNumberInternal(
   1425             String rawPhoneNumber, String defaultCountryIso, PhoneNumberFormat formatIdentifier) {
   1426 
   1427         PhoneNumberUtil util = PhoneNumberUtil.getInstance();
   1428         try {
   1429             PhoneNumber phoneNumber = util.parse(rawPhoneNumber, defaultCountryIso);
   1430             if (util.isValidNumber(phoneNumber)) {
   1431                 return util.format(phoneNumber, formatIdentifier);
   1432             }
   1433         } catch (NumberParseException ignored) { }
   1434 
   1435         return null;
   1436     }
   1437 
   1438     /**
   1439      * Format a phone number.
   1440      * <p>
   1441      * If the given number doesn't have the country code, the phone will be
   1442      * formatted to the default country's convention.
   1443      *
   1444      * @param phoneNumber
   1445      *            the number to be formatted.
   1446      * @param defaultCountryIso
   1447      *            the ISO 3166-1 two letters country code whose convention will
   1448      *            be used if the given number doesn't have the country code.
   1449      * @return the formatted number, or null if the given number is not valid.
   1450      */
   1451     public static String formatNumber(String phoneNumber, String defaultCountryIso) {
   1452         // Do not attempt to format numbers that start with a hash or star symbol.
   1453         if (phoneNumber.startsWith("#") || phoneNumber.startsWith("*")) {
   1454             return phoneNumber;
   1455         }
   1456 
   1457         PhoneNumberUtil util = PhoneNumberUtil.getInstance();
   1458         String result = null;
   1459         try {
   1460             PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
   1461             /**
   1462              * Need to reformat any local Korean phone numbers (when the user is in Korea) with
   1463              * country code to corresponding national format which would replace the leading
   1464              * +82 with 0.
   1465              */
   1466             if (KOREA_ISO_COUNTRY_CODE.equals(defaultCountryIso) &&
   1467                     (pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE)) &&
   1468                     (pn.getCountryCodeSource() ==
   1469                             PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
   1470                 result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
   1471             } else {
   1472                 result = util.formatInOriginalFormat(pn, defaultCountryIso);
   1473             }
   1474         } catch (NumberParseException e) {
   1475         }
   1476         return result;
   1477     }
   1478 
   1479     /**
   1480      * Format the phone number only if the given number hasn't been formatted.
   1481      * <p>
   1482      * The number which has only dailable character is treated as not being
   1483      * formatted.
   1484      *
   1485      * @param phoneNumber
   1486      *            the number to be formatted.
   1487      * @param phoneNumberE164
   1488      *            the E164 format number whose country code is used if the given
   1489      *            phoneNumber doesn't have the country code.
   1490      * @param defaultCountryIso
   1491      *            the ISO 3166-1 two letters country code whose convention will
   1492      *            be used if the phoneNumberE164 is null or invalid, or if phoneNumber
   1493      *            contains IDD.
   1494      * @return the formatted number if the given number has been formatted,
   1495      *            otherwise, return the given number.
   1496      */
   1497     public static String formatNumber(
   1498             String phoneNumber, String phoneNumberE164, String defaultCountryIso) {
   1499         int len = phoneNumber.length();
   1500         for (int i = 0; i < len; i++) {
   1501             if (!isDialable(phoneNumber.charAt(i))) {
   1502                 return phoneNumber;
   1503             }
   1504         }
   1505         PhoneNumberUtil util = PhoneNumberUtil.getInstance();
   1506         // Get the country code from phoneNumberE164
   1507         if (phoneNumberE164 != null && phoneNumberE164.length() >= 2
   1508                 && phoneNumberE164.charAt(0) == '+') {
   1509             try {
   1510                 // The number to be parsed is in E164 format, so the default region used doesn't
   1511                 // matter.
   1512                 PhoneNumber pn = util.parse(phoneNumberE164, "ZZ");
   1513                 String regionCode = util.getRegionCodeForNumber(pn);
   1514                 if (!TextUtils.isEmpty(regionCode) &&
   1515                     // This makes sure phoneNumber doesn't contain an IDD
   1516                     normalizeNumber(phoneNumber).indexOf(phoneNumberE164.substring(1)) <= 0) {
   1517                     defaultCountryIso = regionCode;
   1518                 }
   1519             } catch (NumberParseException e) {
   1520             }
   1521         }
   1522         String result = formatNumber(phoneNumber, defaultCountryIso);
   1523         return result != null ? result : phoneNumber;
   1524     }
   1525 
   1526     /**
   1527      * Normalize a phone number by removing the characters other than digits. If
   1528      * the given number has keypad letters, the letters will be converted to
   1529      * digits first.
   1530      *
   1531      * @param phoneNumber the number to be normalized.
   1532      * @return the normalized number.
   1533      */
   1534     public static String normalizeNumber(String phoneNumber) {
   1535         if (TextUtils.isEmpty(phoneNumber)) {
   1536             return "";
   1537         }
   1538 
   1539         StringBuilder sb = new StringBuilder();
   1540         int len = phoneNumber.length();
   1541         for (int i = 0; i < len; i++) {
   1542             char c = phoneNumber.charAt(i);
   1543             // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
   1544             int digit = Character.digit(c, 10);
   1545             if (digit != -1) {
   1546                 sb.append(digit);
   1547             } else if (sb.length() == 0 && c == '+') {
   1548                 sb.append(c);
   1549             } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
   1550                 return normalizeNumber(PhoneNumberUtils.convertKeypadLettersToDigits(phoneNumber));
   1551             }
   1552         }
   1553         return sb.toString();
   1554     }
   1555 
   1556     /**
   1557      * Replaces all unicode(e.g. Arabic, Persian) digits with their decimal digit equivalents.
   1558      *
   1559      * @param number the number to perform the replacement on.
   1560      * @return the replaced number.
   1561      */
   1562     public static String replaceUnicodeDigits(String number) {
   1563         StringBuilder normalizedDigits = new StringBuilder(number.length());
   1564         for (char c : number.toCharArray()) {
   1565             int digit = Character.digit(c, 10);
   1566             if (digit != -1) {
   1567                 normalizedDigits.append(digit);
   1568             } else {
   1569                 normalizedDigits.append(c);
   1570             }
   1571         }
   1572         return normalizedDigits.toString();
   1573     }
   1574 
   1575     // Three and four digit phone numbers for either special services,
   1576     // or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should
   1577     // not match.
   1578     //
   1579     // This constant used to be 5, but SMS short codes has increased in length and
   1580     // can be easily 6 digits now days. Most countries have SMS short code length between
   1581     // 3 to 6 digits. The exceptions are
   1582     //
   1583     // Australia: Short codes are six or eight digits in length, starting with the prefix "19"
   1584     //            followed by an additional four or six digits and two.
   1585     // Czech Republic: Codes are seven digits in length for MO and five (not billed) or
   1586     //            eight (billed) for MT direction
   1587     //
   1588     // see http://en.wikipedia.org/wiki/Short_code#Regional_differences for reference
   1589     //
   1590     // However, in order to loose match 650-555-1212 and 555-1212, we need to set the min match
   1591     // to 7.
   1592     static final int MIN_MATCH = 7;
   1593 
   1594     /**
   1595      * Checks a given number against the list of
   1596      * emergency numbers provided by the RIL and SIM card.
   1597      *
   1598      * @param number the number to look up.
   1599      * @return true if the number is in the list of emergency numbers
   1600      *         listed in the RIL / SIM, otherwise return false.
   1601      */
   1602     public static boolean isEmergencyNumber(String number) {
   1603         return isEmergencyNumber(getDefaultVoiceSubId(), number);
   1604     }
   1605 
   1606     /**
   1607      * Checks a given number against the list of
   1608      * emergency numbers provided by the RIL and SIM card.
   1609      *
   1610      * @param subId the subscription id of the SIM.
   1611      * @param number the number to look up.
   1612      * @return true if the number is in the list of emergency numbers
   1613      *         listed in the RIL / SIM, otherwise return false.
   1614      * @hide
   1615      */
   1616     public static boolean isEmergencyNumber(int subId, String number) {
   1617         // Return true only if the specified number *exactly* matches
   1618         // one of the emergency numbers listed by the RIL / SIM.
   1619         return isEmergencyNumberInternal(subId, number, true /* useExactMatch */);
   1620     }
   1621 
   1622     /**
   1623      * Checks if given number might *potentially* result in
   1624      * a call to an emergency service on the current network.
   1625      *
   1626      * Specifically, this method will return true if the specified number
   1627      * is an emergency number according to the list managed by the RIL or
   1628      * SIM, *or* if the specified number simply starts with the same
   1629      * digits as any of the emergency numbers listed in the RIL / SIM.
   1630      *
   1631      * This method is intended for internal use by the phone app when
   1632      * deciding whether to allow ACTION_CALL intents from 3rd party apps
   1633      * (where we're required to *not* allow emergency calls to be placed.)
   1634      *
   1635      * @param number the number to look up.
   1636      * @return true if the number is in the list of emergency numbers
   1637      *         listed in the RIL / SIM, *or* if the number starts with the
   1638      *         same digits as any of those emergency numbers.
   1639      *
   1640      * @hide
   1641      */
   1642     public static boolean isPotentialEmergencyNumber(String number) {
   1643         return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number);
   1644     }
   1645 
   1646     /**
   1647      * Checks if given number might *potentially* result in
   1648      * a call to an emergency service on the current network.
   1649      *
   1650      * Specifically, this method will return true if the specified number
   1651      * is an emergency number according to the list managed by the RIL or
   1652      * SIM, *or* if the specified number simply starts with the same
   1653      * digits as any of the emergency numbers listed in the RIL / SIM.
   1654      *
   1655      * This method is intended for internal use by the phone app when
   1656      * deciding whether to allow ACTION_CALL intents from 3rd party apps
   1657      * (where we're required to *not* allow emergency calls to be placed.)
   1658      *
   1659      * @param subId the subscription id of the SIM.
   1660      * @param number the number to look up.
   1661      * @return true if the number is in the list of emergency numbers
   1662      *         listed in the RIL / SIM, *or* if the number starts with the
   1663      *         same digits as any of those emergency numbers.
   1664      * @hide
   1665      */
   1666     public static boolean isPotentialEmergencyNumber(int subId, String number) {
   1667         // Check against the emergency numbers listed by the RIL / SIM,
   1668         // and *don't* require an exact match.
   1669         return isEmergencyNumberInternal(subId, number, false /* useExactMatch */);
   1670     }
   1671 
   1672     /**
   1673      * Helper function for isEmergencyNumber(String) and
   1674      * isPotentialEmergencyNumber(String).
   1675      *
   1676      * @param number the number to look up.
   1677      *
   1678      * @param useExactMatch if true, consider a number to be an emergency
   1679      *           number only if it *exactly* matches a number listed in
   1680      *           the RIL / SIM.  If false, a number is considered to be an
   1681      *           emergency number if it simply starts with the same digits
   1682      *           as any of the emergency numbers listed in the RIL / SIM.
   1683      *           (Setting useExactMatch to false allows you to identify
   1684      *           number that could *potentially* result in emergency calls
   1685      *           since many networks will actually ignore trailing digits
   1686      *           after a valid emergency number.)
   1687      *
   1688      * @return true if the number is in the list of emergency numbers
   1689      *         listed in the RIL / sim, otherwise return false.
   1690      */
   1691     private static boolean isEmergencyNumberInternal(String number, boolean useExactMatch) {
   1692         return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, useExactMatch);
   1693     }
   1694 
   1695     /**
   1696      * Helper function for isEmergencyNumber(String) and
   1697      * isPotentialEmergencyNumber(String).
   1698      *
   1699      * @param subId the subscription id of the SIM.
   1700      * @param number the number to look up.
   1701      *
   1702      * @param useExactMatch if true, consider a number to be an emergency
   1703      *           number only if it *exactly* matches a number listed in
   1704      *           the RIL / SIM.  If false, a number is considered to be an
   1705      *           emergency number if it simply starts with the same digits
   1706      *           as any of the emergency numbers listed in the RIL / SIM.
   1707      *           (Setting useExactMatch to false allows you to identify
   1708      *           number that could *potentially* result in emergency calls
   1709      *           since many networks will actually ignore trailing digits
   1710      *           after a valid emergency number.)
   1711      *
   1712      * @return true if the number is in the list of emergency numbers
   1713      *         listed in the RIL / sim, otherwise return false.
   1714      */
   1715     private static boolean isEmergencyNumberInternal(int subId, String number,
   1716             boolean useExactMatch) {
   1717         return isEmergencyNumberInternal(subId, number, null, useExactMatch);
   1718     }
   1719 
   1720     /**
   1721      * Checks if a given number is an emergency number for a specific country.
   1722      *
   1723      * @param number the number to look up.
   1724      * @param defaultCountryIso the specific country which the number should be checked against
   1725      * @return if the number is an emergency number for the specific country, then return true,
   1726      * otherwise false
   1727      *
   1728      * @hide
   1729      */
   1730     public static boolean isEmergencyNumber(String number, String defaultCountryIso) {
   1731             return isEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
   1732     }
   1733 
   1734     /**
   1735      * Checks if a given number is an emergency number for a specific country.
   1736      *
   1737      * @param subId the subscription id of the SIM.
   1738      * @param number the number to look up.
   1739      * @param defaultCountryIso the specific country which the number should be checked against
   1740      * @return if the number is an emergency number for the specific country, then return true,
   1741      * otherwise false
   1742      * @hide
   1743      */
   1744     public static boolean isEmergencyNumber(int subId, String number, String defaultCountryIso) {
   1745         return isEmergencyNumberInternal(subId, number,
   1746                                          defaultCountryIso,
   1747                                          true /* useExactMatch */);
   1748     }
   1749 
   1750     /**
   1751      * Checks if a given number might *potentially* result in a call to an
   1752      * emergency service, for a specific country.
   1753      *
   1754      * Specifically, this method will return true if the specified number
   1755      * is an emergency number in the specified country, *or* if the number
   1756      * simply starts with the same digits as any emergency number for that
   1757      * country.
   1758      *
   1759      * This method is intended for internal use by the phone app when
   1760      * deciding whether to allow ACTION_CALL intents from 3rd party apps
   1761      * (where we're required to *not* allow emergency calls to be placed.)
   1762      *
   1763      * @param number the number to look up.
   1764      * @param defaultCountryIso the specific country which the number should be checked against
   1765      * @return true if the number is an emergency number for the specific
   1766      *         country, *or* if the number starts with the same digits as
   1767      *         any of those emergency numbers.
   1768      *
   1769      * @hide
   1770      */
   1771     public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) {
   1772         return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
   1773     }
   1774 
   1775     /**
   1776      * Checks if a given number might *potentially* result in a call to an
   1777      * emergency service, for a specific country.
   1778      *
   1779      * Specifically, this method will return true if the specified number
   1780      * is an emergency number in the specified country, *or* if the number
   1781      * simply starts with the same digits as any emergency number for that
   1782      * country.
   1783      *
   1784      * This method is intended for internal use by the phone app when
   1785      * deciding whether to allow ACTION_CALL intents from 3rd party apps
   1786      * (where we're required to *not* allow emergency calls to be placed.)
   1787      *
   1788      * @param subId the subscription id of the SIM.
   1789      * @param number the number to look up.
   1790      * @param defaultCountryIso the specific country which the number should be checked against
   1791      * @return true if the number is an emergency number for the specific
   1792      *         country, *or* if the number starts with the same digits as
   1793      *         any of those emergency numbers.
   1794      * @hide
   1795      */
   1796     public static boolean isPotentialEmergencyNumber(int subId, String number,
   1797             String defaultCountryIso) {
   1798         return isEmergencyNumberInternal(subId, number,
   1799                                          defaultCountryIso,
   1800                                          false /* useExactMatch */);
   1801     }
   1802 
   1803     /**
   1804      * Helper function for isEmergencyNumber(String, String) and
   1805      * isPotentialEmergencyNumber(String, String).
   1806      *
   1807      * @param number the number to look up.
   1808      * @param defaultCountryIso the specific country which the number should be checked against
   1809      * @param useExactMatch if true, consider a number to be an emergency
   1810      *           number only if it *exactly* matches a number listed in
   1811      *           the RIL / SIM.  If false, a number is considered to be an
   1812      *           emergency number if it simply starts with the same digits
   1813      *           as any of the emergency numbers listed in the RIL / SIM.
   1814      *
   1815      * @return true if the number is an emergency number for the specified country.
   1816      */
   1817     private static boolean isEmergencyNumberInternal(String number,
   1818                                                      String defaultCountryIso,
   1819                                                      boolean useExactMatch) {
   1820         return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, defaultCountryIso,
   1821                 useExactMatch);
   1822     }
   1823 
   1824     /**
   1825      * Helper function for isEmergencyNumber(String, String) and
   1826      * isPotentialEmergencyNumber(String, String).
   1827      *
   1828      * @param subId the subscription id of the SIM.
   1829      * @param number the number to look up.
   1830      * @param defaultCountryIso the specific country which the number should be checked against
   1831      * @param useExactMatch if true, consider a number to be an emergency
   1832      *           number only if it *exactly* matches a number listed in
   1833      *           the RIL / SIM.  If false, a number is considered to be an
   1834      *           emergency number if it simply starts with the same digits
   1835      *           as any of the emergency numbers listed in the RIL / SIM.
   1836      *
   1837      * @return true if the number is an emergency number for the specified country.
   1838      * @hide
   1839      */
   1840     private static boolean isEmergencyNumberInternal(int subId, String number,
   1841                                                      String defaultCountryIso,
   1842                                                      boolean useExactMatch) {
   1843         // If the number passed in is null, just return false:
   1844         if (number == null) return false;
   1845 
   1846         // If the number passed in is a SIP address, return false, since the
   1847         // concept of "emergency numbers" is only meaningful for calls placed
   1848         // over the cell network.
   1849         // (Be sure to do this check *before* calling extractNetworkPortionAlt(),
   1850         // since the whole point of extractNetworkPortionAlt() is to filter out
   1851         // any non-dialable characters (which would turn 'abc911def (at) example.com'
   1852         // into '911', for example.))
   1853         if (isUriNumber(number)) {
   1854             return false;
   1855         }
   1856 
   1857         // Strip the separators from the number before comparing it
   1858         // to the list.
   1859         number = extractNetworkPortionAlt(number);
   1860 
   1861         String emergencyNumbers = "";
   1862         int slotId = SubscriptionManager.getSlotId(subId);
   1863 
   1864         // retrieve the list of emergency numbers
   1865         // check read-write ecclist property first
   1866         String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId);
   1867 
   1868         emergencyNumbers = SystemProperties.get(ecclist, "");
   1869 
   1870         Rlog.d(LOG_TAG, "slotId:" + slotId + " subId:" + subId + " country:"
   1871                 + defaultCountryIso + " emergencyNumbers: " +  emergencyNumbers);
   1872 
   1873         if (TextUtils.isEmpty(emergencyNumbers)) {
   1874             // then read-only ecclist property since old RIL only uses this
   1875             emergencyNumbers = SystemProperties.get("ro.ril.ecclist");
   1876         }
   1877 
   1878         if (!TextUtils.isEmpty(emergencyNumbers)) {
   1879             // searches through the comma-separated list for a match,
   1880             // return true if one is found.
   1881             for (String emergencyNum : emergencyNumbers.split(",")) {
   1882                 // It is not possible to append additional digits to an emergency number to dial
   1883                 // the number in Brazil - it won't connect.
   1884                 if (useExactMatch || "BR".equalsIgnoreCase(defaultCountryIso)) {
   1885                     if (number.equals(emergencyNum)) {
   1886                         return true;
   1887                     }
   1888                 } else {
   1889                     if (number.startsWith(emergencyNum)) {
   1890                         return true;
   1891                     }
   1892                 }
   1893             }
   1894             // no matches found against the list!
   1895             return false;
   1896         }
   1897 
   1898         Rlog.d(LOG_TAG, "System property doesn't provide any emergency numbers."
   1899                 + " Use embedded logic for determining ones.");
   1900 
   1901         // If slot id is invalid, means that there is no sim card.
   1902         // According spec 3GPP TS22.101, the following numbers should be
   1903         // ECC numbers when SIM/USIM is not present.
   1904         emergencyNumbers = ((slotId < 0) ? "112,911,000,08,110,118,119,999" : "112,911");
   1905 
   1906         for (String emergencyNum : emergencyNumbers.split(",")) {
   1907             if (useExactMatch) {
   1908                 if (number.equals(emergencyNum)) {
   1909                     return true;
   1910                 }
   1911             } else {
   1912                 if (number.startsWith(emergencyNum)) {
   1913                     return true;
   1914                 }
   1915             }
   1916         }
   1917 
   1918         // No ecclist system property, so use our own list.
   1919         if (defaultCountryIso != null) {
   1920             ShortNumberUtil util = new ShortNumberUtil();
   1921             if (useExactMatch) {
   1922                 return util.isEmergencyNumber(number, defaultCountryIso);
   1923             } else {
   1924                 return util.connectsToEmergencyNumber(number, defaultCountryIso);
   1925             }
   1926         }
   1927 
   1928         return false;
   1929     }
   1930 
   1931     /**
   1932      * Checks if a given number is an emergency number for the country that the user is in.
   1933      *
   1934      * @param number the number to look up.
   1935      * @param context the specific context which the number should be checked against
   1936      * @return true if the specified number is an emergency number for the country the user
   1937      * is currently in.
   1938      */
   1939     public static boolean isLocalEmergencyNumber(Context context, String number) {
   1940         return isLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
   1941     }
   1942 
   1943     /**
   1944      * Checks if a given number is an emergency number for the country that the user is in.
   1945      *
   1946      * @param subId the subscription id of the SIM.
   1947      * @param number the number to look up.
   1948      * @param context the specific context which the number should be checked against
   1949      * @return true if the specified number is an emergency number for the country the user
   1950      * is currently in.
   1951      * @hide
   1952      */
   1953     public static boolean isLocalEmergencyNumber(Context context, int subId, String number) {
   1954         return isLocalEmergencyNumberInternal(subId, number,
   1955                                               context,
   1956                                               true /* useExactMatch */);
   1957     }
   1958 
   1959     /**
   1960      * Checks if a given number might *potentially* result in a call to an
   1961      * emergency service, for the country that the user is in. The current
   1962      * country is determined using the CountryDetector.
   1963      *
   1964      * Specifically, this method will return true if the specified number
   1965      * is an emergency number in the current country, *or* if the number
   1966      * simply starts with the same digits as any emergency number for the
   1967      * current country.
   1968      *
   1969      * This method is intended for internal use by the phone app when
   1970      * deciding whether to allow ACTION_CALL intents from 3rd party apps
   1971      * (where we're required to *not* allow emergency calls to be placed.)
   1972      *
   1973      * @param number the number to look up.
   1974      * @param context the specific context which the number should be checked against
   1975      * @return true if the specified number is an emergency number for a local country, based on the
   1976      *              CountryDetector.
   1977      *
   1978      * @see android.location.CountryDetector
   1979      * @hide
   1980      */
   1981     public static boolean isPotentialLocalEmergencyNumber(Context context, String number) {
   1982         return isPotentialLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
   1983     }
   1984 
   1985     /**
   1986      * Checks if a given number might *potentially* result in a call to an
   1987      * emergency service, for the country that the user is in. The current
   1988      * country is determined using the CountryDetector.
   1989      *
   1990      * Specifically, this method will return true if the specified number
   1991      * is an emergency number in the current country, *or* if the number
   1992      * simply starts with the same digits as any emergency number for the
   1993      * current country.
   1994      *
   1995      * This method is intended for internal use by the phone app when
   1996      * deciding whether to allow ACTION_CALL intents from 3rd party apps
   1997      * (where we're required to *not* allow emergency calls to be placed.)
   1998      *
   1999      * @param subId the subscription id of the SIM.
   2000      * @param number the number to look up.
   2001      * @param context the specific context which the number should be checked against
   2002      * @return true if the specified number is an emergency number for a local country, based on the
   2003      *              CountryDetector.
   2004      *
   2005      * @hide
   2006      */
   2007     public static boolean isPotentialLocalEmergencyNumber(Context context, int subId,
   2008             String number) {
   2009         return isLocalEmergencyNumberInternal(subId, number,
   2010                                               context,
   2011                                               false /* useExactMatch */);
   2012     }
   2013 
   2014     /**
   2015      * Helper function for isLocalEmergencyNumber() and
   2016      * isPotentialLocalEmergencyNumber().
   2017      *
   2018      * @param number the number to look up.
   2019      * @param context the specific context which the number should be checked against
   2020      * @param useExactMatch if true, consider a number to be an emergency
   2021      *           number only if it *exactly* matches a number listed in
   2022      *           the RIL / SIM.  If false, a number is considered to be an
   2023      *           emergency number if it simply starts with the same digits
   2024      *           as any of the emergency numbers listed in the RIL / SIM.
   2025      *
   2026      * @return true if the specified number is an emergency number for a
   2027      *              local country, based on the CountryDetector.
   2028      *
   2029      * @see android.location.CountryDetector
   2030      * @hide
   2031      */
   2032     private static boolean isLocalEmergencyNumberInternal(String number,
   2033                                                           Context context,
   2034                                                           boolean useExactMatch) {
   2035         return isLocalEmergencyNumberInternal(getDefaultVoiceSubId(), number, context,
   2036                 useExactMatch);
   2037     }
   2038 
   2039     /**
   2040      * Helper function for isLocalEmergencyNumber() and
   2041      * isPotentialLocalEmergencyNumber().
   2042      *
   2043      * @param subId the subscription id of the SIM.
   2044      * @param number the number to look up.
   2045      * @param context the specific context which the number should be checked against
   2046      * @param useExactMatch if true, consider a number to be an emergency
   2047      *           number only if it *exactly* matches a number listed in
   2048      *           the RIL / SIM.  If false, a number is considered to be an
   2049      *           emergency number if it simply starts with the same digits
   2050      *           as any of the emergency numbers listed in the RIL / SIM.
   2051      *
   2052      * @return true if the specified number is an emergency number for a
   2053      *              local country, based on the CountryDetector.
   2054      * @hide
   2055      */
   2056     private static boolean isLocalEmergencyNumberInternal(int subId, String number,
   2057                                                           Context context,
   2058                                                           boolean useExactMatch) {
   2059         String countryIso;
   2060         CountryDetector detector = (CountryDetector) context.getSystemService(
   2061                 Context.COUNTRY_DETECTOR);
   2062         if (detector != null && detector.detectCountry() != null) {
   2063             countryIso = detector.detectCountry().getCountryIso();
   2064         } else {
   2065             Locale locale = context.getResources().getConfiguration().locale;
   2066             countryIso = locale.getCountry();
   2067             Rlog.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
   2068                     + countryIso);
   2069         }
   2070         return isEmergencyNumberInternal(subId, number, countryIso, useExactMatch);
   2071     }
   2072 
   2073     /**
   2074      * isVoiceMailNumber: checks a given number against the voicemail
   2075      *   number provided by the RIL and SIM card. The caller must have
   2076      *   the READ_PHONE_STATE credential.
   2077      *
   2078      * @param number the number to look up.
   2079      * @return true if the number is in the list of voicemail. False
   2080      * otherwise, including if the caller does not have the permission
   2081      * to read the VM number.
   2082      */
   2083     public static boolean isVoiceMailNumber(String number) {
   2084         return isVoiceMailNumber(SubscriptionManager.getDefaultSubscriptionId(), number);
   2085     }
   2086 
   2087     /**
   2088      * isVoiceMailNumber: checks a given number against the voicemail
   2089      *   number provided by the RIL and SIM card. The caller must have
   2090      *   the READ_PHONE_STATE credential.
   2091      *
   2092      * @param subId the subscription id of the SIM.
   2093      * @param number the number to look up.
   2094      * @return true if the number is in the list of voicemail. False
   2095      * otherwise, including if the caller does not have the permission
   2096      * to read the VM number.
   2097      * @hide
   2098      */
   2099     public static boolean isVoiceMailNumber(int subId, String number) {
   2100         return isVoiceMailNumber(null, subId, number);
   2101     }
   2102 
   2103     /**
   2104      * isVoiceMailNumber: checks a given number against the voicemail
   2105      *   number provided by the RIL and SIM card. The caller must have
   2106      *   the READ_PHONE_STATE credential.
   2107      *
   2108      * @param context a non-null {@link Context}.
   2109      * @param subId the subscription id of the SIM.
   2110      * @param number the number to look up.
   2111      * @return true if the number is in the list of voicemail. False
   2112      * otherwise, including if the caller does not have the permission
   2113      * to read the VM number.
   2114      * @hide
   2115      */
   2116     public static boolean isVoiceMailNumber(Context context, int subId, String number) {
   2117         String vmNumber;
   2118         try {
   2119             final TelephonyManager tm;
   2120             if (context == null) {
   2121                 tm = TelephonyManager.getDefault();
   2122             } else {
   2123                 tm = TelephonyManager.from(context);
   2124             }
   2125             vmNumber = tm.getVoiceMailNumber(subId);
   2126         } catch (SecurityException ex) {
   2127             return false;
   2128         }
   2129         // Strip the separators from the number before comparing it
   2130         // to the list.
   2131         number = extractNetworkPortionAlt(number);
   2132 
   2133         // compare tolerates null so we need to make sure that we
   2134         // don't return true when both are null.
   2135         return !TextUtils.isEmpty(number) && compare(number, vmNumber);
   2136     }
   2137 
   2138     /**
   2139      * Translates any alphabetic letters (i.e. [A-Za-z]) in the
   2140      * specified phone number into the equivalent numeric digits,
   2141      * according to the phone keypad letter mapping described in
   2142      * ITU E.161 and ISO/IEC 9995-8.
   2143      *
   2144      * @return the input string, with alpha letters converted to numeric
   2145      *         digits using the phone keypad letter mapping.  For example,
   2146      *         an input of "1-800-GOOG-411" will return "1-800-4664-411".
   2147      */
   2148     public static String convertKeypadLettersToDigits(String input) {
   2149         if (input == null) {
   2150             return input;
   2151         }
   2152         int len = input.length();
   2153         if (len == 0) {
   2154             return input;
   2155         }
   2156 
   2157         char[] out = input.toCharArray();
   2158 
   2159         for (int i = 0; i < len; i++) {
   2160             char c = out[i];
   2161             // If this char isn't in KEYPAD_MAP at all, just leave it alone.
   2162             out[i] = (char) KEYPAD_MAP.get(c, c);
   2163         }
   2164 
   2165         return new String(out);
   2166     }
   2167 
   2168     /**
   2169      * The phone keypad letter mapping (see ITU E.161 or ISO/IEC 9995-8.)
   2170      * TODO: This should come from a resource.
   2171      */
   2172     private static final SparseIntArray KEYPAD_MAP = new SparseIntArray();
   2173     static {
   2174         KEYPAD_MAP.put('a', '2'); KEYPAD_MAP.put('b', '2'); KEYPAD_MAP.put('c', '2');
   2175         KEYPAD_MAP.put('A', '2'); KEYPAD_MAP.put('B', '2'); KEYPAD_MAP.put('C', '2');
   2176 
   2177         KEYPAD_MAP.put('d', '3'); KEYPAD_MAP.put('e', '3'); KEYPAD_MAP.put('f', '3');
   2178         KEYPAD_MAP.put('D', '3'); KEYPAD_MAP.put('E', '3'); KEYPAD_MAP.put('F', '3');
   2179 
   2180         KEYPAD_MAP.put('g', '4'); KEYPAD_MAP.put('h', '4'); KEYPAD_MAP.put('i', '4');
   2181         KEYPAD_MAP.put('G', '4'); KEYPAD_MAP.put('H', '4'); KEYPAD_MAP.put('I', '4');
   2182 
   2183         KEYPAD_MAP.put('j', '5'); KEYPAD_MAP.put('k', '5'); KEYPAD_MAP.put('l', '5');
   2184         KEYPAD_MAP.put('J', '5'); KEYPAD_MAP.put('K', '5'); KEYPAD_MAP.put('L', '5');
   2185 
   2186         KEYPAD_MAP.put('m', '6'); KEYPAD_MAP.put('n', '6'); KEYPAD_MAP.put('o', '6');
   2187         KEYPAD_MAP.put('M', '6'); KEYPAD_MAP.put('N', '6'); KEYPAD_MAP.put('O', '6');
   2188 
   2189         KEYPAD_MAP.put('p', '7'); KEYPAD_MAP.put('q', '7'); KEYPAD_MAP.put('r', '7'); KEYPAD_MAP.put('s', '7');
   2190         KEYPAD_MAP.put('P', '7'); KEYPAD_MAP.put('Q', '7'); KEYPAD_MAP.put('R', '7'); KEYPAD_MAP.put('S', '7');
   2191 
   2192         KEYPAD_MAP.put('t', '8'); KEYPAD_MAP.put('u', '8'); KEYPAD_MAP.put('v', '8');
   2193         KEYPAD_MAP.put('T', '8'); KEYPAD_MAP.put('U', '8'); KEYPAD_MAP.put('V', '8');
   2194 
   2195         KEYPAD_MAP.put('w', '9'); KEYPAD_MAP.put('x', '9'); KEYPAD_MAP.put('y', '9'); KEYPAD_MAP.put('z', '9');
   2196         KEYPAD_MAP.put('W', '9'); KEYPAD_MAP.put('X', '9'); KEYPAD_MAP.put('Y', '9'); KEYPAD_MAP.put('Z', '9');
   2197     }
   2198 
   2199     //================ Plus Code formatting =========================
   2200     private static final char PLUS_SIGN_CHAR = '+';
   2201     private static final String PLUS_SIGN_STRING = "+";
   2202     private static final String NANP_IDP_STRING = "011";
   2203     private static final int NANP_LENGTH = 10;
   2204 
   2205     /**
   2206      * This function checks if there is a plus sign (+) in the passed-in dialing number.
   2207      * If there is, it processes the plus sign based on the default telephone
   2208      * numbering plan of the system when the phone is activated and the current
   2209      * telephone numbering plan of the system that the phone is camped on.
   2210      * Currently, we only support the case that the default and current telephone
   2211      * numbering plans are North American Numbering Plan(NANP).
   2212      *
   2213      * The passed-in dialStr should only contain the valid format as described below,
   2214      * 1) the 1st character in the dialStr should be one of the really dialable
   2215      *    characters listed below
   2216      *    ISO-LATIN characters 0-9, *, # , +
   2217      * 2) the dialStr should already strip out the separator characters,
   2218      *    every character in the dialStr should be one of the non separator characters
   2219      *    listed below
   2220      *    ISO-LATIN characters 0-9, *, # , +, WILD, WAIT, PAUSE
   2221      *
   2222      * Otherwise, this function returns the dial string passed in
   2223      *
   2224      * @param dialStr the original dial string
   2225      * @return the converted dial string if the current/default countries belong to NANP,
   2226      * and if there is the "+" in the original dial string. Otherwise, the original dial
   2227      * string returns.
   2228      *
   2229      * This API is for CDMA only
   2230      *
   2231      * @hide TODO: pending API Council approval
   2232      */
   2233     public static String cdmaCheckAndProcessPlusCode(String dialStr) {
   2234         if (!TextUtils.isEmpty(dialStr)) {
   2235             if (isReallyDialable(dialStr.charAt(0)) &&
   2236                 isNonSeparator(dialStr)) {
   2237                 String currIso = TelephonyManager.getDefault().getNetworkCountryIso();
   2238                 String defaultIso = TelephonyManager.getDefault().getSimCountryIso();
   2239                 if (!TextUtils.isEmpty(currIso) && !TextUtils.isEmpty(defaultIso)) {
   2240                     return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr,
   2241                             getFormatTypeFromCountryCode(currIso),
   2242                             getFormatTypeFromCountryCode(defaultIso));
   2243                 }
   2244             }
   2245         }
   2246         return dialStr;
   2247     }
   2248 
   2249     /**
   2250      * Process phone number for CDMA, converting plus code using the home network number format.
   2251      * This is used for outgoing SMS messages.
   2252      *
   2253      * @param dialStr the original dial string
   2254      * @return the converted dial string
   2255      * @hide for internal use
   2256      */
   2257     public static String cdmaCheckAndProcessPlusCodeForSms(String dialStr) {
   2258         if (!TextUtils.isEmpty(dialStr)) {
   2259             if (isReallyDialable(dialStr.charAt(0)) && isNonSeparator(dialStr)) {
   2260                 String defaultIso = TelephonyManager.getDefault().getSimCountryIso();
   2261                 if (!TextUtils.isEmpty(defaultIso)) {
   2262                     int format = getFormatTypeFromCountryCode(defaultIso);
   2263                     return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr, format, format);
   2264                 }
   2265             }
   2266         }
   2267         return dialStr;
   2268     }
   2269 
   2270     /**
   2271      * This function should be called from checkAndProcessPlusCode only
   2272      * And it is used for test purpose also.
   2273      *
   2274      * It checks the dial string by looping through the network portion,
   2275      * post dial portion 1, post dial porting 2, etc. If there is any
   2276      * plus sign, then process the plus sign.
   2277      * Currently, this function supports the plus sign conversion within NANP only.
   2278      * Specifically, it handles the plus sign in the following ways:
   2279      * 1)+1NANP,remove +, e.g.
   2280      *   +18475797000 is converted to 18475797000,
   2281      * 2)+NANP or +non-NANP Numbers,replace + with the current NANP IDP, e.g,
   2282      *   +8475797000 is converted to 0118475797000,
   2283      *   +11875767800 is converted to 01111875767800
   2284      * 3)+1NANP in post dial string(s), e.g.
   2285      *   8475797000;+18475231753 is converted to 8475797000;18475231753
   2286      *
   2287      *
   2288      * @param dialStr the original dial string
   2289      * @param currFormat the numbering system of the current country that the phone is camped on
   2290      * @param defaultFormat the numbering system of the country that the phone is activated on
   2291      * @return the converted dial string if the current/default countries belong to NANP,
   2292      * and if there is the "+" in the original dial string. Otherwise, the original dial
   2293      * string returns.
   2294      *
   2295      * @hide
   2296      */
   2297     public static String
   2298     cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormat) {
   2299         String retStr = dialStr;
   2300 
   2301         boolean useNanp = (currFormat == defaultFormat) && (currFormat == FORMAT_NANP);
   2302 
   2303         // Checks if the plus sign character is in the passed-in dial string
   2304         if (dialStr != null &&
   2305             dialStr.lastIndexOf(PLUS_SIGN_STRING) != -1) {
   2306 
   2307             // Handle case where default and current telephone numbering plans are NANP.
   2308             String postDialStr = null;
   2309             String tempDialStr = dialStr;
   2310 
   2311             // Sets the retStr to null since the conversion will be performed below.
   2312             retStr = null;
   2313             if (DBG) log("checkAndProcessPlusCode,dialStr=" + dialStr);
   2314             // This routine is to process the plus sign in the dial string by loop through
   2315             // the network portion, post dial portion 1, post dial portion 2... etc. if
   2316             // applied
   2317             do {
   2318                 String networkDialStr;
   2319                 // Format the string based on the rules for the country the number is from,
   2320                 // and the current country the phone is camped
   2321                 if (useNanp) {
   2322                     networkDialStr = extractNetworkPortion(tempDialStr);
   2323                 } else  {
   2324                     networkDialStr = extractNetworkPortionAlt(tempDialStr);
   2325 
   2326                 }
   2327 
   2328                 networkDialStr = processPlusCode(networkDialStr, useNanp);
   2329 
   2330                 // Concatenates the string that is converted from network portion
   2331                 if (!TextUtils.isEmpty(networkDialStr)) {
   2332                     if (retStr == null) {
   2333                         retStr = networkDialStr;
   2334                     } else {
   2335                         retStr = retStr.concat(networkDialStr);
   2336                     }
   2337                 } else {
   2338                     // This should never happen since we checked the if dialStr is null
   2339                     // and if it contains the plus sign in the beginning of this function.
   2340                     // The plus sign is part of the network portion.
   2341                     Rlog.e("checkAndProcessPlusCode: null newDialStr", networkDialStr);
   2342                     return dialStr;
   2343                 }
   2344                 postDialStr = extractPostDialPortion(tempDialStr);
   2345                 if (!TextUtils.isEmpty(postDialStr)) {
   2346                     int dialableIndex = findDialableIndexFromPostDialStr(postDialStr);
   2347 
   2348                     // dialableIndex should always be greater than 0
   2349                     if (dialableIndex >= 1) {
   2350                         retStr = appendPwCharBackToOrigDialStr(dialableIndex,
   2351                                  retStr,postDialStr);
   2352                         // Skips the P/W character, extracts the dialable portion
   2353                         tempDialStr = postDialStr.substring(dialableIndex);
   2354                     } else {
   2355                         // Non-dialable character such as P/W should not be at the end of
   2356                         // the dial string after P/W processing in GsmCdmaConnection.java
   2357                         // Set the postDialStr to "" to break out of the loop
   2358                         if (dialableIndex < 0) {
   2359                             postDialStr = "";
   2360                         }
   2361                         Rlog.e("wrong postDialStr=", postDialStr);
   2362                     }
   2363                 }
   2364                 if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr);
   2365             } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr));
   2366         }
   2367         return retStr;
   2368     }
   2369 
   2370     /**
   2371      * Wrap the supplied {@code CharSequence} with a {@code TtsSpan}, annotating it as
   2372      * containing a phone number in its entirety.
   2373      *
   2374      * @param phoneNumber A {@code CharSequence} the entirety of which represents a phone number.
   2375      * @return A {@code CharSequence} with appropriate annotations.
   2376      */
   2377     public static CharSequence createTtsSpannable(CharSequence phoneNumber) {
   2378         if (phoneNumber == null) {
   2379             return null;
   2380         }
   2381         Spannable spannable = Spannable.Factory.getInstance().newSpannable(phoneNumber);
   2382         PhoneNumberUtils.addTtsSpan(spannable, 0, spannable.length());
   2383         return spannable;
   2384     }
   2385 
   2386     /**
   2387      * Attach a {@link TtsSpan} to the supplied {@code Spannable} at the indicated location,
   2388      * annotating that location as containing a phone number.
   2389      *
   2390      * @param s A {@code Spannable} to annotate.
   2391      * @param start The starting character position of the phone number in {@code s}.
   2392      * @param endExclusive The position after the ending character in the phone number {@code s}.
   2393      */
   2394     public static void addTtsSpan(Spannable s, int start, int endExclusive) {
   2395         s.setSpan(createTtsSpan(s.subSequence(start, endExclusive).toString()),
   2396                 start,
   2397                 endExclusive,
   2398                 Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
   2399     }
   2400 
   2401     /**
   2402      * Wrap the supplied {@code CharSequence} with a {@code TtsSpan}, annotating it as
   2403      * containing a phone number in its entirety.
   2404      *
   2405      * @param phoneNumber A {@code CharSequence} the entirety of which represents a phone number.
   2406      * @return A {@code CharSequence} with appropriate annotations.
   2407      * @deprecated Renamed {@link #createTtsSpannable}.
   2408      *
   2409      * @hide
   2410      */
   2411     @Deprecated
   2412     public static CharSequence ttsSpanAsPhoneNumber(CharSequence phoneNumber) {
   2413         return createTtsSpannable(phoneNumber);
   2414     }
   2415 
   2416     /**
   2417      * Attach a {@link TtsSpan} to the supplied {@code Spannable} at the indicated location,
   2418      * annotating that location as containing a phone number.
   2419      *
   2420      * @param s A {@code Spannable} to annotate.
   2421      * @param start The starting character position of the phone number in {@code s}.
   2422      * @param end The ending character position of the phone number in {@code s}.
   2423      *
   2424      * @deprecated Renamed {@link #addTtsSpan}.
   2425      *
   2426      * @hide
   2427      */
   2428     @Deprecated
   2429     public static void ttsSpanAsPhoneNumber(Spannable s, int start, int end) {
   2430         addTtsSpan(s, start, end);
   2431     }
   2432 
   2433     /**
   2434      * Create a {@code TtsSpan} for the supplied {@code String}.
   2435      *
   2436      * @param phoneNumberString A {@code String} the entirety of which represents a phone number.
   2437      * @return A {@code TtsSpan} for {@param phoneNumberString}.
   2438      */
   2439     public static TtsSpan createTtsSpan(String phoneNumberString) {
   2440         if (phoneNumberString == null) {
   2441             return null;
   2442         }
   2443 
   2444         // Parse the phone number
   2445         final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
   2446         PhoneNumber phoneNumber = null;
   2447         try {
   2448             // Don't supply a defaultRegion so this fails for non-international numbers because
   2449             // we don't want to TalkBalk to read a country code (e.g. +1) if it is not already
   2450             // present
   2451             phoneNumber = phoneNumberUtil.parse(phoneNumberString, /* defaultRegion */ null);
   2452         } catch (NumberParseException ignored) {
   2453         }
   2454 
   2455         // Build a telephone tts span
   2456         final TtsSpan.TelephoneBuilder builder = new TtsSpan.TelephoneBuilder();
   2457         if (phoneNumber == null) {
   2458             // Strip separators otherwise TalkBack will be silent
   2459             // (this behavior was observed with TalkBalk 4.0.2 from their alpha channel)
   2460             builder.setNumberParts(splitAtNonNumerics(phoneNumberString));
   2461         } else {
   2462             if (phoneNumber.hasCountryCode()) {
   2463                 builder.setCountryCode(Integer.toString(phoneNumber.getCountryCode()));
   2464             }
   2465             builder.setNumberParts(Long.toString(phoneNumber.getNationalNumber()));
   2466         }
   2467         return builder.build();
   2468     }
   2469 
   2470     // Split a phone number like "+20(123)-456#" using spaces, ignoring anything that is not
   2471     // a digit, to produce a result like "20 123 456".
   2472     private static String splitAtNonNumerics(CharSequence number) {
   2473         StringBuilder sb = new StringBuilder(number.length());
   2474         for (int i = 0; i < number.length(); i++) {
   2475             sb.append(PhoneNumberUtils.isISODigit(number.charAt(i))
   2476                     ? number.charAt(i)
   2477                     : " ");
   2478         }
   2479         // It is very important to remove extra spaces. At time of writing, any leading or trailing
   2480         // spaces, or any sequence of more than one space, will confuse TalkBack and cause the TTS
   2481         // span to be non-functional!
   2482         return sb.toString().replaceAll(" +", " ").trim();
   2483     }
   2484 
   2485     private static String getCurrentIdp(boolean useNanp) {
   2486         String ps = null;
   2487         if (useNanp) {
   2488             ps = NANP_IDP_STRING;
   2489         } else {
   2490             // in case, there is no IDD is found, we shouldn't convert it.
   2491             ps = SystemProperties.get(PROPERTY_OPERATOR_IDP_STRING, PLUS_SIGN_STRING);
   2492         }
   2493         return ps;
   2494     }
   2495 
   2496     private static boolean isTwoToNine (char c) {
   2497         if (c >= '2' && c <= '9') {
   2498             return true;
   2499         } else {
   2500             return false;
   2501         }
   2502     }
   2503 
   2504     private static int getFormatTypeFromCountryCode (String country) {
   2505         // Check for the NANP countries
   2506         int length = NANP_COUNTRIES.length;
   2507         for (int i = 0; i < length; i++) {
   2508             if (NANP_COUNTRIES[i].compareToIgnoreCase(country) == 0) {
   2509                 return FORMAT_NANP;
   2510             }
   2511         }
   2512         if ("jp".compareToIgnoreCase(country) == 0) {
   2513             return FORMAT_JAPAN;
   2514         }
   2515         return FORMAT_UNKNOWN;
   2516     }
   2517 
   2518     /**
   2519      * This function checks if the passed in string conforms to the NANP format
   2520      * i.e. NXX-NXX-XXXX, N is any digit 2-9 and X is any digit 0-9
   2521      * @hide
   2522      */
   2523     public static boolean isNanp (String dialStr) {
   2524         boolean retVal = false;
   2525         if (dialStr != null) {
   2526             if (dialStr.length() == NANP_LENGTH) {
   2527                 if (isTwoToNine(dialStr.charAt(0)) &&
   2528                     isTwoToNine(dialStr.charAt(3))) {
   2529                     retVal = true;
   2530                     for (int i=1; i<NANP_LENGTH; i++ ) {
   2531                         char c=dialStr.charAt(i);
   2532                         if (!PhoneNumberUtils.isISODigit(c)) {
   2533                             retVal = false;
   2534                             break;
   2535                         }
   2536                     }
   2537                 }
   2538             }
   2539         } else {
   2540             Rlog.e("isNanp: null dialStr passed in", dialStr);
   2541         }
   2542         return retVal;
   2543     }
   2544 
   2545    /**
   2546     * This function checks if the passed in string conforms to 1-NANP format
   2547     */
   2548     private static boolean isOneNanp(String dialStr) {
   2549         boolean retVal = false;
   2550         if (dialStr != null) {
   2551             String newDialStr = dialStr.substring(1);
   2552             if ((dialStr.charAt(0) == '1') && isNanp(newDialStr)) {
   2553                 retVal = true;
   2554             }
   2555         } else {
   2556             Rlog.e("isOneNanp: null dialStr passed in", dialStr);
   2557         }
   2558         return retVal;
   2559     }
   2560 
   2561     /**
   2562      * Determines if the specified number is actually a URI
   2563      * (i.e. a SIP address) rather than a regular PSTN phone number,
   2564      * based on whether or not the number contains an "@" character.
   2565      *
   2566      * @hide
   2567      * @param number
   2568      * @return true if number contains @
   2569      */
   2570     public static boolean isUriNumber(String number) {
   2571         // Note we allow either "@" or "%40" to indicate a URI, in case
   2572         // the passed-in string is URI-escaped.  (Neither "@" nor "%40"
   2573         // will ever be found in a legal PSTN number.)
   2574         return number != null && (number.contains("@") || number.contains("%40"));
   2575     }
   2576 
   2577     /**
   2578      * @return the "username" part of the specified SIP address,
   2579      *         i.e. the part before the "@" character (or "%40").
   2580      *
   2581      * @param number SIP address of the form "username@domainname"
   2582      *               (or the URI-escaped equivalent "username%40domainname")
   2583      * @see #isUriNumber
   2584      *
   2585      * @hide
   2586      */
   2587     public static String getUsernameFromUriNumber(String number) {
   2588         // The delimiter between username and domain name can be
   2589         // either "@" or "%40" (the URI-escaped equivalent.)
   2590         int delimiterIndex = number.indexOf('@');
   2591         if (delimiterIndex < 0) {
   2592             delimiterIndex = number.indexOf("%40");
   2593         }
   2594         if (delimiterIndex < 0) {
   2595             Rlog.w(LOG_TAG,
   2596                   "getUsernameFromUriNumber: no delimiter found in SIP addr '" + number + "'");
   2597             delimiterIndex = number.length();
   2598         }
   2599         return number.substring(0, delimiterIndex);
   2600     }
   2601 
   2602     /**
   2603      * Given a {@link Uri} with a {@code sip} scheme, attempts to build an equivalent {@code tel}
   2604      * scheme {@link Uri}.  If the source {@link Uri} does not contain a valid number, or is not
   2605      * using the {@code sip} scheme, the original {@link Uri} is returned.
   2606      *
   2607      * @param source The {@link Uri} to convert.
   2608      * @return The equivalent {@code tel} scheme {@link Uri}.
   2609      *
   2610      * @hide
   2611      */
   2612     public static Uri convertSipUriToTelUri(Uri source) {
   2613         // A valid SIP uri has the format: sip:user:password@host:port;uri-parameters?headers
   2614         // Per RFC3261, the "user" can be a telephone number.
   2615         // For example: sip:1650555121;phone-context=blah.com (at) host.com
   2616         // In this case, the phone number is in the user field of the URI, and the parameters can be
   2617         // ignored.
   2618         //
   2619         // A SIP URI can also specify a phone number in a format similar to:
   2620         // sip:+1-212-555-1212 (at) something.com;user=phone
   2621         // In this case, the phone number is again in user field and the parameters can be ignored.
   2622         // We can get the user field in these instances by splitting the string on the @, ;, or :
   2623         // and looking at the first found item.
   2624 
   2625         String scheme = source.getScheme();
   2626 
   2627         if (!PhoneAccount.SCHEME_SIP.equals(scheme)) {
   2628             // Not a sip URI, bail.
   2629             return source;
   2630         }
   2631 
   2632         String number = source.getSchemeSpecificPart();
   2633         String numberParts[] = number.split("[@;:]");
   2634 
   2635         if (numberParts.length == 0) {
   2636             // Number not found, bail.
   2637             return source;
   2638         }
   2639         number = numberParts[0];
   2640 
   2641         return Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
   2642     }
   2643 
   2644     /**
   2645      * This function handles the plus code conversion
   2646      * If the number format is
   2647      * 1)+1NANP,remove +,
   2648      * 2)other than +1NANP, any + numbers,replace + with the current IDP
   2649      */
   2650     private static String processPlusCode(String networkDialStr, boolean useNanp) {
   2651         String retStr = networkDialStr;
   2652 
   2653         if (DBG) log("processPlusCode, networkDialStr = " + networkDialStr
   2654                 + "for NANP = " + useNanp);
   2655         // If there is a plus sign at the beginning of the dial string,
   2656         // Convert the plus sign to the default IDP since it's an international number
   2657         if (networkDialStr != null &&
   2658             networkDialStr.charAt(0) == PLUS_SIGN_CHAR &&
   2659             networkDialStr.length() > 1) {
   2660             String newStr = networkDialStr.substring(1);
   2661             // TODO: for nonNanp, should the '+' be removed if following number is country code
   2662             if (useNanp && isOneNanp(newStr)) {
   2663                 // Remove the leading plus sign
   2664                 retStr = newStr;
   2665             } else {
   2666                 // Replaces the plus sign with the default IDP
   2667                 retStr = networkDialStr.replaceFirst("[+]", getCurrentIdp(useNanp));
   2668             }
   2669         }
   2670         if (DBG) log("processPlusCode, retStr=" + retStr);
   2671         return retStr;
   2672     }
   2673 
   2674     // This function finds the index of the dialable character(s)
   2675     // in the post dial string
   2676     private static int findDialableIndexFromPostDialStr(String postDialStr) {
   2677         for (int index = 0;index < postDialStr.length();index++) {
   2678              char c = postDialStr.charAt(index);
   2679              if (isReallyDialable(c)) {
   2680                 return index;
   2681              }
   2682         }
   2683         return -1;
   2684     }
   2685 
   2686     // This function appends the non-dialable P/W character to the original
   2687     // dial string based on the dialable index passed in
   2688     private static String
   2689     appendPwCharBackToOrigDialStr(int dialableIndex,String origStr, String dialStr) {
   2690         String retStr;
   2691 
   2692         // There is only 1 P/W character before the dialable characters
   2693         if (dialableIndex == 1) {
   2694             StringBuilder ret = new StringBuilder(origStr);
   2695             ret = ret.append(dialStr.charAt(0));
   2696             retStr = ret.toString();
   2697         } else {
   2698             // It means more than 1 P/W characters in the post dial string,
   2699             // appends to retStr
   2700             String nonDigitStr = dialStr.substring(0,dialableIndex);
   2701             retStr = origStr.concat(nonDigitStr);
   2702         }
   2703         return retStr;
   2704     }
   2705 
   2706     //===== Beginning of utility methods used in compareLoosely() =====
   2707 
   2708     /**
   2709      * Phone numbers are stored in "lookup" form in the database
   2710      * as reversed strings to allow for caller ID lookup
   2711      *
   2712      * This method takes a phone number and makes a valid SQL "LIKE"
   2713      * string that will match the lookup form
   2714      *
   2715      */
   2716     /** all of a up to len must be an international prefix or
   2717      *  separators/non-dialing digits
   2718      */
   2719     private static boolean
   2720     matchIntlPrefix(String a, int len) {
   2721         /* '([^0-9*#+pwn]\+[^0-9*#+pwn] | [^0-9*#+pwn]0(0|11)[^0-9*#+pwn] )$' */
   2722         /*        0       1                           2 3 45               */
   2723 
   2724         int state = 0;
   2725         for (int i = 0 ; i < len ; i++) {
   2726             char c = a.charAt(i);
   2727 
   2728             switch (state) {
   2729                 case 0:
   2730                     if      (c == '+') state = 1;
   2731                     else if (c == '0') state = 2;
   2732                     else if (isNonSeparator(c)) return false;
   2733                 break;
   2734 
   2735                 case 2:
   2736                     if      (c == '0') state = 3;
   2737                     else if (c == '1') state = 4;
   2738                     else if (isNonSeparator(c)) return false;
   2739                 break;
   2740 
   2741                 case 4:
   2742                     if      (c == '1') state = 5;
   2743                     else if (isNonSeparator(c)) return false;
   2744                 break;
   2745 
   2746                 default:
   2747                     if (isNonSeparator(c)) return false;
   2748                 break;
   2749 
   2750             }
   2751         }
   2752 
   2753         return state == 1 || state == 3 || state == 5;
   2754     }
   2755 
   2756     /** all of 'a' up to len must be a (+|00|011)country code)
   2757      *  We're fast and loose with the country code. Any \d{1,3} matches */
   2758     private static boolean
   2759     matchIntlPrefixAndCC(String a, int len) {
   2760         /*  [^0-9*#+pwn]*(\+|0(0|11)\d\d?\d? [^0-9*#+pwn] $ */
   2761         /*      0          1 2 3 45  6 7  8                 */
   2762 
   2763         int state = 0;
   2764         for (int i = 0 ; i < len ; i++ ) {
   2765             char c = a.charAt(i);
   2766 
   2767             switch (state) {
   2768                 case 0:
   2769                     if      (c == '+') state = 1;
   2770                     else if (c == '0') state = 2;
   2771                     else if (isNonSeparator(c)) return false;
   2772                 break;
   2773 
   2774                 case 2:
   2775                     if      (c == '0') state = 3;
   2776                     else if (c == '1') state = 4;
   2777                     else if (isNonSeparator(c)) return false;
   2778                 break;
   2779 
   2780                 case 4:
   2781                     if      (c == '1') state = 5;
   2782                     else if (isNonSeparator(c)) return false;
   2783                 break;
   2784 
   2785                 case 1:
   2786                 case 3:
   2787                 case 5:
   2788                     if      (isISODigit(c)) state = 6;
   2789                     else if (isNonSeparator(c)) return false;
   2790                 break;
   2791 
   2792                 case 6:
   2793                 case 7:
   2794                     if      (isISODigit(c)) state++;
   2795                     else if (isNonSeparator(c)) return false;
   2796                 break;
   2797 
   2798                 default:
   2799                     if (isNonSeparator(c)) return false;
   2800             }
   2801         }
   2802 
   2803         return state == 6 || state == 7 || state == 8;
   2804     }
   2805 
   2806     /** all of 'a' up to len must match non-US trunk prefix ('0') */
   2807     private static boolean
   2808     matchTrunkPrefix(String a, int len) {
   2809         boolean found;
   2810 
   2811         found = false;
   2812 
   2813         for (int i = 0 ; i < len ; i++) {
   2814             char c = a.charAt(i);
   2815 
   2816             if (c == '0' && !found) {
   2817                 found = true;
   2818             } else if (isNonSeparator(c)) {
   2819                 return false;
   2820             }
   2821         }
   2822 
   2823         return found;
   2824     }
   2825 
   2826     //===== End of utility methods used only in compareLoosely() =====
   2827 
   2828     //===== Beginning of utility methods used only in compareStrictly() ====
   2829 
   2830     /*
   2831      * If true, the number is country calling code.
   2832      */
   2833     private static final boolean COUNTRY_CALLING_CALL[] = {
   2834         true, true, false, false, false, false, false, true, false, false,
   2835         false, false, false, false, false, false, false, false, false, false,
   2836         true, false, false, false, false, false, false, true, true, false,
   2837         true, true, true, true, true, false, true, false, false, true,
   2838         true, false, false, true, true, true, true, true, true, true,
   2839         false, true, true, true, true, true, true, true, true, false,
   2840         true, true, true, true, true, true, true, false, false, false,
   2841         false, false, false, false, false, false, false, false, false, false,
   2842         false, true, true, true, true, false, true, false, false, true,
   2843         true, true, true, true, true, true, false, false, true, false,
   2844     };
   2845     private static final int CCC_LENGTH = COUNTRY_CALLING_CALL.length;
   2846 
   2847     /**
   2848      * @return true when input is valid Country Calling Code.
   2849      */
   2850     private static boolean isCountryCallingCode(int countryCallingCodeCandidate) {
   2851         return countryCallingCodeCandidate > 0 && countryCallingCodeCandidate < CCC_LENGTH &&
   2852                 COUNTRY_CALLING_CALL[countryCallingCodeCandidate];
   2853     }
   2854 
   2855     /**
   2856      * Returns integer corresponding to the input if input "ch" is
   2857      * ISO-LATIN characters 0-9.
   2858      * Returns -1 otherwise
   2859      */
   2860     private static int tryGetISODigit(char ch) {
   2861         if ('0' <= ch && ch <= '9') {
   2862             return ch - '0';
   2863         } else {
   2864             return -1;
   2865         }
   2866     }
   2867 
   2868     private static class CountryCallingCodeAndNewIndex {
   2869         public final int countryCallingCode;
   2870         public final int newIndex;
   2871         public CountryCallingCodeAndNewIndex(int countryCode, int newIndex) {
   2872             this.countryCallingCode = countryCode;
   2873             this.newIndex = newIndex;
   2874         }
   2875     }
   2876 
   2877     /*
   2878      * Note that this function does not strictly care the country calling code with
   2879      * 3 length (like Morocco: +212), assuming it is enough to use the first two
   2880      * digit to compare two phone numbers.
   2881      */
   2882     private static CountryCallingCodeAndNewIndex tryGetCountryCallingCodeAndNewIndex(
   2883         String str, boolean acceptThailandCase) {
   2884         // Rough regexp:
   2885         //  ^[^0-9*#+]*((\+|0(0|11)\d\d?|166) [^0-9*#+] $
   2886         //         0        1 2 3 45  6 7  89
   2887         //
   2888         // In all the states, this function ignores separator characters.
   2889         // "166" is the special case for the call from Thailand to the US. Uguu!
   2890         int state = 0;
   2891         int ccc = 0;
   2892         final int length = str.length();
   2893         for (int i = 0 ; i < length ; i++ ) {
   2894             char ch = str.charAt(i);
   2895             switch (state) {
   2896                 case 0:
   2897                     if      (ch == '+') state = 1;
   2898                     else if (ch == '0') state = 2;
   2899                     else if (ch == '1') {
   2900                         if (acceptThailandCase) {
   2901                             state = 8;
   2902                         } else {
   2903                             return null;
   2904                         }
   2905                     } else if (isDialable(ch)) {
   2906                         return null;
   2907                     }
   2908                 break;
   2909 
   2910                 case 2:
   2911                     if      (ch == '0') state = 3;
   2912                     else if (ch == '1') state = 4;
   2913                     else if (isDialable(ch)) {
   2914                         return null;
   2915                     }
   2916                 break;
   2917 
   2918                 case 4:
   2919                     if      (ch == '1') state = 5;
   2920                     else if (isDialable(ch)) {
   2921                         return null;
   2922                     }
   2923                 break;
   2924 
   2925                 case 1:
   2926                 case 3:
   2927                 case 5:
   2928                 case 6:
   2929                 case 7:
   2930                     {
   2931                         int ret = tryGetISODigit(ch);
   2932                         if (ret > 0) {
   2933                             ccc = ccc * 10 + ret;
   2934                             if (ccc >= 100 || isCountryCallingCode(ccc)) {
   2935                                 return new CountryCallingCodeAndNewIndex(ccc, i + 1);
   2936                             }
   2937                             if (state == 1 || state == 3 || state == 5) {
   2938                                 state = 6;
   2939                             } else {
   2940                                 state++;
   2941                             }
   2942                         } else if (isDialable(ch)) {
   2943                             return null;
   2944                         }
   2945                     }
   2946                     break;
   2947                 case 8:
   2948                     if (ch == '6') state = 9;
   2949                     else if (isDialable(ch)) {
   2950                         return null;
   2951                     }
   2952                     break;
   2953                 case 9:
   2954                     if (ch == '6') {
   2955                         return new CountryCallingCodeAndNewIndex(66, i + 1);
   2956                     } else {
   2957                         return null;
   2958                     }
   2959                 default:
   2960                     return null;
   2961             }
   2962         }
   2963 
   2964         return null;
   2965     }
   2966 
   2967     /**
   2968      * Currently this function simply ignore the first digit assuming it is
   2969      * trunk prefix. Actually trunk prefix is different in each country.
   2970      *
   2971      * e.g.
   2972      * "+79161234567" equals "89161234567" (Russian trunk digit is 8)
   2973      * "+33123456789" equals "0123456789" (French trunk digit is 0)
   2974      *
   2975      */
   2976     private static int tryGetTrunkPrefixOmittedIndex(String str, int currentIndex) {
   2977         int length = str.length();
   2978         for (int i = currentIndex ; i < length ; i++) {
   2979             final char ch = str.charAt(i);
   2980             if (tryGetISODigit(ch) >= 0) {
   2981                 return i + 1;
   2982             } else if (isDialable(ch)) {
   2983                 return -1;
   2984             }
   2985         }
   2986         return -1;
   2987     }
   2988 
   2989     /**
   2990      * Return true if the prefix of "str" is "ignorable". Here, "ignorable" means
   2991      * that "str" has only one digit and separator characters. The one digit is
   2992      * assumed to be trunk prefix.
   2993      */
   2994     private static boolean checkPrefixIsIgnorable(final String str,
   2995             int forwardIndex, int backwardIndex) {
   2996         boolean trunk_prefix_was_read = false;
   2997         while (backwardIndex >= forwardIndex) {
   2998             if (tryGetISODigit(str.charAt(backwardIndex)) >= 0) {
   2999                 if (trunk_prefix_was_read) {
   3000                     // More than one digit appeared, meaning that "a" and "b"
   3001                     // is different.
   3002                     return false;
   3003                 } else {
   3004                     // Ignore just one digit, assuming it is trunk prefix.
   3005                     trunk_prefix_was_read = true;
   3006                 }
   3007             } else if (isDialable(str.charAt(backwardIndex))) {
   3008                 // Trunk prefix is a digit, not "*", "#"...
   3009                 return false;
   3010             }
   3011             backwardIndex--;
   3012         }
   3013 
   3014         return true;
   3015     }
   3016 
   3017     /**
   3018      * Returns Default voice subscription Id.
   3019      */
   3020     private static int getDefaultVoiceSubId() {
   3021         return SubscriptionManager.getDefaultVoiceSubscriptionId();
   3022     }
   3023     //==== End of utility methods used only in compareStrictly() =====
   3024 }
   3025