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