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