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