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