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