PhoneNumberUtils.java revision db1f4993989bb03cae2f3e008d4db3e49577aa73
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.telephony;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Contacts;
25f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkeyimport android.provider.ContactsContract;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Editable;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.SpannableStringBuilder;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils;
2918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.comimport android.util.Log;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseIntArray;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
327850cdde66705152b859aafda875833acdda9653Libin Tangimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
3318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.comimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING;
347850cdde66705152b859aafda875833acdda9653Libin Tangimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
3518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Locale;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.regex.Matcher;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.regex.Pattern;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Various utilities for dealing with phone number strings.
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class PhoneNumberUtils
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Special characters
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (See "What is a phone number?" doc)
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 'p' --- GSM pause character, same as comma
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 'n' --- GSM wild character
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 'w' --- GSM wait character
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final char PAUSE = ',';
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final char WAIT = ';';
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final char WILD = 'N';
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TOA = TON + NPI
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * See TS 24.008 section 10.5.4.7 for details.
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * These are the only really useful TOA values
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int TOA_International = 0x91;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int TOA_Unknown = 0x81;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    static final String LOG_TAG = "PhoneNumberUtils";
6618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static final boolean DBG = false;
6718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * global-phone-number = ["+"] 1*( DIGIT / written-sep )
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * written-sep         = ("-"/".")
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final Pattern GLOBAL_PHONE_NUMBER_PATTERN =
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Pattern.compile("[\\+]?[0-9.-]+");
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** True if c is ISO-LATIN characters 0-9 */
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    isISODigit (char c) {
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return c >= '0' && c <= '9';
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** True if c is ISO-LATIN characters 0-9, *, # */
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static boolean
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    is12Key(char c) {
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (c >= '0' && c <= '9') || c == '*' || c == '#';
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** True if c is ISO-LATIN characters 0-9, *, # , +, WILD  */
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static boolean
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    isDialable(char c) {
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+' || c == WILD;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** True if c is ISO-LATIN characters 0-9, *, # , + (no WILD)  */
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static boolean
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    isReallyDialable(char c) {
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+';
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** True if c is ISO-LATIN characters 0-9, *, # , +, WILD, WAIT, PAUSE   */
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static boolean
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    isNonSeparator(char c) {
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+'
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || c == WILD || c == WAIT || c == PAUSE;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** This any anything to the right of this char is part of the
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  post-dial string (eg this is PAUSE or WAIT)
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static boolean
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    isStartsPostDial (char c) {
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return c == PAUSE || c == WAIT;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1149a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /** Returns true if ch is not dialable or alpha char */
1159a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean isSeparator(char ch) {
1169a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return !isDialable(ch) && !(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'));
1179a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
1189a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Extracts the phone number from an Intent.
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param intent the intent to get the number of
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context a context to use for database access
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the phone number that would be called by the intent, or
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         <code>null</code> if the number cannot be found.
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String getNumberFromIntent(Intent intent, Context context) {
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String number = null;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Uri uri = intent.getData();
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String scheme = uri.getScheme();
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (scheme.equals("tel")) {
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return uri.getSchemeSpecificPart();
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13760d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // TODO: We don't check for SecurityException here (requires
13860d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // READ_PHONE_STATE permission).
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (scheme.equals("voicemail")) {
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return TelephonyManager.getDefault().getVoiceMailNumber();
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (context == null) {
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String type = intent.resolveType(context);
148f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        String phoneColumn = null;
149f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey
150f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        // Correctly read out the phone entry based on requested provider
151f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        final String authority = uri.getAuthority();
152f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        if (Contacts.AUTHORITY.equals(authority)) {
153f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey            phoneColumn = Contacts.People.Phones.NUMBER;
154f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        } else if (ContactsContract.AUTHORITY.equals(authority)) {
155f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey            phoneColumn = ContactsContract.CommonDataKinds.Phone.NUMBER;
156f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        }
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
158f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        final Cursor c = context.getContentResolver().query(uri, new String[] {
159f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey            phoneColumn
160f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        }, null, null, null);
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c != null) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (c.moveToFirst()) {
164f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey                    number = c.getString(c.getColumnIndex(phoneColumn));
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c.close();
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return number;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Extracts the network address portion and canonicalizes
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  (filters out separators.)
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Network address portion is everything up to DTMF control digit
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  separators (pause or wait), but without non-dialable characters.
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Please note that the GSM wild character is allowed in the result.
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  This must be resolved before dialing.
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Allows + only in the first  position in the result string.
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Returns null if phoneNumber == null
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    extractNetworkPortion(String phoneNumber) {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (phoneNumber == null) {
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = phoneNumber.length();
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder(len);
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean firstCharAdded = false;
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < len; i++) {
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = phoneNumber.charAt(i);
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isDialable(c) && (c != '+' || !firstCharAdded)) {
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                firstCharAdded = true;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ret.append(c);
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (isStartsPostDial (c)) {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Strips separators from a phone number string.
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param phoneNumber phone number to strip.
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return phone string stripped of separators.
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String stripSeparators(String phoneNumber) {
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (phoneNumber == null) {
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = phoneNumber.length();
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder(len);
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < len; i++) {
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = phoneNumber.charAt(i);
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isNonSeparator(c)) {
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ret.append(c);
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** or -1 if both are negative */
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static private int
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    minPositive (int a, int b) {
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (a >= 0 && b >= 0) {
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (a < b) ? a : b;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (a >= 0) { /* && b < 0 */
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return a;
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (b >= 0) { /* && a < 0 */
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return b;
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else { /* a < 0 && b < 0 */
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static void log(String msg) {
24618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        Log.d(LOG_TAG, msg);
24718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** index of the last character of the network portion
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  (eg anything after is a post-dial string)
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static private int
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    indexOfLastNetworkChar(String a) {
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int pIndex, wIndex;
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int origLength;
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int trimIndex;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        origLength = a.length();
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        pIndex = a.indexOf(PAUSE);
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        wIndex = a.indexOf(WAIT);
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        trimIndex = minPositive(pIndex, wIndex);
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (trimIndex < 0) {
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return origLength - 1;
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return trimIndex - 1;
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Extracts the post-dial sequence of DTMF control digits, pauses, and
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * waits. Strips separators. This string may be empty, but will not be null
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * unless phoneNumber == null.
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if phoneNumber == null
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    extractPostDialPortion(String phoneNumber) {
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (phoneNumber == null) return null;
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int trimIndex;
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder();
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        trimIndex = indexOfLastNetworkChar (phoneNumber);
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = trimIndex + 1, s = phoneNumber.length()
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ; i < s; i++
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ) {
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = phoneNumber.charAt(i);
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isNonSeparator(c)) {
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ret.append(c);
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3019a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Compare phone numbers a and b, return true if they're identical enough for caller ID purposes.
3029a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
3039a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    public static boolean compare(String a, String b) {
3049a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        // We've used loose comparation at least Eclair, which may change in the future.
305db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar
3069a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return compare(a, b, false);
3079a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
3089a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
3099a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
310db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar     * Compare phone numbers a and b, and return true if they're identical
311db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar     * enough for caller ID purposes. Checks a resource to determine whether
312db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar     * to use a strict or loose comparison algorithm.
313db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar     */
314db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar    public static boolean compare(Context context, String a, String b) {
315db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar        boolean useStrict = context.getResources().getBoolean(
316db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar               com.android.internal.R.bool.config_use_strict_phone_number_comparation);
317db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar        return compare(a, b, useStrict);
318db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar    }
319db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar
320db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar    /**
3219a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * @hide only for testing.
3229a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
3239a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    public static boolean compare(String a, String b, boolean useStrictComparation) {
3249a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return (useStrictComparation ? compareStrictly(a, b) : compareLoosely(a, b));
3259a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
3269a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
3279a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Compare phone numbers a and b, return true if they're identical
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * enough for caller ID purposes.
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * - Compares from right to left
33202b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang     * - requires MIN_MATCH (7) characters to match
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * - handles common trunk prefixes and international prefixes
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   (basically, everything except the Russian trunk prefix)
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Note that this method does not return false even when the two phone numbers
3379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * are not exactly same; rather; we can call this method "similar()", not "equals()".
3389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *
3399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * @hide
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean
3429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    compareLoosely(String a, String b) {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int ia, ib;
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int matched;
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (a == null || b == null) return a == b;
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (a.length() == 0 || b.length() == 0) {
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ia = indexOfLastNetworkChar (a);
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ib = indexOfLastNetworkChar (b);
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        matched = 0;
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (ia >= 0 && ib >=0) {
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char ca, cb;
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean skipCmp = false;
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ca = a.charAt(ia);
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isDialable(ca)) {
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ia--;
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                skipCmp = true;
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cb = b.charAt(ib);
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isDialable(cb)) {
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ib--;
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                skipCmp = true;
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!skipCmp) {
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cb != ca && ca != WILD && cb != WILD) {
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ia--; ib--; matched++;
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (matched < MIN_MATCH) {
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int aLen = a.length();
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // if the input strings match, but their lengths < MIN_MATCH,
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // treat them as equal.
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (aLen == b.length() && aLen == matched) {
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // At least one string has matched completely;
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (matched >= MIN_MATCH && (ia < 0 || ib < 0)) {
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Now, what remains must be one of the following for a
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * match:
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  - a '+' on one and a '00' or a '011' on the other
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  - a '0' on one and a (+,00)<country code> on the other
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     (for this, a '0' and a '00' prefix would have succeeded above)
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (matchIntlPrefix(a, ia + 1)
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && matchIntlPrefix (b, ib +1)
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ) {
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (matchTrunkPrefix(a, ia + 1)
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && matchIntlPrefixAndCC(b, ib +1)
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ) {
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (matchTrunkPrefix(b, ib + 1)
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && matchIntlPrefixAndCC(a, ia +1)
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ) {
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4299a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * @hide
4309a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
4319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    public static boolean
4329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    compareStrictly(String a, String b) {
4339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return compareStrictly(a, b, true);
4349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
4359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
4369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
4379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * @hide
4389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
4399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    public static boolean
4409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    compareStrictly(String a, String b, boolean acceptInvalidCCCPrefix) {
4419a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        if (a == null || b == null) {
4429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            return a == b;
4439a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        } else if (a.length() == 0 && b.length() == 0) {
4449a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            return false;
4459a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
4469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
4479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int forwardIndexA = 0;
4489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int forwardIndexB = 0;
4499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
4509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        CountryCallingCodeAndNewIndex cccA =
4519a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            tryGetCountryCallingCodeAndNewIndex(a, acceptInvalidCCCPrefix);
4529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        CountryCallingCodeAndNewIndex cccB =
4539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            tryGetCountryCallingCodeAndNewIndex(b, acceptInvalidCCCPrefix);
4549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean bothHasCountryCallingCode = false;
4559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean okToIgnorePrefix = true;
4569a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean trunkPrefixIsOmittedA = false;
4579a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean trunkPrefixIsOmittedB = false;
4589a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        if (cccA != null && cccB != null) {
4599a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (cccA.countryCallingCode != cccB.countryCallingCode) {
4609a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                // Different Country Calling Code. Must be different phone number.
4619a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                return false;
4629a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
4639a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // When both have ccc, do not ignore trunk prefix. Without this,
4649a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // "+81123123" becomes same as "+810123123" (+81 == Japan)
4659a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            okToIgnorePrefix = false;
4669a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            bothHasCountryCallingCode = true;
4679a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            forwardIndexA = cccA.newIndex;
4689a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            forwardIndexB = cccB.newIndex;
4699a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        } else if (cccA == null && cccB == null) {
4709a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // When both do not have ccc, do not ignore trunk prefix. Without this,
4719a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // "123123" becomes same as "0123123"
4729a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            okToIgnorePrefix = false;
4739a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        } else {
4749a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (cccA != null) {
4759a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                forwardIndexA = cccA.newIndex;
4769a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            } else {
4779a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                int tmp = tryGetTrunkPrefixOmittedIndex(b, 0);
4789a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (tmp >= 0) {
4799a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    forwardIndexA = tmp;
4809a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    trunkPrefixIsOmittedA = true;
4819a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
4829a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
4839a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (cccB != null) {
4849a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                forwardIndexB = cccB.newIndex;
4859a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            } else {
4869a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                int tmp = tryGetTrunkPrefixOmittedIndex(b, 0);
4879a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (tmp >= 0) {
4889a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    forwardIndexB = tmp;
4899a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    trunkPrefixIsOmittedB = true;
4909a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
4919a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
4929a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
4939a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
4949a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int backwardIndexA = a.length() - 1;
4959a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int backwardIndexB = b.length() - 1;
4969a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        while (backwardIndexA >= forwardIndexA && backwardIndexB >= forwardIndexB) {
4979a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            boolean skip_compare = false;
4989a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            final char chA = a.charAt(backwardIndexA);
4999a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            final char chB = b.charAt(backwardIndexB);
5009a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (isSeparator(chA)) {
5019a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexA--;
5029a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                skip_compare = true;
5039a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
5049a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (isSeparator(chB)) {
5059a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexB--;
5069a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                skip_compare = true;
5079a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
5089a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
5099a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (!skip_compare) {
5109a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (chA != chB) {
5119a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return false;
5129a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
5139a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexA--;
5149a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexB--;
5159a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
5169a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
5179a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
5189a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        if (okToIgnorePrefix) {
5199a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if ((trunkPrefixIsOmittedA && forwardIndexA <= backwardIndexA) ||
5209a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                !checkPrefixIsIgnorable(a, forwardIndexA, backwardIndexA)) {
5219a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (acceptInvalidCCCPrefix) {
5229a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // Maybe the code handling the special case for Thailand makes the
5239a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // result garbled, so disable the code and try again.
5249a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // e.g. "16610001234" must equal to "6610001234", but with
5259a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    //      Thailand-case handling code, they become equal to each other.
5269a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    //
5279a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // Note: we select simplicity rather than adding some complicated
5289a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    //       logic here for performance(like "checking whether remaining
5299a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    //       numbers are just 66 or not"), assuming inputs are small
5309a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    //       enough.
5319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return compare(a, b, false);
5329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                } else {
5339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return false;
5349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
5359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
5369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if ((trunkPrefixIsOmittedB && forwardIndexB <= backwardIndexB) ||
5379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                !checkPrefixIsIgnorable(b, forwardIndexA, backwardIndexB)) {
5389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (acceptInvalidCCCPrefix) {
5399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return compare(a, b, false);
5409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                } else {
5419a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return false;
5429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
5439a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
5449a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        } else {
5459a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // In the US, 1-650-555-1234 must be equal to 650-555-1234,
5469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // while 090-1234-1234 must not be equalt to 90-1234-1234 in Japan.
5479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // This request exists just in US (with 1 trunk (NDD) prefix).
5489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // In addition, "011 11 7005554141" must not equal to "+17005554141",
5499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // while "011 1 7005554141" must equal to "+17005554141"
5509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            //
5519a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // In this comparison, we ignore the prefix '1' just once, when
5529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // - at least either does not have CCC, or
5539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // - the remaining non-separator number is 1
5549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            boolean maybeNamp = !bothHasCountryCallingCode;
5559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            while (backwardIndexA >= forwardIndexA) {
5569a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                final char chA = a.charAt(backwardIndexA);
5579a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (isDialable(chA)) {
5589a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (maybeNamp && tryGetISODigit(chA) == 1) {
5599a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        maybeNamp = false;
5609a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    } else {
5619a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return false;
5629a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
5639a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
5649a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexA--;
5659a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
5669a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            while (backwardIndexB >= forwardIndexB) {
5679a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                final char chB = b.charAt(backwardIndexB);
5689a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (isDialable(chB)) {
5699a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (maybeNamp && tryGetISODigit(chB) == 1) {
5709a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        maybeNamp = false;
5719a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    } else {
5729a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return false;
5739a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
5749a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
5759a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexB--;
5769a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
5779a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
5789a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
5799a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return true;
5809a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
5819a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
5829a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the rightmost MIN_MATCH (5) characters in the network portion
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in *reversed* order
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This can be used to do a database lookup against the column
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that stores getStrippedReversed()
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if phoneNumber == null
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    toCallerIDMinMatch(String phoneNumber) {
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String np = extractNetworkPortion(phoneNumber);
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return internalGetStrippedReversed(np, MIN_MATCH);
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the network portion reversed.
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This string is intended to go into an index column for a
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * database lookup.
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if phoneNumber == null
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    getStrippedReversed(String phoneNumber) {
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String np = extractNetworkPortion(phoneNumber);
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (np == null) return null;
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return internalGetStrippedReversed(np, np.length());
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the last numDigits of the reversed phone number
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if np == null
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    internalGetStrippedReversed(String np, int numDigits) {
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (np == null) return null;
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder(numDigits);
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int length = np.length();
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = length - 1, s = length
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ; i >= 0 && (s - i) <= numDigits ; i--
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ) {
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = np.charAt(i);
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ret.append(c);
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Basically: makes sure there's a + in front of a
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TOA_International number
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if s == null
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    stringFromStringAndTOA(String s, int TOA) {
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (s == null) return null;
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TOA == TOA_International && s.length() > 0 && s.charAt(0) != '+') {
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "+" + s;
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return s;
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the TOA for the given dial string
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Basically, returns TOA_International if there's a + prefix
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    toaFromString(String s) {
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (s != null && s.length() > 0 && s.charAt(0) == '+') {
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return TOA_International;
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return TOA_Unknown;
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  3GPP TS 24.008 10.5.4.7
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Called Party BCD Number
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  See Also TS 51.011 10.5.1 "dialing number/ssc string"
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  and TS 11.11 "10.3.1 EF adn (Abbreviated dialing numbers)"
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param bytes the data buffer
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param offset should point to the TOA (aka. TON/NPI) octet after the length byte
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param length is the number of bytes including TOA byte
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                and must be at least 2
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return partial string on invalid decode
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * FIXME(mkf) support alphanumeric address type
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  currently implemented in SMSMessage.getAddress()
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    calledPartyBCDToString (byte[] bytes, int offset, int length) {
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean prependPlus = false;
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder(1 + length * 2);
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (length < 2) {
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "";
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((bytes[offset] & 0xff) == TOA_International) {
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            prependPlus = true;
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        internalCalledPartyBCDFragmentToString(
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ret, bytes, offset + 1, length - 1);
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (prependPlus && ret.length() == 0) {
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the only thing there is a prepended plus, return ""
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "";
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (prependPlus) {
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is an "international number" and should have
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a plus prepended to the dialing number. But there
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // can also be Gsm MMI codes as defined in TS 22.030 6.5.2
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // so we need to handle those also.
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // http://web.telia.com/~u47904776/gsmkode.htm is a
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // has a nice list of some of these GSM codes.
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Examples are:
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   **21*+886988171479#
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   **21*8311234567#
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   *21#
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   #21#
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   *#21#
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   *31#+11234567890
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   #31#+18311234567
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   #31#8311234567
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   18311234567
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   +18311234567#
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   +18311234567
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Odd ball cases that some phones handled
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // where there is no dialing number so they
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // append the "+"
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   *21#+
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   **21#+
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String retString = ret.toString();
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Pattern p = Pattern.compile("(^[#*])(.*)([#*])(.*)(#)$");
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Matcher m = p.matcher(retString);
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (m.matches()) {
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ("".equals(m.group(2))) {
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Started with two [#*] ends with #
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // So no dialing number and we'll just
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // append a +, this handles **21#+
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = new StringBuilder();
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(1));
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(3));
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(4));
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(5));
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append("+");
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Starts with [#*] and ends with #
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Assume group 4 is a dialing number
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // such as *21*+1234554#
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = new StringBuilder();
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(1));
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(2));
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(3));
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append("+");
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(4));
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(5));
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p = Pattern.compile("(^[#*])(.*)([#*])(.*)");
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                m = p.matcher(retString);
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (m.matches()) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Starts with [#*] and only one other [#*]
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Assume the data after last [#*] is dialing
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // number (i.e. group 4) such as *31#+11234567890.
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // This also includes the odd ball *21#+
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = new StringBuilder();
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(1));
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(2));
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(3));
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append("+");
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(4));
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Does NOT start with [#*] just prepend '+'
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = new StringBuilder();
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append('+');
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(retString);
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    internalCalledPartyBCDFragmentToString(
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb, byte [] bytes, int offset, int length) {
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = offset ; i < length + offset ; i++) {
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            byte b;
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c;
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            c = bcdToChar((byte)(bytes[i] & 0xf));
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c == 0) {
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(c);
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // FIXME(mkf) TS 23.040 9.1.2.3 says
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // "if a mobile receives 1111 in a position prior to
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // the last semi-octet then processing shall commense with
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // the next semi-octet and the intervening
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // semi-octet shall be ignored"
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // How does this jive with 24,008 10.5.4.7
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            b = (byte)((bytes[i] >> 4) & 0xf);
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (b == 0xf && i + 1 == length + offset) {
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                //ignore final 0xf
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            c = bcdToChar(b);
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c == 0) {
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(c);
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Like calledPartyBCDToString, but field does not start with a
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TOA byte. For example: SIM ADN extension fields
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    calledPartyBCDFragmentToString(byte [] bytes, int offset, int length) {
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder(length * 2);
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        internalCalledPartyBCDFragmentToString(ret, bytes, offset, length);
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** returns 0 on invalid value */
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static char
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bcdToChar(byte b) {
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (b < 0xa) {
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (char)('0' + b);
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else switch (b) {
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case 0xa: return '*';
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case 0xb: return '#';
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case 0xc: return PAUSE;
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case 0xd: return WILD;
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default: return 0;
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static int
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    charToBCD(char c) {
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '0' && c <= '9') {
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return c - '0';
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (c == '*') {
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0xa;
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (c == '#') {
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0xb;
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (c == PAUSE) {
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0xc;
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (c == WILD) {
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0xd;
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException ("invalid char for BCD " + c);
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return true iff the network portion of <code>address</code> is,
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as far as we can tell on the device, suitable for use as an SMS
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * destination address.
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean isWellFormedSmsAddress(String address) {
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String networkPortion =
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PhoneNumberUtils.extractNetworkPortion(address);
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (!(networkPortion.equals("+")
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  || TextUtils.isEmpty(networkPortion)))
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               && isDialable(networkPortion);
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean isGlobalPhoneNumber(String phoneNumber) {
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TextUtils.isEmpty(phoneNumber)) {
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Matcher match = GLOBAL_PHONE_NUMBER_PATTERN.matcher(phoneNumber);
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return match.matches();
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean isDialable(String address) {
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0, count = address.length(); i < count; i++) {
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isDialable(address.charAt(i))) {
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
89818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static boolean isNonSeparator(String address) {
89918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        for (int i = 0, count = address.length(); i < count; i++) {
90018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            if (!isNonSeparator(address.charAt(i))) {
90118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                return false;
90218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            }
90318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
90418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return true;
90518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9073a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     * Note: calls extractNetworkPortion(), so do not use for
9083a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     * SIM EF[ADN] style records
9093a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     *
9103a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     * Returns null if network portion is empty.
9113a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     */
9123a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink    public static byte[]
9133a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink    networkPortionToCalledPartyBCD(String s) {
9143a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        String networkPortion = extractNetworkPortion(s);
9153a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        return numberToCalledPartyBCDHelper(networkPortion, false);
9163a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink    }
9173a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink
9183a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink    /**
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Same as {@link #networkPortionToCalledPartyBCD}, but includes a
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * one-byte length prefix.
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static byte[]
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    networkPortionToCalledPartyBCDWithLength(String s) {
9243a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        String networkPortion = extractNetworkPortion(s);
9253a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        return numberToCalledPartyBCDHelper(networkPortion, true);
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Convert a dialing number to BCD byte array
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param number dialing number string
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        if the dialing number starts with '+', set to internationl TOA
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return BCD byte array
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static byte[]
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    numberToCalledPartyBCD(String number) {
9373a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        return numberToCalledPartyBCDHelper(number, false);
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9413a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     * If includeLength is true, prepend a one-byte length value to
9423a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     * the return array.
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static byte[]
9453a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink    numberToCalledPartyBCDHelper(String number, boolean includeLength) {
9463a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int numberLenReal = number.length();
9473a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int numberLenEffective = numberLenReal;
9483a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        boolean hasPlus = number.indexOf('+') != -1;
9493a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        if (hasPlus) numberLenEffective--;
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9513a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        if (numberLenEffective == 0) return null;
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9533a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int resultLen = (numberLenEffective + 1) / 2;  // Encoded numbers require only 4 bits each.
9543a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int extraBytes = 1;                            // Prepended TOA byte.
9553a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        if (includeLength) extraBytes++;               // Optional prepended length byte.
9563a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        resultLen += extraBytes;
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9583a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        byte[] result = new byte[resultLen];
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9603a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int digitCount = 0;
9613a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        for (int i = 0; i < numberLenReal; i++) {
9623a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink            char c = number.charAt(i);
9633a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink            if (c == '+') continue;
9643a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink            int shift = ((digitCount & 0x01) == 1) ? 4 : 0;
9653a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink            result[extraBytes + (digitCount >> 1)] |= (byte)((charToBCD(c) & 0x0F) << shift);
9663a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink            digitCount++;
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9693a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        // 1-fill any trailing odd nibble/quartet.
9703a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        if ((digitCount & 0x01) == 1) result[extraBytes + (digitCount >> 1)] |= 0xF0;
9713a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink
9723a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int offset = 0;
9733a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        if (includeLength) result[offset++] = (byte)(resultLen - 1);
9743a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        result[offset] = (byte)(hasPlus ? TOA_International : TOA_Unknown);
9753a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink
9763a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        return result;
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    //================ Number formatting =========================
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The current locale is unknown, look for a country code or don't format */
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int FORMAT_UNKNOWN = 0;
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** NANP formatting */
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int FORMAT_NANP = 1;
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Japanese formatting */
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int FORMAT_JAPAN = 2;
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** List of country codes for countries that use the NANP */
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String[] NANP_COUNTRIES = new String[] {
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "US", // United States
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "CA", // Canada
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "AS", // American Samoa
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "AI", // Anguilla
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "AG", // Antigua and Barbuda
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "BS", // Bahamas
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "BB", // Barbados
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "BM", // Bermuda
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "VG", // British Virgin Islands
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KY", // Cayman Islands
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "DM", // Dominica
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "DO", // Dominican Republic
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "GD", // Grenada
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "GU", // Guam
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "JM", // Jamaica
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "PR", // Puerto Rico
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "MS", // Montserrat
10077850cdde66705152b859aafda875833acdda9653Libin Tang        "MP", // Northern Mariana Islands
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KN", // Saint Kitts and Nevis
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "LC", // Saint Lucia
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "VC", // Saint Vincent and the Grenadines
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "TT", // Trinidad and Tobago
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "TC", // Turks and Caicos Islands
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "VI", // U.S. Virgin Islands
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Breaks the given number down and formats it according to the rules
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * for the country the number is from.
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param source the phone number to format
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a locally acceptable formatting of the input, or the raw input if
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  formatting rules aren't known for the number
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String formatNumber(String source) {
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SpannableStringBuilder text = new SpannableStringBuilder(source);
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        formatNumber(text, getFormatTypeForLocale(Locale.getDefault()));
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return text.toString();
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the phone number formatting type for the given locale.
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param locale The locale of interest, usually {@link Locale#getDefault()}
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the formatting type for the given locale, or FORMAT_UNKNOWN if the formatting
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * rules are not known for the given locale
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int getFormatTypeForLocale(Locale locale) {
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String country = locale.getCountry();
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10407850cdde66705152b859aafda875833acdda9653Libin Tang        return getFormatTypeFromCountryCode(country);
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Formats a phone number in-place. Currently only supports NANP formatting.
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text The number to be formatted, will be modified with the formatting
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param defaultFormattingType The default formatting rules to apply if the number does
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * not begin with +<country_code>
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void formatNumber(Editable text, int defaultFormattingType) {
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int formatType = defaultFormattingType;
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (text.length() > 2 && text.charAt(0) == '+') {
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (text.charAt(1) == '1') {
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                formatType = FORMAT_NANP;
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (text.length() >= 3 && text.charAt(1) == '8'
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && text.charAt(2) == '1') {
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                formatType = FORMAT_JAPAN;
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (formatType) {
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case FORMAT_NANP:
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                formatNanpNumber(text);
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case FORMAT_JAPAN:
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                formatJapaneseNumber(text);
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NANP_STATE_DIGIT = 1;
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NANP_STATE_PLUS = 2;
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NANP_STATE_ONE = 3;
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NANP_STATE_DASH = 4;
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Formats a phone number in-place using the NANP formatting rules. Numbers will be formatted
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as:
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p><code>
10845214376d2b1ce082765f766be1c7d56b50df74a7Ficus Kirkpatrick     * xxxxx
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * xxx-xxxx
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * xxx-xxx-xxxx
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 1-xxx-xxx-xxxx
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * +1-xxx-xxx-xxxx
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * </code></p>
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text the number to be formatted, will be modified with the formatting
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void formatNanpNumber(Editable text) {
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int length = text.length();
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (length > "+1-nnn-nnn-nnnn".length()) {
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The string is too long to be formatted
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
10985214376d2b1ce082765f766be1c7d56b50df74a7Ficus Kirkpatrick        } else if (length <= 5) {
10995214376d2b1ce082765f766be1c7d56b50df74a7Ficus Kirkpatrick            // The string is either a shortcode or too short to be formatted
11005214376d2b1ce082765f766be1c7d56b50df74a7Ficus Kirkpatrick            return;
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11025214376d2b1ce082765f766be1c7d56b50df74a7Ficus Kirkpatrick
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence saved = text.subSequence(0, length);
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Strip the dashes first, as we're going to add them back
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int p = 0;
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (p < text.length()) {
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (text.charAt(p) == '-') {
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                text.delete(p, p + 1);
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p++;
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        length = text.length();
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // When scanning the number we record where dashes need to be added,
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // if they're non-0 at the end of the scan the dashes will be added in
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the proper places.
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dashPositions[] = new int[3];
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numDashes = 0;
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int state = NANP_STATE_DIGIT;
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numDigits = 0;
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < length; i++) {
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = text.charAt(i);
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (c) {
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '1':
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (numDigits == 0 || state == NANP_STATE_PLUS) {
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        state = NANP_STATE_ONE;
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // fall through
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '2':
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '3':
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '4':
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '5':
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '6':
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '7':
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '8':
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '9':
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '0':
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (state == NANP_STATE_PLUS) {
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Only NANP number supported for now
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        text.replace(0, length, saved);
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return;
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else if (state == NANP_STATE_ONE) {
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Found either +1 or 1, follow it up with a dash
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        dashPositions[numDashes++] = i;
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else if (state != NANP_STATE_DASH && (numDigits == 3 || numDigits == 6)) {
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Found a digit that should be after a dash that isn't
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        dashPositions[numDashes++] = i;
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    state = NANP_STATE_DIGIT;
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    numDigits++;
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '-':
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    state = NANP_STATE_DASH;
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '+':
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (i == 0) {
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Plus is only allowed as the first character
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        state = NANP_STATE_PLUS;
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Fall through
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                default:
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Unknown character, bail on formatting
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    text.replace(0, length, saved);
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (numDigits == 7) {
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // With 7 digits we want xxx-xxxx, not xxx-xxx-x
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            numDashes--;
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Actually put the dashes in place
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numDashes; i++) {
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int pos = dashPositions[i];
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            text.replace(pos + i, pos + i, "-");
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Remove trailing dashes
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = text.length();
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (len > 0) {
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (text.charAt(len - 1) == '-') {
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                text.delete(len - 1, len);
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                len--;
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Formats a phone number in-place using the Japanese formatting rules.
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Numbers will be formatted as:
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p><code>
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 03-xxxx-xxxx
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 090-xxxx-xxxx
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 0120-xxx-xxx
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * +81-3-xxxx-xxxx
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * +81-90-xxxx-xxxx
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * </code></p>
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text the number to be formatted, will be modified with
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the formatting
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void formatJapaneseNumber(Editable text) {
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        JapanesePhoneNumberFormatter.format(text);
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
121702b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // Three and four digit phone numbers for either special services,
121802b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should
121902b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // not match.
122002b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //
122102b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // This constant used to be 5, but SMS short codes has increased in length and
122202b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // can be easily 6 digits now days. Most countries have SMS short code length between
122302b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // 3 to 6 digits. The exceptions are
122402b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //
122502b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // Australia: Short codes are six or eight digits in length, starting with the prefix "19"
122602b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //            followed by an additional four or six digits and two.
122702b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // Czech Republic: Codes are seven digits in length for MO and five (not billed) or
122802b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //            eight (billed) for MT direction
122902b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //
123002b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // see http://en.wikipedia.org/wiki/Short_code#Regional_differences for reference
123102b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //
123202b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // However, in order to loose match 650-555-1212 and 555-1212, we need to set the min match
123302b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // to 7.
123402b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    static final int MIN_MATCH = 7;
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * isEmergencyNumber: checks a given number against the list of
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   emergency numbers provided by the RIL and SIM card.
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param number the number to look up.
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return if the number is in the list of emergency numbers
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * listed in the ril / sim, then return true, otherwise false.
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean isEmergencyNumber(String number) {
1245694bd8bf733aee372705e00d13964a20e5b16209Peng Zhu        // If the number passed in is null, just return false:
1246694bd8bf733aee372705e00d13964a20e5b16209Peng Zhu        if (number == null) return false;
1247694bd8bf733aee372705e00d13964a20e5b16209Peng Zhu
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Strip the separators from the number before comparing it
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // to the list.
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        number = extractNetworkPortion(number);
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // retrieve the list of emergency numbers
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String numbers = SystemProperties.get("ro.ril.ecclist");
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!TextUtils.isEmpty(numbers)) {
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // searches through the comma-separated list for a match,
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // return true if one is found.
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (String emergencyNum : numbers.split(",")) {
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (emergencyNum.equals(number)) {
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return true;
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // no matches found against the list!
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //no ecclist system property, so use our own list.
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (number.equals("112") || number.equals("911"));
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
127260d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * isVoiceMailNumber: checks a given number against the voicemail
127360d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     *   number provided by the RIL and SIM card. The caller must have
127460d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     *   the READ_PHONE_STATE credential.
127560d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     *
127660d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * @param number the number to look up.
127760d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * @return true if the number is in the list of voicemail. False
127860d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * otherwise, including if the caller does not have the permission
127960d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * to read the VM number.
128060d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * @hide TODO: pending API Council approval
128160d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     */
128260d45f0f0320801a16db2ad038453c098e98966cNicolas Catania    public static boolean isVoiceMailNumber(String number) {
128360d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        String vmNumber;
128460d45f0f0320801a16db2ad038453c098e98966cNicolas Catania
128560d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        try {
128660d45f0f0320801a16db2ad038453c098e98966cNicolas Catania            vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
128760d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        } catch (SecurityException ex) {
128860d45f0f0320801a16db2ad038453c098e98966cNicolas Catania            return false;
128960d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        }
129060d45f0f0320801a16db2ad038453c098e98966cNicolas Catania
129160d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // Strip the separators from the number before comparing it
129260d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // to the list.
129360d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        number = extractNetworkPortion(number);
129460d45f0f0320801a16db2ad038453c098e98966cNicolas Catania
129560d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // compare tolerates null so we need to make sure that we
129660d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // don't return true when both are null.
129760d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        return !TextUtils.isEmpty(number) && compare(number, vmNumber);
129860d45f0f0320801a16db2ad038453c098e98966cNicolas Catania    }
129960d45f0f0320801a16db2ad038453c098e98966cNicolas Catania
130060d45f0f0320801a16db2ad038453c098e98966cNicolas Catania    /**
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Translates any alphabetic letters (i.e. [A-Za-z]) in the
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * specified phone number into the equivalent numeric digits,
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * according to the phone keypad letter mapping described in
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * ITU E.161 and ISO/IEC 9995-8.
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the input string, with alpha letters converted to numeric
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         digits using the phone keypad letter mapping.  For example,
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         an input of "1-800-GOOG-411" will return "1-800-4664-411".
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String convertKeypadLettersToDigits(String input) {
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (input == null) {
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return input;
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = input.length();
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (len == 0) {
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return input;
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char[] out = input.toCharArray();
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < len; i++) {
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = out[i];
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If this char isn't in KEYPAD_MAP at all, just leave it alone.
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out[i] = (char) KEYPAD_MAP.get(c, c);
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new String(out);
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The phone keypad letter mapping (see ITU E.161 or ISO/IEC 9995-8.)
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TODO: This should come from a resource.
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final SparseIntArray KEYPAD_MAP = new SparseIntArray();
13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('a', '2'); KEYPAD_MAP.put('b', '2'); KEYPAD_MAP.put('c', '2');
13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('A', '2'); KEYPAD_MAP.put('B', '2'); KEYPAD_MAP.put('C', '2');
13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('d', '3'); KEYPAD_MAP.put('e', '3'); KEYPAD_MAP.put('f', '3');
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('D', '3'); KEYPAD_MAP.put('E', '3'); KEYPAD_MAP.put('F', '3');
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('g', '4'); KEYPAD_MAP.put('h', '4'); KEYPAD_MAP.put('i', '4');
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('G', '4'); KEYPAD_MAP.put('H', '4'); KEYPAD_MAP.put('I', '4');
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('j', '5'); KEYPAD_MAP.put('k', '5'); KEYPAD_MAP.put('l', '5');
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('J', '5'); KEYPAD_MAP.put('K', '5'); KEYPAD_MAP.put('L', '5');
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('m', '6'); KEYPAD_MAP.put('n', '6'); KEYPAD_MAP.put('o', '6');
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('M', '6'); KEYPAD_MAP.put('N', '6'); KEYPAD_MAP.put('O', '6');
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('p', '7'); KEYPAD_MAP.put('q', '7'); KEYPAD_MAP.put('r', '7'); KEYPAD_MAP.put('s', '7');
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('P', '7'); KEYPAD_MAP.put('Q', '7'); KEYPAD_MAP.put('R', '7'); KEYPAD_MAP.put('S', '7');
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('t', '8'); KEYPAD_MAP.put('u', '8'); KEYPAD_MAP.put('v', '8');
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('T', '8'); KEYPAD_MAP.put('U', '8'); KEYPAD_MAP.put('V', '8');
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('w', '9'); KEYPAD_MAP.put('x', '9'); KEYPAD_MAP.put('y', '9'); KEYPAD_MAP.put('z', '9');
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('W', '9'); KEYPAD_MAP.put('X', '9'); KEYPAD_MAP.put('Y', '9'); KEYPAD_MAP.put('Z', '9');
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
136018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
136118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    //================ Plus Code formatting =========================
136218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static final char PLUS_SIGN_CHAR = '+';
136318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static final String PLUS_SIGN_STRING = "+";
136418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static final String NANP_IDP_STRING = "011";
136518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static final int NANP_LENGTH = 10;
136618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
136718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    /**
136818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * This function checks if there is a plus sign (+) in the passed-in dialing number.
136918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * If there is, it processes the plus sign based on the default telephone
137018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * numbering plan of the system when the phone is activated and the current
137118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * telephone numbering plan of the system that the phone is camped on.
137218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * Currently, we only support the case that the default and current telephone
137318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * numbering plans are North American Numbering Plan(NANP).
137418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
137518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * The passed-in dialStr should only contain the valid format as described below,
137618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * 1) the 1st character in the dialStr should be one of the really dialable
137718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *    characters listed below
137818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *    ISO-LATIN characters 0-9, *, # , +
137918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * 2) the dialStr should already strip out the separator characters,
138018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *    every character in the dialStr should be one of the non separator characters
138118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *    listed below
138218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *    ISO-LATIN characters 0-9, *, # , +, WILD, WAIT, PAUSE
138318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
138418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * Otherwise, this function returns the dial string passed in
138518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
13867850cdde66705152b859aafda875833acdda9653Libin Tang     * @param dialStr the original dial string
13877850cdde66705152b859aafda875833acdda9653Libin Tang     * @return the converted dial string if the current/default countries belong to NANP,
13887850cdde66705152b859aafda875833acdda9653Libin Tang     * and if there is the "+" in the original dial string. Otherwise, the original dial
13897850cdde66705152b859aafda875833acdda9653Libin Tang     * string returns.
13907850cdde66705152b859aafda875833acdda9653Libin Tang     *
139118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * This API is for CDMA only
139218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
139318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * @hide TODO: pending API Council approval
139418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     */
139518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    public static String cdmaCheckAndProcessPlusCode(String dialStr) {
139618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (!TextUtils.isEmpty(dialStr)) {
139718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            if (isReallyDialable(dialStr.charAt(0)) &&
139818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                isNonSeparator(dialStr)) {
13997850cdde66705152b859aafda875833acdda9653Libin Tang                String currIso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY, "");
14007850cdde66705152b859aafda875833acdda9653Libin Tang                String defaultIso = SystemProperties.get(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
14017850cdde66705152b859aafda875833acdda9653Libin Tang                if (!TextUtils.isEmpty(currIso) && !TextUtils.isEmpty(defaultIso)) {
14027850cdde66705152b859aafda875833acdda9653Libin Tang                    return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr,
14037850cdde66705152b859aafda875833acdda9653Libin Tang                            getFormatTypeFromCountryCode(currIso),
14047850cdde66705152b859aafda875833acdda9653Libin Tang                            getFormatTypeFromCountryCode(defaultIso));
14057850cdde66705152b859aafda875833acdda9653Libin Tang                }
140618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            }
140718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
140818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return dialStr;
140918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
141018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
141118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    /**
141218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * This function should be called from checkAndProcessPlusCode only
141318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * And it is used for test purpose also.
141418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
141518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * It checks the dial string by looping through the network portion,
141618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * post dial portion 1, post dial porting 2, etc. If there is any
141718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * plus sign, then process the plus sign.
141818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * Currently, this function supports the plus sign conversion within NANP only.
141918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * Specifically, it handles the plus sign in the following ways:
14207850cdde66705152b859aafda875833acdda9653Libin Tang     * 1)+1NANP,remove +, e.g.
142118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *   +18475797000 is converted to 18475797000,
14227850cdde66705152b859aafda875833acdda9653Libin Tang     * 2)+NANP or +non-NANP Numbers,replace + with the current NANP IDP, e.g,
14237850cdde66705152b859aafda875833acdda9653Libin Tang     *   +8475797000 is converted to 0118475797000,
142418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *   +11875767800 is converted to 01111875767800
14257850cdde66705152b859aafda875833acdda9653Libin Tang     * 3)+1NANP in post dial string(s), e.g.
14267850cdde66705152b859aafda875833acdda9653Libin Tang     *   8475797000;+18475231753 is converted to 8475797000;18475231753
14277850cdde66705152b859aafda875833acdda9653Libin Tang     *
142818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
14297850cdde66705152b859aafda875833acdda9653Libin Tang     * @param dialStr the original dial string
14307850cdde66705152b859aafda875833acdda9653Libin Tang     * @param currFormat the numbering system of the current country that the phone is camped on
14317850cdde66705152b859aafda875833acdda9653Libin Tang     * @param defaultFormat the numbering system of the country that the phone is activated on
14327850cdde66705152b859aafda875833acdda9653Libin Tang     * @return the converted dial string if the current/default countries belong to NANP,
14337850cdde66705152b859aafda875833acdda9653Libin Tang     * and if there is the "+" in the original dial string. Otherwise, the original dial
14347850cdde66705152b859aafda875833acdda9653Libin Tang     * string returns.
143518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
143618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * @hide
143718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     */
14387850cdde66705152b859aafda875833acdda9653Libin Tang    public static String
14397850cdde66705152b859aafda875833acdda9653Libin Tang    cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormt) {
144018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        String retStr = dialStr;
144118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
144218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        // Checks if the plus sign character is in the passed-in dial string
144318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (dialStr != null &&
144418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            dialStr.lastIndexOf(PLUS_SIGN_STRING) != -1) {
14457850cdde66705152b859aafda875833acdda9653Libin Tang            // Format the string based on the rules for the country the number is from,
14467850cdde66705152b859aafda875833acdda9653Libin Tang            // and the current country the phone is camped on.
14477850cdde66705152b859aafda875833acdda9653Libin Tang            if ((currFormat == defaultFormt) && (currFormat == FORMAT_NANP)) {
14487850cdde66705152b859aafda875833acdda9653Libin Tang                // Handle case where default and current telephone numbering plans are NANP.
14497850cdde66705152b859aafda875833acdda9653Libin Tang                String postDialStr = null;
14507850cdde66705152b859aafda875833acdda9653Libin Tang                String tempDialStr = dialStr;
14517850cdde66705152b859aafda875833acdda9653Libin Tang
14527850cdde66705152b859aafda875833acdda9653Libin Tang                // Sets the retStr to null since the conversion will be performed below.
14537850cdde66705152b859aafda875833acdda9653Libin Tang                retStr = null;
14547850cdde66705152b859aafda875833acdda9653Libin Tang                if (DBG) log("checkAndProcessPlusCode,dialStr=" + dialStr);
14557850cdde66705152b859aafda875833acdda9653Libin Tang                // This routine is to process the plus sign in the dial string by loop through
14567850cdde66705152b859aafda875833acdda9653Libin Tang                // the network portion, post dial portion 1, post dial portion 2... etc. if
14577850cdde66705152b859aafda875833acdda9653Libin Tang                // applied
14587850cdde66705152b859aafda875833acdda9653Libin Tang                do {
14597850cdde66705152b859aafda875833acdda9653Libin Tang                    String networkDialStr;
146018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    networkDialStr = extractNetworkPortion(tempDialStr);
146118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    // Handles the conversion within NANP
146218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    networkDialStr = processPlusCodeWithinNanp(networkDialStr);
14637850cdde66705152b859aafda875833acdda9653Libin Tang
14647850cdde66705152b859aafda875833acdda9653Libin Tang                    // Concatenates the string that is converted from network portion
14657850cdde66705152b859aafda875833acdda9653Libin Tang                    if (!TextUtils.isEmpty(networkDialStr)) {
14667850cdde66705152b859aafda875833acdda9653Libin Tang                        if (retStr == null) {
14677850cdde66705152b859aafda875833acdda9653Libin Tang                            retStr = networkDialStr;
14687850cdde66705152b859aafda875833acdda9653Libin Tang                        } else {
14697850cdde66705152b859aafda875833acdda9653Libin Tang                            retStr = retStr.concat(networkDialStr);
14707850cdde66705152b859aafda875833acdda9653Libin Tang                        }
147118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    } else {
14727850cdde66705152b859aafda875833acdda9653Libin Tang                        // This should never happen since we checked the if dialStr is null
14737850cdde66705152b859aafda875833acdda9653Libin Tang                        // and if it contains the plus sign in the beginning of this function.
14747850cdde66705152b859aafda875833acdda9653Libin Tang                        // The plus sign is part of the network portion.
14757850cdde66705152b859aafda875833acdda9653Libin Tang                        Log.e("checkAndProcessPlusCode: null newDialStr", networkDialStr);
14767850cdde66705152b859aafda875833acdda9653Libin Tang                        return dialStr;
147718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    }
14787850cdde66705152b859aafda875833acdda9653Libin Tang                    postDialStr = extractPostDialPortion(tempDialStr);
14797850cdde66705152b859aafda875833acdda9653Libin Tang                    if (!TextUtils.isEmpty(postDialStr)) {
14807850cdde66705152b859aafda875833acdda9653Libin Tang                        int dialableIndex = findDialableIndexFromPostDialStr(postDialStr);
14817850cdde66705152b859aafda875833acdda9653Libin Tang
14827850cdde66705152b859aafda875833acdda9653Libin Tang                        // dialableIndex should always be greater than 0
14837850cdde66705152b859aafda875833acdda9653Libin Tang                        if (dialableIndex >= 1) {
14847850cdde66705152b859aafda875833acdda9653Libin Tang                            retStr = appendPwCharBackToOrigDialStr(dialableIndex,
14857850cdde66705152b859aafda875833acdda9653Libin Tang                                     retStr,postDialStr);
14867850cdde66705152b859aafda875833acdda9653Libin Tang                            // Skips the P/W character, extracts the dialable portion
14877850cdde66705152b859aafda875833acdda9653Libin Tang                            tempDialStr = postDialStr.substring(dialableIndex);
14887850cdde66705152b859aafda875833acdda9653Libin Tang                        } else {
14897850cdde66705152b859aafda875833acdda9653Libin Tang                            // Non-dialable character such as P/W should not be at the end of
14907850cdde66705152b859aafda875833acdda9653Libin Tang                            // the dial string after P/W processing in CdmaConnection.java
14917850cdde66705152b859aafda875833acdda9653Libin Tang                            // Set the postDialStr to "" to break out of the loop
14927850cdde66705152b859aafda875833acdda9653Libin Tang                            if (dialableIndex < 0) {
14937850cdde66705152b859aafda875833acdda9653Libin Tang                                postDialStr = "";
14947850cdde66705152b859aafda875833acdda9653Libin Tang                            }
14957850cdde66705152b859aafda875833acdda9653Libin Tang                            Log.e("wrong postDialStr=", postDialStr);
149618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                        }
149718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    }
14987850cdde66705152b859aafda875833acdda9653Libin Tang                    if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr);
14997850cdde66705152b859aafda875833acdda9653Libin Tang                } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr));
15007850cdde66705152b859aafda875833acdda9653Libin Tang            } else {
15017850cdde66705152b859aafda875833acdda9653Libin Tang                // TODO: Support NANP international conversion and other telephone numbering plans.
15027850cdde66705152b859aafda875833acdda9653Libin Tang                // Currently the phone is never used in non-NANP system, so return the original
15037850cdde66705152b859aafda875833acdda9653Libin Tang                // dial string.
15047850cdde66705152b859aafda875833acdda9653Libin Tang                Log.e("checkAndProcessPlusCode:non-NANP not supported", dialStr);
15057850cdde66705152b859aafda875833acdda9653Libin Tang            }
150618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
150718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return retStr;
150818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     }
150918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
151018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    // This function gets the default international dialing prefix
151118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static String getDefaultIdp( ) {
151218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        String ps = null;
151318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        SystemProperties.get(PROPERTY_IDP_STRING, ps);
151418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (TextUtils.isEmpty(ps)) {
151518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            ps = NANP_IDP_STRING;
151618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
151718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return ps;
151818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
151918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
152018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static boolean isTwoToNine (char c) {
152118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (c >= '2' && c <= '9') {
152218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            return true;
152318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        } else {
152418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            return false;
152518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
152618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
152718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
15287850cdde66705152b859aafda875833acdda9653Libin Tang    private static int getFormatTypeFromCountryCode (String country) {
15297850cdde66705152b859aafda875833acdda9653Libin Tang        // Check for the NANP countries
15307850cdde66705152b859aafda875833acdda9653Libin Tang        int length = NANP_COUNTRIES.length;
15317850cdde66705152b859aafda875833acdda9653Libin Tang        for (int i = 0; i < length; i++) {
15327850cdde66705152b859aafda875833acdda9653Libin Tang            if (NANP_COUNTRIES[i].compareToIgnoreCase(country) == 0) {
15337850cdde66705152b859aafda875833acdda9653Libin Tang                return FORMAT_NANP;
15347850cdde66705152b859aafda875833acdda9653Libin Tang            }
15357850cdde66705152b859aafda875833acdda9653Libin Tang        }
15367850cdde66705152b859aafda875833acdda9653Libin Tang        if ("jp".compareToIgnoreCase(country) == 0) {
15377850cdde66705152b859aafda875833acdda9653Libin Tang            return FORMAT_JAPAN;
15387850cdde66705152b859aafda875833acdda9653Libin Tang        }
15397850cdde66705152b859aafda875833acdda9653Libin Tang        return FORMAT_UNKNOWN;
15407850cdde66705152b859aafda875833acdda9653Libin Tang    }
15417850cdde66705152b859aafda875833acdda9653Libin Tang
154218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    /**
154318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * This function checks if the passed in string conforms to the NANP format
154418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * i.e. NXX-NXX-XXXX, N is any digit 2-9 and X is any digit 0-9
154518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     */
154618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static boolean isNanp (String dialStr) {
154718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        boolean retVal = false;
154818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (dialStr != null) {
154918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            if (dialStr.length() == NANP_LENGTH) {
155018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                if (isTwoToNine(dialStr.charAt(0)) &&
155118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    isTwoToNine(dialStr.charAt(3))) {
155218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    retVal = true;
155318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    for (int i=1; i<NANP_LENGTH; i++ ) {
155418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                        char c=dialStr.charAt(i);
155518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                        if (!PhoneNumberUtils.isISODigit(c)) {
155618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                            retVal = false;
155718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                            break;
155818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                        }
155918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    }
156018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                }
156118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            }
156218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        } else {
156318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            Log.e("isNanp: null dialStr passed in", dialStr);
156418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
156518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return retVal;
156618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
156718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
156818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com   /**
156918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    * This function checks if the passed in string conforms to 1-NANP format
157018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    */
157118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static boolean isOneNanp(String dialStr) {
157218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        boolean retVal = false;
157318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (dialStr != null) {
157418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            String newDialStr = dialStr.substring(1);
157518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            if ((dialStr.charAt(0) == '1') && isNanp(newDialStr)) {
157618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                retVal = true;
157718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            }
157818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        } else {
157918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            Log.e("isOneNanp: null dialStr passed in", dialStr);
158018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
158118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return retVal;
158218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
158318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
158418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    /**
158518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * This function handles the plus code conversion within NANP CDMA network
158618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * If the number format is
15877850cdde66705152b859aafda875833acdda9653Libin Tang     * 1)+1NANP,remove +,
15887850cdde66705152b859aafda875833acdda9653Libin Tang     * 2)other than +1NANP, any + numbers,replace + with the current IDP
158918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     */
159018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static String processPlusCodeWithinNanp(String networkDialStr) {
159118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        String retStr = networkDialStr;
159218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
159318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (DBG) log("processPlusCodeWithinNanp,networkDialStr=" + networkDialStr);
159418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        // If there is a plus sign at the beginning of the dial string,
159518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        // Convert the plus sign to the default IDP since it's an international number
159618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (networkDialStr != null &
159718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            networkDialStr.charAt(0) == PLUS_SIGN_CHAR &&
159818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            networkDialStr.length() > 1) {
159918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            String newStr = networkDialStr.substring(1);
16007850cdde66705152b859aafda875833acdda9653Libin Tang            if (isOneNanp(newStr)) {
160118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                // Remove the leading plus sign
160218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                retStr = newStr;
160318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com             } else {
160418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                 String idpStr = getDefaultIdp();
160518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                 // Replaces the plus sign with the default IDP
160618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                 retStr = networkDialStr.replaceFirst("[+]", idpStr);
160718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            }
160818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
160918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (DBG) log("processPlusCodeWithinNanp,retStr=" + retStr);
161018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return retStr;
161118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
161218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
161318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    // This function finds the index of the dialable character(s)
161418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    // in the post dial string
161518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static int findDialableIndexFromPostDialStr(String postDialStr) {
161618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        for (int index = 0;index < postDialStr.length();index++) {
161718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com             char c = postDialStr.charAt(index);
161818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com             if (isReallyDialable(c)) {
161918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                return index;
162018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com             }
162118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
162218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return -1;
162318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
162418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
162518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    // This function appends the non-diablable P/W character to the original
162618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    // dial string based on the dialable index passed in
162718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static String
162818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    appendPwCharBackToOrigDialStr(int dialableIndex,String origStr, String dialStr) {
162918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        String retStr;
163018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
163118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        // There is only 1 P/W character before the dialable characters
163218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (dialableIndex == 1) {
163318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            StringBuilder ret = new StringBuilder(origStr);
163418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            ret = ret.append(dialStr.charAt(0));
163518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            retStr = ret.toString();
163618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        } else {
163718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            // It means more than 1 P/W characters in the post dial string,
163818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            // appends to retStr
163918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            String nonDigitStr = dialStr.substring(0,dialableIndex);
164018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            retStr = origStr.concat(nonDigitStr);
164118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
164218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return retStr;
164318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
16449a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
16459a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    //===== Begining of utility methods used in compareLoosely() =====
16469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
16479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
16489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Phone numbers are stored in "lookup" form in the database
16499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * as reversed strings to allow for caller ID lookup
16509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *
16519a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * This method takes a phone number and makes a valid SQL "LIKE"
16529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * string that will match the lookup form
16539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *
16549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
16559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /** all of a up to len must be an international prefix or
16569a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *  separators/non-dialing digits
16579a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
16589a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean
16599a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    matchIntlPrefix(String a, int len) {
16609a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        /* '([^0-9*#+pwn]\+[^0-9*#+pwn] | [^0-9*#+pwn]0(0|11)[^0-9*#+pwn] )$' */
16619a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        /*        0       1                           2 3 45               */
16629a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
16639a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int state = 0;
16649a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        for (int i = 0 ; i < len ; i++) {
16659a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            char c = a.charAt(i);
16669a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
16679a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            switch (state) {
16689a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 0:
16699a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '+') state = 1;
16709a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (c == '0') state = 2;
16719a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
16729a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
16739a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
16749a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 2:
16759a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '0') state = 3;
16769a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (c == '1') state = 4;
16779a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
16789a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
16799a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
16809a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 4:
16819a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '1') state = 5;
16829a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
16839a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
16849a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
16859a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                default:
16869a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (isNonSeparator(c)) return false;
16879a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
16889a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
16899a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
16909a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
16919a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
16929a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return state == 1 || state == 3 || state == 5;
16939a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
16949a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
16959a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /** all of 'a' up to len must be a (+|00|011)country code)
16969a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *  We're fast and loose with the country code. Any \d{1,3} matches */
16979a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean
16989a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    matchIntlPrefixAndCC(String a, int len) {
16999a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        /*  [^0-9*#+pwn]*(\+|0(0|11)\d\d?\d? [^0-9*#+pwn] $ */
17009a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        /*      0          1 2 3 45  6 7  8                 */
17019a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17029a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int state = 0;
17039a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        for (int i = 0 ; i < len ; i++ ) {
17049a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            char c = a.charAt(i);
17059a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17069a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            switch (state) {
17079a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 0:
17089a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '+') state = 1;
17099a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (c == '0') state = 2;
17109a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
17119a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
17129a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17139a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 2:
17149a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '0') state = 3;
17159a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (c == '1') state = 4;
17169a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
17179a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
17189a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17199a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 4:
17209a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '1') state = 5;
17219a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
17229a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
17239a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17249a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 1:
17259a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 3:
17269a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 5:
17279a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (isISODigit(c)) state = 6;
17289a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
17299a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
17309a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 6:
17329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 7:
17339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (isISODigit(c)) state++;
17349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
17359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
17369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                default:
17389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (isNonSeparator(c)) return false;
17399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
17409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
17419a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return state == 6 || state == 7 || state == 8;
17439a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
17449a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17459a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /** all of 'a' up to len must match non-US trunk prefix ('0') */
17469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean
17479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    matchTrunkPrefix(String a, int len) {
17489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean found;
17499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        found = false;
17519a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        for (int i = 0 ; i < len ; i++) {
17539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            char c = a.charAt(i);
17549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (c == '0' && !found) {
17569a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                found = true;
17579a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            } else if (isNonSeparator(c)) {
17589a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                return false;
17599a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
17609a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
17619a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17629a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return found;
17639a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
17649a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17659a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    //===== End of utility methods used only in compareLoosely() =====
17669a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17679a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    //===== Beggining of utility methods used only in compareStrictly() ====
17689a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17699a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /*
17709a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * If true, the number is country calling code.
17719a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
17729a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static final boolean COUNTLY_CALLING_CALL[] = {
17739a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, true, false, false, false, false, false, true, false, false,
17749a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        false, false, false, false, false, false, false, false, false, false,
17759a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, false, false, false, false, false, false, true, true, false,
17769a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, true, true, true, true, false, true, false, false, true,
17779a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, false, false, true, true, true, true, true, true, true,
17789a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        false, true, true, true, true, true, true, true, true, false,
17799a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, true, true, true, true, true, true, false, false, false,
17809a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        false, false, false, false, false, false, false, false, false, false,
17819a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        false, true, true, true, true, false, true, false, false, true,
17829a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, true, true, true, true, true, false, false, true, false,
17839a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    };
17849a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static final int CCC_LENGTH = COUNTLY_CALLING_CALL.length;
17859a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17869a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
17879a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * @return true when input is valid Country Calling Code.
17889a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
17899a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean isCountryCallingCode(int countryCallingCodeCandidate) {
17909a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return countryCallingCodeCandidate > 0 && countryCallingCodeCandidate < CCC_LENGTH &&
17919a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                COUNTLY_CALLING_CALL[countryCallingCodeCandidate];
17929a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
17939a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
17949a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
17959a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Returns interger corresponding to the input if input "ch" is
17969a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * ISO-LATIN characters 0-9.
17979a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Returns -1 otherwise
17989a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
17999a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static int tryGetISODigit(char ch) {
18009a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        if ('0' <= ch && ch <= '9') {
18019a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            return ch - '0';
18029a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        } else {
18039a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            return -1;
18049a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
18059a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
18069a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
18079a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static class CountryCallingCodeAndNewIndex {
18089a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        public final int countryCallingCode;
18099a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        public final int newIndex;
18109a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        public CountryCallingCodeAndNewIndex(int countryCode, int newIndex) {
18119a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            this.countryCallingCode = countryCode;
18129a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            this.newIndex = newIndex;
18139a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
18149a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
18159a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
18169a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /*
18179a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Note that this function does not strictly care the country calling code with
18189a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * 3 length (like Morocco: +212), assuming it is enough to use the first two
18199a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * digit to compare two phone numbers.
18209a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
18219a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static CountryCallingCodeAndNewIndex tryGetCountryCallingCodeAndNewIndex(
18229a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        String str, boolean acceptThailandCase) {
18239a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        // Rough regexp:
18249a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        //  ^[^0-9*#+]*((\+|0(0|11)\d\d?|166) [^0-9*#+] $
18259a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        //         0        1 2 3 45  6 7  89
18269a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        //
18279a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        // In all the states, this function ignores separator characters.
18289a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        // "166" is the special case for the call from Thailand to the US. Uguu!
18299a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int state = 0;
18309a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int ccc = 0;
18319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        final int length = str.length();
18329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        for (int i = 0 ; i < length ; i++ ) {
18339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            char ch = str.charAt(i);
18349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            switch (state) {
18359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 0:
18369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (ch == '+') state = 1;
18379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (ch == '0') state = 2;
18389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (ch == '1') {
18399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        if (acceptThailandCase) {
18409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            state = 8;
18419a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        } else {
18429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            return null;
18439a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        }
18449a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    } else if (isDialable(ch)) {
18459a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return null;
18469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
18479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
18489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
18499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 2:
18509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (ch == '0') state = 3;
18519a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (ch == '1') state = 4;
18529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isDialable(ch)) {
18539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return null;
18549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
18559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
18569a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
18579a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 4:
18589a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (ch == '1') state = 5;
18599a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isDialable(ch)) {
18609a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return null;
18619a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
18629a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
18639a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
18649a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 1:
18659a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 3:
18669a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 5:
18679a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 6:
18689a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 7:
18699a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    {
18709a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        int ret = tryGetISODigit(ch);
18719a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        if (ret > 0) {
18729a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            ccc = ccc * 10 + ret;
18739a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            if (ccc >= 100 || isCountryCallingCode(ccc)) {
18749a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                                return new CountryCallingCodeAndNewIndex(ccc, i + 1);
18759a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            }
18769a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            if (state == 1 || state == 3 || state == 5) {
18779a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                                state = 6;
18789a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            } else {
18799a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                                state++;
18809a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            }
18819a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        } else if (isDialable(ch)) {
18829a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            return null;
18839a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        }
18849a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
18859a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    break;
18869a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 8:
18879a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (ch == '6') state = 9;
18889a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isDialable(ch)) {
18899a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return null;
18909a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
18919a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    break;
18929a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 9:
18939a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (ch == '6') {
18949a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return new CountryCallingCodeAndNewIndex(66, i + 1);
18959a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    } else {
18969a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return null;
18979a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
18989a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                default:
18999a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return null;
19009a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
19019a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
19029a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
19039a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return null;
19049a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
19059a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
19069a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
19079a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Currently this function simply ignore the first digit assuming it is
19089a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * trunk prefix. Actually trunk prefix is different in each country.
19099a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *
19109a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * e.g.
19119a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * "+79161234567" equals "89161234567" (Russian trunk digit is 8)
19129a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * "+33123456789" equals "0123456789" (French trunk digit is 0)
19139a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *
19149a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
19159a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static int tryGetTrunkPrefixOmittedIndex(String str, int currentIndex) {
19169a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int length = str.length();
19179a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        for (int i = currentIndex ; i < length ; i++) {
19189a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            final char ch = str.charAt(i);
19199a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (tryGetISODigit(ch) >= 0) {
19209a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                return i + 1;
19219a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            } else if (isDialable(ch)) {
19229a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                return -1;
19239a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
19249a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
19259a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return -1;
19269a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
19279a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
19289a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
19299a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Return true if the prefix of "str" is "ignorable". Here, "ignorable" means
19309a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * that "str" has only one digit and separater characters. The one digit is
19319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * assumed to be trunk prefix.
19329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
19339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean checkPrefixIsIgnorable(final String str,
19349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            int forwardIndex, int backwardIndex) {
19359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean trunk_prefix_was_read = false;
19369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        while (backwardIndex >= forwardIndex) {
19379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (tryGetISODigit(str.charAt(backwardIndex)) >= 0) {
19389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (trunk_prefix_was_read) {
19399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // More than one digit appeared, meaning that "a" and "b"
19409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // is different.
19419a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return false;
19429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                } else {
19439a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // Ignore just one digit, assuming it is trunk prefix.
19449a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    trunk_prefix_was_read = true;
19459a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
19469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            } else if (isDialable(str.charAt(backwardIndex))) {
19479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                // Trunk prefix is a digit, not "*", "#"...
19489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                return false;
19499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
19509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            backwardIndex--;
19519a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
19529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
19539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return true;
19549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
19559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
19569a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    //==== End of utility methods used only in compareStrictly() =====
19579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1958